diff --git a/README b/README index c68e549481..99cf34ecc0 100644 --- a/README +++ b/README @@ -4,15 +4,17 @@ ================================= -This is the source tree of the reference implementation of the Genode OS -architecture. For a general overview about the architecture, please refer to -the project's official website: +This is the source code of Genode, which is a framework for creating +component-based operating systems. It combines capability-based security, +microkernel technology, sandboxed device drivers, and virtualization with +a novel operating system architecture. For a general overview about the +architecture, please refer to the project's official website: -:Official project website for the Genode OS Framework: +:Website for the Genode OS Framework: [https://genode.org/documentation/general-overview] -The current implementation can be compiled for 8 different kernels: Linux, +Genode-based operating systems can be compiled for a variety of kernels: Linux, L4ka::Pistachio, L4/Fiasco, OKL4, NOVA, Fiasco.OC, seL4, and a custom "hw" microkernel for running Genode without a 3rd-party kernel. Whereas the Linux version serves us as development vehicle and enables us to rapidly develop the @@ -22,7 +24,7 @@ one. If a microkernel pretended to be fit for all use cases, it wouldn't be "micro". Hence, all microkernels differ in terms of their respective features, complexity, and supported hardware architectures. -Genode allows the use of each of the kernels listed above with a rich set of +Genode allows for the use of each of the supported kernels with a rich set of device drivers, protocol stacks, libraries, and applications in a uniform way. For developers, the framework provides an easy way to target multiple different kernels instead of tying the development to a particular kernel technology. For @@ -37,7 +39,7 @@ Documentation ############# The primary documentation is the book "Genode Foundations", which is available -on the front page of Genode website: +on the front page of the Genode website: :Download the book "Genode Foundations": @@ -79,11 +81,6 @@ The source tree is composed of the following subdirectories: Source-code management tools and scripts. Please refer to the README file contained in the directory. -:'depot': - - Directory used by Genode's package-management tools. It contains the public - keys and download locations of software providers. - Additional hardware support ########################### @@ -108,13 +105,32 @@ system scenarios. [https://github.com/genodelabs/genode-world] +Community blog +############## + +Genodians.org presents ideas, announcements, experience stories, and tutorials +around Genode, informally written by Genode users and developers. + +:Genodians.org: + + [https://genodians.org] + + Contact ####### -The best way to get in touch with Genode developers and users is the project's -mailing list. Please feel welcome to join in! +The community forum is organized by Genode users to help newcomers, share ideas +and experiences, and discuss Genode-related projects. -:Genode Mailing Lists: +:Community forum: + + [https://genode.discourse.group] + +The mailing list is the primary way for reaching out to Genode's core +developers, for receiving announcements, and for the project's annual road-map +discussion. + +:Genode Mailing List: [https://genode.org/community/mailing-lists] diff --git a/VERSION b/VERSION index 54de1e741d..3dce2e921c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -22.08 +24.08 diff --git a/doc/challenges.txt b/doc/challenges.txt index 623953303f..5b138bf771 100644 --- a/doc/challenges.txt +++ b/doc/challenges.txt @@ -16,17 +16,24 @@ research projects on Genode. Applications and library infrastructure ####################################### -:VNC server implementing Genode's framebuffer session interface: +:Port of the Ladybird web browser: - With 'Input' and 'Framebuffer', Genode provides two low-level interfaces - used by interactive applications. For example, the Nitpicker GUI server uses - these interfaces as a client and, in turn, exports multiple virtual - 'Framebuffer' and 'Input' interfaces to its clients. This enables a - highly modular use of applications such as the nesting of GUIs. By - implementing the 'Framebuffer' and 'Input' interfaces with a VNC server - implementation, all graphical workloads of Genode would become available over - the network. One immediate application of this implementation is the remote - testing of graphical Genode applications running on a headless server. + [https://ladybird.org/ - Ladybird] is a new web browser developed + independently from the large browser-engine vendors. It is designed to + be light-weight and portable. Among the supported platforms is Qt, + which is available for Genode. This makes the porting of Ladybird a + tempting application of the Goa SDK. + +:Goa SDK running on Sculpt OS: + + Genode's [https://github.com/genodelabs/goa - Goa SDK] is currently used + in Linux-based development environments, facilitating cross-compilation + to Genode. The goal of this project is the ability to use Goa directly on + Sculpt OS without the need for a Linux VM. This entails a number of + challenges, ranging from running the Goa tool itself by porting the expect + interpreter, over running the Genode tool chain, adjusting the + network-facing Goa commands to Genode's environment, to crafting custom + support for executing 'goa run' as a sandboxed Genode subsystem. :Interfacing with the SAFE network: @@ -39,25 +46,6 @@ Applications and library infrastructure integrated in the operating system, i.e., in the form of Genode components or a set of Genode VFS plugins. -:Interactive sound switchbox based on Genode's Audio_out session interface: - - Since version 10.05, Genode features a highly flexible configuration concept - that allows the arbitrary routing of session requests throughout the - hierarchic process structure. Even though primarily designed for expressing - mandatory-access control rules, the concept scales far beyond this use case. - For example, it can be used to run an arbitrary number of processes - implementing the same interface and connecting the different interface - implementations. One special case of this scenario is a chain of audio - filters with each using the 'Audio_out' session interface for both roles - client and server. Combined with the Nitpicker GUI server and Genode's - support for real-time priorities, this base techniques enable the creation of - flexible audio mixer / switchboard applications, which require dedicated - frameworks (e.g., Jack audio) on traditional operating systems. The goal of - this project is to create a showcase implementation demonstrating the - feasibility for creating high-quality audio applications on Genode. - Furthermore, we wish for feedback regarding the current design of our bulk - streaming interface when used for low-latency applications. - :Graphical on-target IPC tracing tool using Qt: Analysing the interaction of components of a multi-server operating system @@ -94,31 +82,39 @@ Applications and library infrastructure :Ports of popular software: - Genode features a ports mechanism to cleanly integrate 3rd-party software. + The [https://github.com/genodelabs/goa - Goa SDK] streamlines the process + of developing, porting, packaging, and publishing software for Genode, + and Sculpt OS in particular. Thanks to the C runtime, the flexible per-component VFS, the standard - C++ library, and the Noux runtime (for UNIX software), porting software - to Genode is relatively straight forward. The - [https://genode.org/documentation/developer-resources/porting - porting guide] - explains the typical steps. A wish list of software that we'd like to - have available on Genode is available at + C++ library, and a variety of supported 3rd-party libraries, porting + software to Genode is relatively straight forward. + A wish list of software that we'd like to have available on Genode is + available at [https://usr.sysret.de/jws/genode/porting_wishlist.html]. :Native Open-Street-Maps (OSM) client: - When using Sculpt OS, we regularly need to spawn a fully fledged web - browser in a virtual machine for using OSM or Google maps. The goal - of this project would be a native component that makes maps functionality - directly available on Genode, alleviating the urge to reach for a SaaS - product. The work would include a review of existing OSM clients regarding - their feature sets and the feasibility of porting them to Genode. - Depending on the outcome of this review, an existing application could - be ported or a new component could be developed, e.g., leveraging Genode's - Qt support. + When using Sculpt OS, we regularly need to spawn a fully fledged web browser + for using OSM or Google maps. The goal of this project would be a native + component that makes maps functionality directly available on Genode, + alleviating the urge to reach for a SaaS product. The work would include a + review of existing OSM clients regarding their feature sets and the + feasibility of porting them to Genode. Depending on the outcome of this + review, an existing application could be ported or a new component could be + developed, e.g., leveraging Genode's Qt support. Application frameworks and runtime environments ############################################### +:GTK: + + Genode supports Qt as a native toolkit. But many popular applications + are built upon [https://www.gtk.org/ - GTK]. A port of GTK to Genode would + allow for the use of these applications on Sculpt OS without the need + of a Linux VM. A tangible goal for this line of work could be the port + of [https://mtpaint.sourceforge.net/ - mtPaint] to Sculpt OS. + :OpenJDK: [https://openjdk.java.net/ - OpenJDK] is the reference implementation of the @@ -143,31 +139,6 @@ Application frameworks and runtime environments removed from the trusted computing base of Android, facilitating the use of this mobile OS in high-assurance settings. -:Go language runtime: - - Go is a popular language in particular for web applications. In the past, - there were numerous attempts to make the Go runtime available on Genode - but so far, none of those undertakings have landed in the official - Genode source tree. To goal of this project is the hosting of - Go-written applications - in particular networking applications - as - Genode components. The topic comprises work on the tool-chain - and build-system integration, the porting the runtime libraries, and - the glue between the Go and Genode environments. - -:Combination of CAmkES with Genode: - - [https://wiki.sel4.systems/CAmkES - CAmkES] is a component framework for - seL4. In contrast to Genode, which is a dynamic system, CAmkES-based systems - are defined at design time and remain fixed at runtime. Hence, CAmkES and - Genode can be seen as the opposite ends of component-based used-land - architectures. The goal of this project is to build a bridge between - both projects with the potential to cross-pollinate the respective communities. - Among the principal approaches are embedding of a single CAmkES - component as a Genode component (e.g., an individual device driver), - the hosting of a dynamic Genode system as a component within a - CAmkES system, or the hosting of a CAmkES system composition as a Genode - subsystem. - :Runtime for the D programming language: The D systems programming language was designed to overcome many gripes that @@ -181,19 +152,6 @@ Application frameworks and runtime environments programs, and interfacing D programs with other Genode components written in C++. -:Using Haskell as systems-development language: - - The goal of this project is the application of functional programming - i.e., Haskell, for the implementation of low-level Genode components. - Implementing critical functionalities in such a high-level language instead - of a classical systems language such as C or C++ would pave the way towards - analyzing such components with formal methods. - - The use of Haskell for systems development was pioneered by the - [https://programatica.cs.pdx.edu/House/ - House Project]. A more recent - development is [https://halvm.org - HalVM] - a light-weight OS runtime for - Xen that is based on Haskell. - :Xlib compatibility: Developments like Wayland notwithstanding, most application software on @@ -214,45 +172,44 @@ Application frameworks and runtime environments requests issued by a block-session client to a block-device driver, such a bump-in-the-wire component could visualize the access patterns of a block device. Similar ideas could be pursued for - other session interfaces, like the audio-out (sound visualization) or NIC + other session interfaces, like record/play (sound visualization) or NIC session (live visualization of network communication). The visualization of system behavior would offer valuable insights, e.g., new opportunities for optimization. But more importantly, they - would be extremely fun to play with. + would be fun to play with. + + +Platforms +######### + +:Support for additional ARM SoCs: + + Genode's ARM support has been focused on NXP's i.MX family, Allwinner A64 + (used by the PinePhone), and to a lesser degree the Raspberry Pi. To make + Genode compatible with a larger variety of devices, the support for further + chip families calls for exploration. For example, + [https://en.wikipedia.org/wiki/Rockchip - Rockchip] SoCs are getting + popular in products by open-source hardware vendors such as + [https://pine64.com/ - Pine64] and [https://mntre.com/ - MNT]. + The first steps have been [https://github.com/mickenx/genode-rockchip - already taken] + by [https://genodians.org/mickenx/index - Michael Grunditz]! + Another example is the Mediatek SoC family, which is popular in + affordable consumer smartphones. + Another example is the Mediatek SoC family, which is popular in + affordable consumer smartphones. + + The process of bringing an OS like Genode to a new SoC is full of technical + challenges and labor-intensive, yet extremely gratifying. + As a guide through this process, the + [https://genode.org/documentation/genode-platforms-23-05.pdf - Genode Platforms] + book breaks the challenge down to a sequence of manageable steps, where + each step can be celebrated as a success. Virtualization ############## -:VirtualBox on top of KVM on Linux: - - Genode's version of VirtualBox replaces the original in-kernel VirtualBox - hypervisor by the virtualization mechanism of the NOVA hypervisor or the - Muen separation kernel. Those mechanisms look very similar the KVM - interface of the Linux kernel. It should in principle be possible to - re-target Genode's version of VirtualBox to KVM. This way, VirtualBox and - Qemu/KVM-based virtual machines could co-exist on the same system, which - is normally not possible. Also, complex Genode scenarios (like Turmvilla) - could be prototyped on GNU/Linux. - -:Xen as kernel for Genode: - - Using Xen as kernel for Genode would clear the way to remove the - overly complex Linux OS from the trusted computing base of Xen - guests OSes. - - Xen is a hypervisor that can host multiple virtual machines on one physical - machine. For driving physical devices and for virtual-machine management, Xen - relies on a privileged guest OS called Dom0. Currently, Linux is the - predominant choice to be used as Dom0, which implicates a trusted computing - base of millions of lines of code for the other guest OSes. - - Even though Xen was designed as hypervisor, a thorough analysis done by Julian - Stecklina concludes that Xen qualifies well as a kernel for Genode. For - example, Julian implemented a version of Genode's IPC framework that utilizes - Xen's communication mechanisms (event channels and shared memory). - :Genode as virtualization layer for Qubes OS: [https://www.qubes-os.org/ - Qubes OS] is a desktop operating system @@ -278,121 +235,37 @@ Virtualization the project bears the opportunity to explore the provisioning of the KVM interface based on Genode's VFS plugin concept. -:Hardware-accelerated graphics for virtual machines: - In - [https://genode.org/documentation/release-notes/17.08#Hardware-accelerated_graphics_for_Intel_Gen-8_GPUs - Genode 17.08], - we introduced a GPU multiplexer for Intel Broadwell along with support - for Mesa-based 3D-accelerated applications. - While designing Genode's GPU-session interface, we also aimed at supporting - the hardware-accelerated graphics for Genode's virtual machine monitors like - VirtualBox or Seoul, but until now, we did not took the practical steps of - implementing a virtual GPU device model. +System management and tools +########################### - The goal of this project is the offering of a virtual GPU to a Linux guest - OS running on top of Genode's existing virtualization and driver - infrastructure. +:Virtual network-boot infrastructure as Sculpt component: + Network-based development work flows for PCs require a variety of tools and + network-configuration peculiarities. Think of a development network with a + custom configured DHCP server, a TFTP or HTTP server on the development + machine, the provisioning of a PXE boot loader, tooling for obtaining serial + output over AMT, or tooling for remote power control via AMT. -Device drivers -############## + The goal of this project would be the hosting of all those functions in a + Sculpt OS component "devnet" that is exclusively in charge of a dedicated + LAN port of the developer's Sculpt machine. By connecting a test machine to + this LAN port, the test machine becomes immediately available as development + target without any manual installation or configuration steps needed. The + devnet component would interface with the rest of the Sculpt system as a + client of a file-system session (containing the boot payloads) and a + terminal session (for the virtual serial connection). -:Sound on the Raspberry Pi: +:Statistical profiler using Sculpt's GDB monitor: - The goal of this project is a component that uses the Raspberry Pi's - PWM device to implement Genode's audio-out-session interface. Since - Genode's version of libSDL already supports this interface as audio - backend, the new driver will make the sound of all SDL-based games - available on the Raspberry Pi. - -:Data Plane Development Kit (DPDK): - - Genode utilizes the network device drivers of the iPXE project, which - perform reasonably well for everyday use cases but are obviously not - designated for high-performance networking. - The [https://dpdk.org/ - DPDK] is a vendor-supported suite of network device - drivers that is specifically developed for high-performance applications. - It presents an attractive alternative to iPXE-based drivers. This project - has the goal to make DPDK drivers available as a Genode component. - - -Platforms -######### - -:Microkernelizing Linux: - - Thanks to Genode's generic interfaces for I/O access as provided by core, all - Genode device drivers including drivers ported from Linux and gPXE can be - executed as user-level components on all supported microkernels. However, so - far, we have not enabled the use of these device drivers on Linux as base - platform. The goal of this project is the systematic replacement of in-kernel - Linux device drivers by Genode processes running in user space, effectively - reducing the Linux kernel to a runtime for Genode's core process. But moving - drivers to Genode processes is just the beginning. By employing further - Genode functionality such as its native GUI, lwIP, and Noux, many protocol - stacks can effectively be removed from the Linux kernel. - - In 2018, Johannes Kliemann pursued this topic to a state where Genode - could be used as init process atop a customized Linux kernel. - [https://lists.genode.org/pipermail/users/2018-May/006066.html - His work] - included the execution of Genode's regular device drivers for VESA and - PS/2 as regular Genode components so that Genode's interactive demo - scenario ran happily on a laptop. At this time, however, only parts of - his results were merged into Genode's mainline. - - The goal of this project is to follow up on Johannes' work, bring the - [https://github.com/genodelabs/genode/pull/2829 - remaining parts] into - shape for the inclusion into Genode, and address outstanding topics, in - particular the handling of DMA by user-level device drivers. Further down - the road, it would be tempting to explore the use of - [https://en.wikipedia.org/wiki/Seccomp - seccomp] as sandboxing mechanism - for Genode on Linux and the improvement of the Linux-specific implementation - of Genode's object-capability model. - -:Support for the HelenOS/SPARTAN kernel: - - [http://www.helenos.org - HelenOS] is a microkernel-based multi-server OS - developed at the university of Prague. It is based on the SPARTAN microkernel, - which runs on a wide variety of CPU architectures including Sparc, MIPS, and - PowerPC. This broad platform support makes SPARTAN an interesting kernel to - look at alone. But a further motivation is the fact that SPARTAN does not - follow the classical L4 road, providing a kernel API that comes with an own - terminology and different kernel primitives. This makes the mapping of - SPARTAN's kernel API to Genode a challenging endeavour and would provide us - with feedback regarding the universality of Genode's internal interfaces. - Finally, this project has the potential to ignite a further collaboration - between the HelenOS and Genode communities. - -:Support for the XNU kernel (Darwin): - - XNU is the kernel used by Darwin and Mac OS X. It is derived from the - MACH microkernel and extended with a UNIX-like syscall API. Because the - kernel is used for Mac OS X, it could represent an industry-strength - base platform for Genode supporting all CPU features as used by Mac OS X. - -:Genode on the Librem5 phone hardware: - - Even though there exists a great variety of ARM-based SoCs, Genode - primarily focuses on the NXP i.MX family because it is - in contrast - to most SoCs in the consumer space - very liberal in terms of - good-quality public documentation and reference code, and it scales - from industrial to end-user-facing use cases (multi-media). - - The [https://puri.sm/products/librem-5/ - Librem5] project - with its - mission to build a trustworthy mobile phone - has chosen the i.MX family as - the basis for their product for likely the same reasons that attract us. - - To goal of this work is bringing Genode to the Librem5 hardware. - For the Librem5 project, Genode could pave the ground towards new use cases - like high-security markets where a regular Linux-based OS would not be - accepted. For the Genode community, the Librem5 hardware could become an - attractive mobile platform for everyday use, similar to how we developers - use our Genode-based [https://genode.org/download/sculpt - Sculpt OS] on our - laptops. - - -System management -################# + Starting with version 24.04, Sculpt OS provides the ability to supervise + selected components + [https://genodians.org/chelmuth/2024-05-17-on-target-debugging - using the GDB protocol]. + The underlying mechanism and infrastructure could be leveraged for + implementing a statistical profiler that monitors components live. + Using the on-target information obtained via Sculpt's "download debug info" + option, the tool could display a sorted list of the most executed + functions, facilitating interactive on-target analysis and experimentation. :Remote management of Sculpt OS via Puppet: @@ -406,18 +279,3 @@ System management The project would explore the application of the Puppet approach and tools to Sculpt OS. - -Optimizations -############# - -:De-privileging the VESA graphics driver: - - The VESA graphics driver executes the graphics initialization code provided - by the graphics card via an x86 emulator. To initialize a graphics mode, this - code needs to access device hardware. Currently, we permit access to all - device registers requested by the graphics-card's code. These devices include - the system timer, the PCI configuration registers, and the interrupt - controller, which are critical for the proper operating of the kernel. The - goal of this work is to restrict the permissions of the VESA driver to a - minimum by virtualizing all devices but the actual graphics card. - diff --git a/doc/components.txt b/doc/components.txt index 7fe7f350e5..b4cedc24c5 100644 --- a/doc/components.txt +++ b/doc/components.txt @@ -34,10 +34,11 @@ of them is briefly characterized as follows: the driver is made available to other system components via one of Genode's device-independent session interfaces, which are 'platform_session', 'capture_session', 'event_session', 'block_session', - 'audio_out_session', 'log_session', 'nic_session', and 'timer_session' - (see _os/include/_ for the interface definitions). Those interfaces are - uniform across hardware platforms and kernel base platforms. Usually, - each device driver can accommodate only one client at a time. + 'record_session', 'play_session', 'log_session', 'uplink_session', and + 'timer_session' (see _os/include/_ for the interface definitions). + Those interfaces are uniform across hardware platforms and kernel base + platforms. Usually, each device driver accommodates one client at a + time. :Resource multiplexers: provide mechanisms to multiplex device resources to multiple clients. A typical resource multiplexer requests one @@ -64,7 +65,7 @@ of them is briefly characterized as follows: Device drivers ############## -Device drivers usually reside in the _src/drivers/_ subdirectory of source-code +Device drivers usually reside in the _src/driver/_ subdirectory of source-code repositories. The most predominant repositories hosting device drivers are 'os', 'dde_ipxe', 'dde_linux', 'pc'. The main source tree is accompanied by a variety of optional source-code repositories, each hosting the support of @@ -78,18 +79,23 @@ a different SoC family such as NXP's i.MX, Allwinner, Xilinx Zynq, or RISC-V. Platform devices ================ -:_os/src/drivers/platform/_: Platform drivers for various platforms. +:_os/src/driver/platform/_: Platform drivers for various platforms. On x86, the platform driver uses the PCI controller as found on x86 PC hardware. A client can probe for a particular device and request information about physical device resources (using the 'platform_device' interface). I/O resources for MMIO regions, I/O ports, and interrupts can be requested by the provided device abstraction. -:_os/src/drivers/acpi/_: +:_os/src/driver/acpi/_: On x86 platforms that use the APIC (namely Fiasco.OC, NOVA, and hw_x86_64) this simple ACPI parser traverses the ACPI tables and reports device-resource information (e.g., interrupt lines of PCI devices). +:_os/src/app/pci_decode/_: + A component that reports the physical information about PCI devices after + parsing and initializing the PCI bus. The reported information is usually + consumed by the platform driver. + :_os/src/app/smbios_decoder/_: A component that parses SMBIOS information on x86 platforms and makes the result available as a report. @@ -108,10 +114,10 @@ UART devices The UART device drivers implement the UART-session interface. -:_os/src/drivers/uart/spec/pbxa9/_: +:_os/src/driver/uart/spec/pbxa9/_: Driver for the PL011 UART as found on many ARM-based platforms. -:_os/src/drivers/uart/spec/x86/_: +:_os/src/driver/uart/spec/x86/_: Driver for the i8250 UART as found on PC hardware. @@ -121,11 +127,11 @@ Framebuffer and input drivers Framebuffer and input drivers are implemented as clients of the capture-session and event-session interfaces respectively. -:_os/src/drivers/ps2/x86/_: +:_os/src/driver/ps2/x86/_: Driver for the 'i8042' PS/2 controller as found in x86 PCs. It supports both mouse (including ImPS/2, ExPS/2) and keyboard. -:_os/src/drivers/ps2/pl050/_: +:_os/src/driver/ps2/pl050/_: Driver for the PL050 PS/2 controller as found on ARM platforms such as VersatilePB. The physical base address used by the driver is obtained at compile time from a header file called _pl050_defs.h_. The version of the @@ -133,33 +139,36 @@ capture-session and event-session interfaces respectively. is made available to the driver via the SPECS machinery of the Genode build system. -:_libports/src/drivers/framebuffer/vesa/_: +:_libports/src/driver/framebuffer/vesa/_: Driver using VESA mode setting on x86 PCs. For more information, please refer to the README file in the driver directory. -:_libports/src/drivers/framebuffer/boot/_: +:_libports/src/driver/framebuffer/boot/_: Driver for boot-time initialized framebuffers (e.g., UEFI GOP) discovered from the 'platform_info' ROM -:_os/src/drivers/framebuffer/pl11x/_: +:_os/src/driver/framebuffer/pl11x/_: Driver for the PL110/PL111 LCD display. -:_os/src/drivers/framebuffer/sdl/_: +:_os/src/driver/framebuffer/sdl/_: Serves as both framebuffer and input driver on Linux using libSDL. This driver is only usable on the Linux base platform. -:_os/src/drivers/gpu/intel/_: - An experimental Intel Graphics GPU multiplexer for Broadwell and newer. +:_os/src/driver/framebuffer/virtio/_: + Driver for the Virtio virtual graphics device as supported by Qemu. -:_pc/src/drivers/framebuffer/intel/_: +:_os/src/driver/gpu/intel/_: + An Intel Graphics GPU multiplexer for Broadwell and newer. + +:_pc/src/driver/framebuffer/intel/_: Framebuffer driver for Intel i915 compatible graphic cards based on the Linux Intel KMS driver. -:_pc/src/drivers/usb_host/_: +:_pc/src/driver/usb_host/_: USB host-controller driver that provides an USB session interface to USB drivers. -:_dde_linux/src/drivers/usb_hid/_: +:_dde_linux/src/driver/usb_hid/_: USB Human Interface Device driver using the USB session interface. @@ -186,14 +195,14 @@ provided by the kernel, or a pseudo time source (busy): Audio drivers ============= -Audio drivers implement the Audio_out session interface defined at -_os/include/audio_out_session/_ for playback and optionally the audio_in -interface for recording. +Audio drivers use the audio mixer's record session interface defined at +_os/include/record_session/_ for audio output and optionally the play +session interface _os/include/play_session/_ for audio input. -:_os/src/drivers/audio/spec/linux/_: +:_os/src/driver/audio/spec/linux/_: Uses ALSA as back-end on the Linux base platform and supports only playback. -:_dde_bsd/src/drivers/audio/_: +:_dde_bsd/src/driver/audio/_: Sound drivers ported from OpenBSD. Currently, the repository includes support for Intel HD Audio as well as for Ensoniq AudioPCI (ES1370) compatible sound cards. @@ -205,21 +214,17 @@ Block drivers All block drivers implement the block-session interface defined at _os/include/block_session/_. -:_os/src/drivers/sd_card/pl180/_: +:_os/src/driver/sd_card/pl180/_: Driver for SD-cards connected via the PL180 device as found on the PBX-A9 platform. -:_os/src/drivers/sd_card/imx53/_: - Driver for SD-cards connected to the Freescale i.MX53 platform like the - Quick Start Board or the USB armory device. - -:_os/src/drivers/ahci/_: +:_os/src/driver/ahci/_: Driver for SATA disks and CD-ROMs on x86 PCs. -:_os/src/drivers/nvme/_: +:_os/src/driver/nvme/_: Driver for NVMe block devices on x86 PCs. -:_os/src/drivers/usb_block/_: +:_os/src/driver/usb_block/_: USB Mass Storage Bulk-Only driver using the USB session interface and provides a block-session interface. @@ -230,28 +235,29 @@ Network interface drivers All network interface drivers implement the NIC session interface defined at _os/include/nic_session/_. -:_os/src/drivers/nic/spec/linux/_: +:_os/src/driver/nic/spec/linux/_: Driver that uses a Linux tap device as back end. It is only useful on the Linux base platform. -:_os/src/drivers/nic/lan9118/_: +:_os/src/driver/nic/lan9118/_: Native device driver for the LAN9118 network adaptor as featured on the PBX-A9 platform. -:_dde_ipxe/src/drivers/nic/_: +:_dde_ipxe/src/driver/nic/_: Device drivers ported from the iPXE project. Supported devices are Intel E1000 and pcnet32. -:_pc/src/drivers/wifi/_: +:_pc/src/driver/nic/pc/_: + The PC NIC-driver component uses network driver code of the Linux kernel + to drive common network cards as found in commodity PC hardware. + +:_pc/src/driver/wifi/_: The wifi driver component is a port of the Linux mac802.11 stack, including the iwlwifi driver. It enables the use of Intel Wireless 6xxx and 7xxx cards. -:_dde_linux/src/drivers/usb_net/_: +:_dde_linux/src/driver/usb_net/_: USB network driver using the USB session interface. -:_dde_linux/src/drivers/nic/fec/_: - Driver for ethernet NICs of the i.MX SoC family. - Resource multiplexers ##################### @@ -268,9 +274,9 @@ subdirectory of a source repository. framebuffer and a virtual input interface. Nitpicker (including a README file) is located at _os/src/server/nitpicker/_. -:Audio output: The audio mixer located at _os/src/server/mixer/_ enables - multiple clients to use the audio-out interface. The mixing is done by simply - adding and clamping the signals of all present clients. +:Audio output: The audio mixer located at _os/src/server/record_play_mixer/_ + allows for the routing and mixing of audio signals from play-session clients + to record-session clients. :Networking: The NIC bridge located at _os/src/server/nic_bridge/_ multiplexes one NIC session to multiple virtual NIC sessions using a proxy-ARP @@ -282,6 +288,9 @@ subdirectory of a source repository. session to multiple virtual NIC sessions by applying network address translation (NAT). + The NIC-uplink component located at _os/src/server/nic_uplink/_ connects + a NIC client directly to a network driver (as uplink client) without routing. + :Block: The block-device partition server at _os/src/server/part_block/_ reads the partition table of a block session and exports each partition found as separate block session. For using this server, please refer to the run @@ -491,8 +500,8 @@ Libraries Library for implementing pseudo-graphical applications (i.e., VIM) that run on a text terminal. -:_libports/lib/mk/qt5_*/_: - Qt5 framework, using GUI session and NIC session as back end. +:_libports/qt6/_: + Qt6 application framework. :_libports/lib/mk/vfs_jitterentropy.mk_: A VFS plugin that makes a jitter-based random-number generator available @@ -530,14 +539,14 @@ located in their respective directory. :_demo/src/app/scout/_: Graphical hypertext browser used for Genode's default demonstration scenario. -:_ports/src/app/gdb_monitor/_: - Application that allows the debugging of a process via GDB over a remote - connection. +:_os/src/monitor/_: + Variant of init that allows for the debugging of components via GDB over a + remote connection. -:_libports/src/app/qt5/qt_launchpad/_: +:_libports/src/app/qt6/qt_launchpad/_: Graphical application starter implemented using Qt. -:_libports/src/app/qt5/examples/_: +:_libports/src/app/qt6/examples/_: Several example applications that come with Qt. :_os/src/app/sequence/_: @@ -577,6 +586,9 @@ Package-management components :_gems/src/app/depot_deploy/_: Subsystem init configuration generator based on blueprints. +:_gems/src/app/depot_remove/_: + Tool for the orderly removal of depot content. + :_libports/src/app/fetchurl/_: A runtime-configurable frontend to the libcURL library for downloading content. diff --git a/doc/depot.txt b/doc/depot.txt index 7fcab5ff49..abd9196a13 100644 --- a/doc/depot.txt +++ b/doc/depot.txt @@ -228,7 +228,7 @@ subdirectory. Within this directory, there is a 'pubkey' file with the user's public key that is used to verify the integrity of archives downloaded from the user. The file 'download' specifies the download location as an URL. -Subsuming archives in a subdirectory that correspond to their the origin +Subsuming archives in a subdirectory that correspond to their origin (user) serves two purposes. First, it provides a user-local name space for versioning archives. E.g., there might be two versions of a 'nitpicker/2017-04-15' source archive, one by "genodelabs" and one by @@ -290,7 +290,7 @@ archive is downloaded as well. All archive types are accepted as arguments including binary and package archives. Furthermore, it is possible to download all binary archives referenced by a package archive. For example, the following command downloads the window-manager (wm) package archive including -all binary archives for the 32-bit x86 architecture. Downloaded binary +all binary archives for the 64-bit x86 architecture. Downloaded binary archives are always accompanied with their corresponding source and used API archives. diff --git a/doc/getting_started.txt b/doc/getting_started.txt index 70569c418d..e9679cd351 100644 --- a/doc/getting_started.txt +++ b/doc/getting_started.txt @@ -22,7 +22,8 @@ The best starting point for exploring Genode is to run it on Linux. Make sure that your system satisfies the following requirements: * GNU Make version 3.81 or newer -* 'libSDL-dev' +* 'libsdl2-dev', 'libdrm-dev', and 'libgbm-dev' (needed to run interactive + system scenarios directly on Linux) * 'tclsh' and 'expect' * 'byacc' (only needed for the L4/Fiasco kernel) * 'qemu' and 'xorriso' (for testing non-Linux platforms via Qemu) diff --git a/doc/news.txt b/doc/news.txt index 46f5b2cd18..69ca452c64 100644 --- a/doc/news.txt +++ b/doc/news.txt @@ -4,6 +4,516 @@ =========== +Genode OS Framework release 24.08 | 2024-08-29 +############################################## + +| Genode 24.08 introduces the Qt6 application framework, updates all +| Linux-based components and PC device drivers to Linux version 6.6.47, +| equips the Goa SDK with remote debugging support, modernizes the base +| and GUI interfaces of the framework, extends the board support for +| i.MX-based devices, and explores AVX on x86. + +The highlights of Genode 24.08 are the addition of the Qt6 application +framework in addition to the time-tested Qt5 and the major update of all +Linux-based components and PC device drivers. So Genode users can enjoy +current-generation commodity software and drivers across all kernels supported +by the framework. + +For developers, the new combination of Genode's recent advances in +on-target debugging with the Goa SDK enables seamless remote debugging. + +Regarding hardware support, the new version broadens the driver landscape for +NXP i.MX-based devices, paving the way for Sculpt OS on the +[https://shop.mntre.com/products/mnt-pocket-reform - MNT Pocket Reform] +open-source hardware laptop. + +For the full picture, please refer to the +[https:/documentation/release-notes/24.08 - release documentation of version 24.08...] + + +New community forum at Discourse | 2024-08-13 +############################################# + +| Our new community forum is organized by Genode users to share ideas +| and experiences, help newcomers, and discuss Genode-related projects. + +The new forum complements the existing +[http:/community/mailing-lists - mailing list] and +[https://github.com/genodelabs/genode - issue tracker] +with a place for casual conversation among newcomers, seasoned users, +and developers. + +[https://genode.discourse.group] + +As the forum is a place for users, it is moderated by users. Thanks a lot +to Spencer and Cedric for constituting the initial moderation team! + + +Meet us at FroSCon during August 17-18 | 2024-07-30 +################################################### + +| The Genode project will host a booth at this year's Free +| and Open-Source Software Conference in Sankt Augustin. + +Besides FOSDEM, public appearances of Genode are rather rare. +All the more delighted we are about the opportunity to host +a booth at the upcoming FrOScon conference. + +*FrOScon Free and Open-Source Software Conference* + +*August 18 and 17 in Sankt Augustin* + +[https://froscon.org] + +The Genode stand will be maintained by the Genode team members +Stefan Kalkowski, Johannes Schlatow, Christian Helmuth, and +Norman Feske. It goes without saying that we will have Sculpt +OS in various forms and flavors with us to showcase. Whether +you like to get acquainted with our project or touch base with +us developers in person, FrOScon might present the perfect +opportunity! + + +Genode OS Framework release 24.05 | 2024-05-30 +############################################## + +| The highlights of Genode 24.05 are the new ability to run Sculpt OS on +| our custom kernel, GDB on Sculpt OS, suspend/resume, the redesign of +| the framework's USB infrastructure, and the completed transition to +| the new audio interfaces. The release is accompanied with the annual +| update of the "Genode Foundations" book. + +With Genode 24.05, the underpinnings of the many usability improvements +of the [https://genode.org/news/sculpt-os-release-24.04 - latest] Sculpt OS +release found their way into the framework. Among them are a completely +redesigned USB infrastructure that allows for fine-grained and dynamic +assignment of USB devices to components and virtual machines, the consistent +use of the audio facilities introduced in February, and the driver life-cycle +management for suspend/resume. + +Beside those usability-related topics, two mile-stone achievements stand out. +First, we have realized our long-time vision of running Sculpt OS on our +custom kernel specifically designed for Genode. With Intel virtualization +support, the release delivers the final missing piece of this puzzle. +Second, our long-hedged dream of natural on-target debugging via the GNU +debugger running directly on Sculpt OS has become true. This feature, which +has been in the works for more than a year, enables Sculpt OS users to +leverage GDB for the development of applications, services, and even device +drivers. + +The release is accompanied by a new version of the "Genode Foundations" book, +which is the go-to documentation of the framework. +Further topics of the current release range from timing and network-throughput +optimizations, over updated 3rd-party software like Mesa, libSDL2, and cURL, +to developer tooling. Find these among many more topics covered in the detailed +[https:/documentation/release-notes/24.05 - release documentation of version 24.05...] + + +Sculpt OS release 24.04 | 2024-04-26 +#################################### + +| Sculpt OS 24.04 is rich of new user-visible features. +| It now supports 4K displays and I2C touchpads out of the box, +| brings experimental support for suspend/resume, +| allows the fine-grained assignment of USB devices to applications and VMs, +| and introduces new audio-mixing capabilities. + +The release of version 24.04 adheres to +our [https://genode.org/about/road-map - declared] focus on Sculpt OS usability +during this year. Seasoned users will immediately recognize the new power of the +component-management UI, offering easy control over optional features, +software providers, and software installation. Among many little +user-interface improvements, the component graph and configuration interface +have become scrollable, boosting the interactive user experience. + +When looking closely at the components, users will recognize a whole new set +of drivers neatly grouped under hardware. In contrast to earlier versions, +which operated these drivers hidden from the user, the new version manages the +drivers dynamically and fully transparent for the user. The change makes the +user interface more logical and simpler. However, the driving force behind this +approach +was our aspired support for suspend/resume, which requires the dynamic +life-cycle management of drivers. This brings us to the technical highlight of +the release: After on-and-off development for more than a year, we are more +than happy offering suspend/resume as an experimental feature. + +As culmination of a second long-term development, version 24.04 employs a new +and much more flexible interplay between the USB-host driver and components +accessing USB devices. The dynamic assignment of devices to virtual machines +and other components has become a breeze. + +Just in time for the release, Sculpt OS has received a completely overhauled +audio stack that supports pluggable drivers, arbitrary sample rates, and the +flexible routing and mixing of audio signals. We are eager to stress and +refine the taken approach over the upcoming release cycle to make low-latency +audio a commodity on Sculpt OS. + +Thanks to our routine with running Sculpt OS on modern laptops day to day, +version 24.04 bumps the range of supported hardware. Displays up to 4K are +supported out of the box now, and touchpads of laptops like the Gen13 Framework +have become operational. + +Speaking of developers, the release offers two bold new features targeted at +this specific demography, namely the support for on-target debugging via GDB, +and the ability to use Sculpt OS as a remote test target of Genode's Goa SDK. +Look out for more information about these features in the upcoming weeks +at [https://genodians.org]. + +Sculpt OS 24.04 is available as ready-to-use system image at the +[https://genode.org/download/sculpt - Sculpt download page] accompanied +with updated [https://genode.org/documentation/articles/sculpt-24-04 - documentation]. + + +Genode OS Framework release 24.02 | 2024-02-29 +############################################## + +| Version 24.02 revisits Genode's audio support for latency-sensitive +| scenarios, flexible sample rates, and pluggable drivers. It also introduces +| the new ability of the Goa SDK to use Sculpt OS as remote test target, +| comes with a new TCP/IP stack based on Linux 6.1.20, makes drivers aware +| of suspend/resume, and improves HID event handling. + +Genode 24.02 kicks off the year with a profound redesign of the framework's +audio infrastructure, addressing the routing and mixing of multi-channel audio +streams at flexible sample rates, the dynamic starting and removal of audio +sources and sinks, and latency optimization. + +Besides audio, the second infrastructural rework is a new TCP/IP stack based +on DDE-Linux 6.1.20. It wraps up our long-year transition from a fairly +fragmented landscape of ported driver code to the consistent use of our modern +Linux device-driver environment across all Linux-based drivers and protocol +stacks. + +The feature highlight of the release is the new ability of using Sculpt OS as +a remote test target for the Goa SDK during application development. Thanks +to this new feature, Genode applications can be developed and tested in a +quick and uniform way, whether testing directly on a Linux-based development +environment, or on a Sculpt PC reachable via a local network, or a PinePhone +connected to the same wireless access point. + +Further highlights of the release are the versatile handling of human-interface +devices including the calibration of motion events, the use of Vivante GPUs by +multiple clients, and the driver-related preparatory steps needed for +implementing suspend/resume for Sculpt OS. + +You can find the changes presented in full detail in the +[https:/documentation/release-notes/24.02 - release documentation of version 24.02...] + + +Road Map for 2024 | 2024-01-18 +############################## + +| After intensively concentrating on deeply technical topics below the surface +| in 2023, we are going to reap user-visible rewards in 2024 by focussing on +| Sculpt OS usability. + +Thanks to the input gathered from our annual road-map discussion on Genode's +[https://genode.org/community/mailing-lists - mailing list], we have updated +the project [https://genode.org/about/road-map - road map] for 2024. + +Without hesitation, our developer community quickly rallied behind the topic +"Sculpt OS usability", desiring to boost the user experience with respect to +multi-monitor usage, convenient interactive UIs for common tasks, +profound support for touchpads and touchscreens, tearing-free graphics, +low-latency audio, casual on-target debugging, and suspend/resume. + +The focus on usability notwithstanding, we will steadily continue with the +gardening of Genode's driver landscape, fostering the consistent use of drivers +ported from up-to-date Linux kernels, clear-cut ACPI support, and making +drivers pluggable. +In 2024, we will also promote Genode's custom (base-hw) microkernel to become +the default kernel for Sculpt OS, which is the culmination of a multi-year +effort. + +Please find our reflection of the past year and the complete plan for 2024 +presented on Genode's official [https:/about/road-map - road-map page]. + + +Genode OS Framework release 23.11 | 2023-11-30 +############################################## + +| Genode 23.11 moves the IOMMU driver from the kernel to the user land, +| introduces CPU power/temperature/frequency monitoring and steering, +| comes with a new API for low-complexity GUI applications, and +| streamlines the framework's virtualization interface. It also improves +| developer ergonomics and showcases the port of the Linphone VoIP stack. + +Version 23.11 of the Genode OS Framework introduces DMA protection as +kernel-agnostic feature, parting with the tradition of driving I/O protection +units from the kernel. This radical move is accompanied by a sweeping +modernization of the framework's virtualization interface across kernels and +instruction-set architectures. In other words, the release is dominated by +deeply technical topics. + +That said, it is not void of user-facing features either, as illustrated by +the new port of the Linphone VoIP stack using the Goa tool, the extension of +the Seoul virtual machine monitor to 64-bit guests, and the support for CPU +power/temperature/frequency monitoring and steering on PC platforms. +Furthermore, developers receive better tooling for the use and distribution of +debug builds, and will observe a welcomed boost of their development-test +cycles thanks to a largely streamlined build-system. + +These and more topics are covered in full detail by the +[https:/documentation/release-notes/23.11 - release documentation of version 23.11...] + + +Sculpt OS release 23.10 | 2023-10-26 +#################################### + +| Modern PCs provide plenty of metering and power-management options. +| Version 23.10 of the Genode-based Sculpt operating system makes these features +| available via an interactive user interface. One can watch the temperature +| of each CPU core, monitor the individual CPU frequencies, switch between +| power profiles, and reveal details about power draw. + +Our official +[https://genode.org/documentation/articles/sculpt-23-10 - documentation] +introduces Sculpt as an operating system that puts the user in the position +of full control. With the new release, this promise is taken to the precise +control and monitoring of physical CPU parameters. + +Besides restricting workloads to specific CPU cores, each individual core can +be interactively parametrized, e.g., by balancing performance against power +efficiency. The effects of changing these parameters become immediately +visible by the monitored frequencies, temperature, and power draw. The new +knobs add plenty of play value and an entirely new sense of control to the +user experience. You can find the new power-control feature described in a +[https://genodians.org/alex-ab/2023-10-23-msr - dedicated article]. + +The advanced power-control abilities are accompanied with generally improved +support for modern laptops. E.g., on the Framework Gen 12 laptop, +features like battery monitoring, keyboard backlight control, and external +displays just work now. + +Like the previous release, Sculpt OS is available for both PCs and the +PinePhone. The PinePhone version received several usability improvements +motivated by the feedback we got from the Pine64 community. Most importantly, +a new screensaver reduces the power draw to less than 40%, making the device +more viable in practice. +Under the hood, Sculpt completely removes the drivers for the display and the +touchscreen while the screen is blanked. Those drivers are restarted when +pressing the power button. Furthermore, the volume buttons have become +functional, and the dial pad has become more flexible. + +Beside the user-visible improvements, the underpinnings of Sculpt OS +received a number of improvements. The entire software is now consistently +built with GCC 12.3. The former iPXE-based network driver has been replaced +by driver code of the Linux kernel 6.1.20, which works nicely on modern +machines. The new version also introduces the principle mechanisms needed +for on-target debugging, switches to a much revised virtualization interface, +and replaces the block-encryption engine of the file vault. Users of the latter +should follow the documented +[https://genodians.org/m-stein/2023-10-25-file-vault-migration-1 - migration steps]. + +Sculpt OS 23.10 for PC and PinePhone is available as ready-to-use system image +at the [https://genode.org/download/sculpt - Sculpt download page] accompanied +with updated [https://genode.org/documentation/articles/sculpt-23-10 - documentation]. +Seasoned Sculpt users can conveniently switch to the new version via the +system-update dialog. + + +Genode OS Framework release 23.08 | 2023-08-24 +############################################## + +| The main theme of the current release is tooling for developing, debugging, +| porting, and publishing Genode components. Beyond that, the release improves +| driver support and the internals of core and the base-framework. + +The headline features of this release introduce a new multi-component debug +monitor and extend the Goa tool with support for working with multiple +projects. + +The new debug monitor reapproaches Genode's GDB debugging support and sets +smooth on-target debugging in Sculpt OS as its final goal. The monitor can +transparently replace the Init component and is equipped with support for +multi-component debugging by GDB inferiors. The Goa tool evolves into an +all-encompassing alternative to Genode's traditional work flows for developing, +porting, and publishing applications. With this release, runtime testing with +Goa gets extremely flexible and handling of multiple Goa projects becomes a no +brainer. + +Beside the tooling topics, we round out the release with a new PC NIC driver +based on Linux, new RaspberryPi/i.MX6 USB host-controller drivers, +hardware-button and screensaver support on the PinePhone, improved Intel +GPU/display, WiFi, and audio drivers. + +Find all details of changes and improvements in the +[https:/documentation/release-notes/23.08 - release documentation of version 23.08...] + + +Genode OS Framework release 23.05 | 2023-05-31 +############################################## + +| Besides the annual documentation update, the scheduled tool-chain update, +| and the switch to C++20, the release puts the spotlight on the Goa tool, +| which enables the use of existing SDKs like Lomiri or Rust's cargo for +| targeting Genode. + +By now, the dedication of Genode's May releases to housekeeping tasks has +become a fine tradition, and this year is no different. With version 23.05, +the framework consistently switches from the C++ standard C++17 to C++20, +thanks to our new tool chain based on GCC 12.3, which will serve us for the +next two years. Speaking of consistency, both Genode books "Foundations" and +"Platforms" have been updated to the most recent version of the framework. You +can find the PDFs at the [https://genode.org - genode.org front page]. + +Following the recent release of Sculpt OS 23.04 targeting both PC and mobile +platforms, Genode 23.05 brings good news for application developers interested +in targeting Genode and Sculpt OS in particular. The release introduces the +ability to use existing SDKs, in particular the Lomiri UI toolkit as well as +Rust's cargo for crafting Genode applications. + +A prominent topic among the previous releases is our Linux device-driver +environment (DDE), which allows for the use of Linux drivers as Genode +components. The current release continues this line of work by upgrading DDE +to Linux 6.1.20 and by using DDE as enabler of our cross-platform Wifi stack +that works for the PC and ARM platforms like the PinePhone. This way, Genode +users can benefit from the enormous efforts of the Linux kernel community +targeting modern hardware. + +Further highlights of the new version are the initial use of our custom +base-hw microkernel as x86 hypervisor, a profoundly reworked block-encryption +stack, and updates of supported 3rd-party software like the seL4 kernel and +VirtualBox. + +All changes are covered in detail by the official +[https:/documentation/release-notes/23.05 - release documentation of version 23.05...] + + +Sculpt OS release 23.04 | 2023-04-28 +#################################### + +| Sculpt OS 23.04 marks the first-time PinePhone support in addition to the PC +| version. With this release, the system supports live upgrades of the boot +| image, rendering Sculpt updates and the switching between versions a matter of +| some easy steps. The new preset feature brings entire application scenarios to +| your screen after just one click/tap. + +With the fresh release 23.04, the Sculpt operating system boards the PinePhone +to explore the mobile world and, thereby, adds a second platform to its +year-long support for Intel PCs. In preparation, we added two key features to +Genode during the past months, which are the phone-oriented Sculpt +user-interface variant and the system-update functionality. Now, Sculpt +versions can be switched by three easy steps directly in the integrated user +interface: downloading system images to the software depot, install the +desired version on the boot medium, and reboot the device. + +Further, the release supports so-called presets in the system menu UI, which +are entire runtime scenarios. The user can load and switch between presets by +just one click. Presets currently available in Sculpt are a simple GUI demo +(nano3d), a simple desktop including background picture and window manager, +and a ready to use Falkon web browser. Still, components can be integrated +into the system (or the currently running preset) by the + menu of the +component graph. + +Sculpt OS 23.04 for PC and PinePhone is available as ready-to-use system image +at the [https://genode.org/download/sculpt - Sculpt download page] accompanied +with updated [https://genode.org/documentation/articles/sculpt-23-04 - documentation]. + + +Genode OS Framework release 23.02 | 2023-02-28 +############################################## + +| Version 23.02 introduces system-update functionality to the mobile version +| of Sculpt OS, enhances our ARM VMM for interactive guest OSes, adds DMA +| protection to Xilinx Zynq via a custom IP core, extends suspend/resume +| support, and makes Intel's P&E cores explicitly manageable. + +For the first time, Genode has become easily installable on the PinePhone. +The first system image is not merely a re-targeted PC version of Sculpt OS but +it comes with a novel user interface, a new mechanism for rapidly switching +between different application scenarios, and system-update functionality. This +is everything we need to kick off the first public field test of Genode on the +phone. This line of development motivated plenty of optimizations - from +kernel scheduling, over the I/O throughput of the VFS, to the interfacing of +GPU drivers - that made it into version 23.02. + +Besides the focus on the phone, the release continues the hardware-software +co-design story of the previous version by adding DMA protection to Xilinx +Zynq SoCs using custom FPGA fabric, which is especially tailored for Genode. +But also stationary platforms like PCs and ARM laptops received attention. +On ARM, we enabled the use of interactive virtual machines by adding +device models for the GPU and input events. For the PC, the principle support +for suspend/resume has become available to Genode's custom microkernel in +addition to NOVA, and Genode learned to distinguish Intel's performance cores +from energy-efficient cores. + +Regarding application workloads, the new release is accompanied by a +substantially improved version of the Goa tool, which streamlines the +creation, packaging, and publishing of Genode components using commodity +build systems. With the new version, Goa largely automates the +porting of CMake-based 3rd-party libraries for Genode. + +Find these among many more topics covered by the official +[https:/documentation/release-notes/23.02 - release documentation of version 23.02...] + + +Road Map for 2023 | 2023-01-17 +############################## + +| In 2023, we will make the mobile version of Sculpt OS fit for end users, +| unleash advanced hardware features of Intel platforms, +| switch to C++20 by default, and run the feature-complete PC version +| of Sculpt OS on Genode's custom-tailored microkernel. + +After having enabled all hardware features of the PinePhone that are +fundamental for a mobile phone over the course of the past year, the +project now aims at getting the mobile version of Sculpt OS into the hands of +end users. Throughout the year, there will be multiple rounds of field tests +within the community, allowing us to reach the desired state of maturity and +usefulness in an iterative way. + +On PC platforms, Genode will increasingly address advanced platform features +like the distinction between power-efficient and high-performance cores, the +management of temperatures and frequencies, or the practical use of +suspend/resume. By the end of the year, we envision the PC version of Sculpt +OS running on Genode's custom-tailored microkernel leveraging all those +aspects of modern PC hardware. + +Along the planned timeline of the project, one can spot plenty of additional +topics of interest such as the continued line of work of combining Genode +with FPGAs, applications implemented in Rust, the integration of IPv6, the +use of C++20 by default, or completed driver support for the MNT Reform laptop. +An exciting year lies ahead of us! + +More details including our reflections of the past year, this year's focus, +and a rough schedule are presented at our official +[https:/about/road-map - road-map page]. + + +Genode OS Framework release 22.11 | 2022-11-30 +############################################## + +| Genode 22.11 enables hardware-accelerated graphics on up-to-date Intel +| GEN12+ hardware, introduces work flows for hardware-software co-design, +| wraps up the framework's unified device-driver infrastructure across PC and +| ARM, and pushes forward the use of Genode on the PinePhone. + +The Genode OS framework is both a dependable foundation for custom operating +systems - like Sculpt OS - and at the same time a playground for new ideas. +The just released version 22.11 pays tribute to both facets. On the one hand, +it features the results of our year-long effort of unifying and simplifying +the framework's device-driver infrastructure across all base platforms, which +subjects the interaction of driver components with device hardware to an +unprecedentedly rigid regime of least privilege. This makes Genode-based +systems ever more dependable and clear. + +The role of Genode as a playground for innovation is embodied by the +combination of the framework with reconfigurable hardware. The release +introduces new work flows for designing hardware IP cores and Genode +components in tandem, which allows for low-complexity software-hardware +co-designs that fit like a glove. + +Feature-wise, the new version covers a vast area of topics. The enhancement of +our Intel GPU multiplexer to current GEN12+ hardware stands out most. Further +topics range from the emerging user interface for Genode on the PinePhone, +over plenty of device-driver work, to virtualization improvements on ARM and +PC hardware. + +These and many more topics of the new version are covered by the official +[https:/documentation/release-notes/22.11 - release documentation of version 22.11...] + + Sculpt OS release 22.10 | 2022-10-13 #################################### diff --git a/doc/release_notes/22-08.txt b/doc/release_notes/22-08.txt index 6b501b28f2..224cb4a750 100644 --- a/doc/release_notes/22-08.txt +++ b/doc/release_notes/22-08.txt @@ -400,7 +400,7 @@ We invite seasoned developers - especially those who are following the [https://genodians.org/nfeske/index - Pine-fun article series] - to experiment with the new phone variant. It can be built via the following command: -! built/arm_v8a$ make run/sculpt KERNEL=hw BOARD=pinephone SCULPT=phone +! build/arm_v8a$ make run/sculpt KERNEL=hw BOARD=pinephone SCULPT=phone For a broader audience, we plan to provide a ready-to-use SD-card image for the PinePhone in tandem with the next release of Sculpt OS. diff --git a/doc/release_notes/22-11.txt b/doc/release_notes/22-11.txt new file mode 100644 index 0000000000..06e54b3794 --- /dev/null +++ b/doc/release_notes/22-11.txt @@ -0,0 +1,1015 @@ + + + =============================================== + Release notes for the Genode OS Framework 22.11 + =============================================== + + Genode Labs + + + +With version 22.11, we pursued two new exploratory topics as we envisioned on +the project's [https://genode.org/about/road-map - road map] for this year, +namely the use of the framework for hardware-software co-design work, +and principally enabling suspend/resume functionality on PCs. + +A decade ago, we +[https://genode.org/documentation/release-notes/11.02#Approaching_platform_support_for_Xilinx_MicroBlaze - explored the combination] +of Genode with FPGA technology for the first time. +Our interest in this direction got reignited two years ago when we started +enabling Genode on a board based on the Xilinx Zynq, which combines an ARMv7 +SoC with FPGA fabric. This line of work eventually culminated in new +development work flows for creating hardware IP cores and Genode components in +tandem. Section [Hardware-software co-design with Genode on Xilinx Zynq] covers +the results of this line of work. + +The second largely exploratory topic is the practical use of sleep states +on PC hardware, which - until this point - remained rather mysterious to us. +Section [Low-level mechanism for suspend/resume on PC platforms] reports +on our findings and the forthcoming integration of this feature into Genode. + +Besides the exploration work, the profound enhancement of our Intel GPU +multiplexer stands out. As detailed in Section +[Hardware-accelerated graphics with Intel GEN12+ GPUs], the new version +supports up-to-date GEN12+ GPUs, comes with numerous robustness and +performance improvements, and got adapted to Genode's new uniform driver +infrastructure. + +The latter point brings us to the most elaborate development under the hood +of the framework, which is the great unification of the device-driver +interfaces across all supported architectures. +Section [Uniform use of new platform-driver interface] wraps up this +intensive line of work, which left no PC-related driver unturned. + +A recurring theme throughout this year is the use of Genode on the PinePhone. +The current release is no exception. +Sections [Emerging Sculpt OS variant for the PinePhone] and +[PinePhone drivers for audio, camera, and power control] report on the +progress at the user-facing side as well as the driver-related achievements +digging deep into the realms of power management, audio, and the camera. + +Among the many further topics of the current release are virtualization on PC +and ARM (Sections [ARM virtual machine monitor] and [Seoul VMM]), plenty +of device-driver improvements, and enhanced tooling that makes the framework +ever more enjoyable to use (Section [Build system and tools]). + + +Hardware-software co-design with Genode on Xilinx Zynq +###################################################### + +A distinct feature of the Xilinx Zynq-7000 SoC is the combination of its +Cortex-A9 CPU with an FPGA, which is also referred to as _programmable logic_. +As the name suggests, the FPGA can be programmed with custom hardware designs +and thus act as an accelerator, DSP, or an arbitrary peripheral device. The +Zynq platform thereby accommodates a playground for hardware-software co-design +for a comparably low budget. + +While extending the platform support for the Zynq in general, we have +particularly been working towards establishing the required infrastructure +for supporting hardware-software co-design in Genode. With this release, we +can draw an almost complete picture of such a co-design workflow in Genode. +Our achievements culminate in a beginner-level tutorial for the Zybo Z7 board. + + +Runtime reconfiguration of the FPGA +=================================== + +A key component to FPGA runtime reconfiguration in Genode is the +_drivers_fpga-zynq_ subsystem that we already +[https://genode.org/documentation/release-notes/22.05#Xilinx_Zynq - introduced with release 22.05]. + +This subsystem enabled bitstream loading at runtime in order to reprogram the +FPGA. In conjunction with the _Zynq Driver Manager_, it allowed +launching/stopping of device drivers in accordance with the availability of the +devices implemented on the FPGA. + +For this release, we reworked this subsystem in order to support switching +between several bitstreams. In particular, we added a _devices manager_ to +merge the static 'devices' ROM with a bitstream-dependent set of devices. The +latter is specified by the component's configuration as follows: + +! +! +! +! +! +! +! +! +! + +The configuration comprises an arbitrary number of _bitstream_ nodes with a +mandatory _name_ attribute. Each _bitstream_ node may contain a set of device +specifications as expected by the platform driver. The _devices manager_ merges +the static 'devices' ROM with the devices of the currently loaded bitstream, +which is reported by the _fpga_drv_ component. The result is then consumed +by the platform driver. The bitstream to be loaded is specified by the +configuration of the _fpga_drv_ as follows: + +! +! +! + +These changes are bundled into the new _drivers_fpga-zynq_ subsystem. +The figure below illustrates how this subsystem is used as a replacement for +the platform driver. + +[image zynq_driver_manager_22_11] + +Just as the standard platform driver, the subsystem expects a 'policy' and +'devices' ROM. In addition, we must provide it with a _devices_manager.config_ +ROM as shown above. The bitstreams as well as the configuration for the internal +_fpga_drv_ component must be provided via a file system session. + +In addition to these changes to the _drivers_fpga-zynq_ subsystem, we added +configurability of the four FPGA clocks ("fpga0" to "fpga3") to the Zynq +platform driver. Moreover, we added four equally named reset domains. + +All changes are found in the +[https://github.com/genodelabs/genode-zynq - genode-zynq] +repository. + + +Packaging of bitstreams with Goa +================================ + +Custom hardware designs for the Zynq SoC are created with Xilinx Vivado. +In order to simplify reproducing a bitstream from its sources and creating +corresponding depot archives, we added Vivado as a supported build system to +[https://github.com/nfeske/goa - Goa]. In particular, we leveraged the fact +that a hardware project can be exported from Vivado as a tcl script that +reproduces the project. With this approach, we only need to keep the custom +source files and omit any generated glue code. + +In addition, we added support for auto-generating a _devices_manager.config_ +from a hardware design. When provided with a sparse _devices_ file (mentioning +the name or type of each device), Goa tries to extract the corresponding MMIO +addresses and clock rates from the design and adds a corresponding +_devices_manager.config_ to the depot archive. + +Please find detailed instructions in the Goa documentation via + +! $ goa help build-systems + + +Pin driver and co-design tutorial +================================= + +Following the lead of the Allwinner SoC, we implemented a pin driver for the +Zynq platform. Since GPIO on the Zynq may require loading of a custom bitstream +in case the FPGA's I/O pins are used, we developed and published a tutorial +for the Zybo Z7 board. This tutorial showcases a co-design workflow +demonstrating the use of the pin driver, custom hardware design with Xilinx +Vivado, bitstream generation and packaging with Goa as well as bitstream +switching at runtime. +You can find the tutorial on the new +[https://www.hackster.io/genode/ - Genode channel on hackster.io]. + + +Hardware-accelerated graphics with Intel GEN12+ GPUs +#################################################### + +With our big [https://mesa3d.org - Mesa 3D] library update from version 11.2.2 +to version [https://genode.org/documentation/release-notes/21.08 - 21.0.0], +we also switched the Intel graphics back end from the dated DRI2/i965 to the +Gallium/Iris based graphics driver. The reason for doing so is becoming +apparent with the current Genode release. The old i965 driver does not support +newer Intel Graphics hardware and is limited to (U)HD graphics devices found, +for example, on Broadwell, Skylake, or Kabylake platforms. The new +[https://en.wikipedia.org/wiki/Intel_Xe - Intel Xe] (eXascale for +everyone = GEN12) hardware is only supported by the Iris driver and can be +found on current architectures like Tigerlake or Alderlake. Intel Xe comes +with a completely new instruction set architecture (ISA). Thanks to our switch +to Iris, most of these ISA changes are handled transparently by the Mesa +library for us. The main task for Genode was to adjust our Intel GPU +multiplexer to the new graphics-device generation. + + +Intel GPU-GEN12 multiplexer adjustments +======================================= + +Genode's GPU multiplexer is a very low level component within the 3D graphics +stack. Technically, it handles the GPU resources (like graphics memory) and the +scheduling and execution of compiled GPU code (i.e., batch buffers) of the +graphics device. It is also responsible for providing separation of different +GPU clients, which is achieved by GPU contexts with a separate page table per +client in hardware. Also, it serves interrupts and informs the clients, +respectively the 3D applications, about progress so a client can submit the +next rendering request. For Intel Xe, there are only two changes within this +low level ISA. First, the interrupt handling registers have been improved. +It has become easier to distinguish, for example, between a display-engine +interrupt and a rendering interrupt. Since graphics cards can have many +interrupt causes, this is a useful and welcome change. Second, it is now +possible to schedule 16 instead of 4 jobs onto the GPU. While we don't take +advantage of this feature yet - we schedule one job at a time - this may come +in handy for use cases like 3D compositing. Additionally, the multiplexer has +to provide information about slices, subslices, and EUs (Execution Units) to +Mesa clients. + + +Stability and resource improvements +=================================== + +Resources need to be traded on Genode, and it is essential that the GPU +multiplexer does not pay for memory allocations or capability upgrades from +its own budget. The client has to donate these resources beforehand. +If this rule is violated, the multiplexer might run out of budget and stall +all clients. Because 3D applications can require a huge amount of resources, +this has been a challenging topic during the last release cycle, and we are +glad to announce that even sophisticated workloads are now running well on +Genode. There is still room for improvement, but the current situation is +already reassuring. Stability-wise, we have tested the updated 3D stack with +various workloads (games, browsers, VirtualBox6-3D) and did fix all issues +that we came across. + + +Base framework and OS-level infrastructure +########################################## + +Base API changes +================ + +New 'Dictionary' utility +------------------------ + +Throughout the Genode code base, there are several places where objects are +accessed by using a name as key. To avoid the repeated manual crafting of such +data structures, we introduced a basic 'Dictionary' data structure located at +_base/include/util/dictionary.h_. + +It follows the patterns of the existing 'Id_space' and 'Registry'. That is, +elements are automatically added to the dictionary at construction time, +respectively removed at destruction time. There exists a 'with_element' method +for applying a functor to one element by specifying a name as key, and a +'with_any_element' method that can be used to destruct all dictionary items. + + +Tightening the 'Xml_node' interface +----------------------------------- + +The former 'with_sub_node' method has been renamed to 'with_optional_sub_node' +to better reflect the intention of the caller. If no sub node of the specified +type exists, the specified functor is not executed. + +Use cases where a sub node is mandatory are best covered by the new +'with_sub_node' method that takes two functors as arguments, one called with +the matching sub node, and one that is called if no such sub node exists. + + +NIC router +========== + +The NIC router now generates reports triggered by internal events +(re-configuration, link state change, etc.) asynchronously. This has the +benefit that the potentially expensive report update does not delay the event +processing that triggered the update and that a report is guaranteed to reflect +a consistent state of the router's internals. + +Furthermore, if the '' attribute 'link_state_triggers' is set, the +router now updates the report also whenever a network session gets constructed +or destructed. This is definitely necessary with sessions whose link state is +"up" because we should consider a non-existent session to be "down". However, +in real-world scenarios, a subscriber might want to know about the +construction and destruction of sessions that are "down" as well because one +has to be able to synchronize the lifetime of local objects that keep track of +the link states. + +Besides the polishing of the report functionality, there are some improvements +related to the DHCP processing in the router. First, the router is now robust +against invalid DNS addresses in DHCP ACK packets. Next, the DHCP client +doesn't produce oversized Ethernet packets anymore. This is important in +networks with a low bandwidth. Then, the link state of a session that is bound +to the state of another domain via the '' attribute +'dns_config_from' is now correctly synchronized to whether that domain has an +IP configuration or not. And, last but not least, the DHCP server now accepts +the optimized startup sequence of clients like Debian that store their lease +persistently and directly try re-requesting it on boot-up (no DHCP DISCOVER). +These last two changes both prevent DHCP re-attempts that could cause a +significantly delayed network boot-up at applications behind the router. + + +Improved support for time-multiplexed GPIO pins +=============================================== + +Prompted by the need to enable a bit-banging I2C driver on the PinePhone, +we extended Genode's pin-driver framework introduced in version +[https://genode.org/documentation/release-notes/21.11#Pin_I_O_session_interfaces - 21.11] +with support for the time-multiplexed operation of a pin as output or input. + +To operate a pin in both directions, a driver obtains both a pin-state and a +pin-control session for the same pin. The pin-state session can be used to +sense the current pin state. The control session allows the client to set the +pin to high or low (using the 'state' method), or to set it to high-impedance +via the 'yield' method. Once switched to high-impedance, the pin can be used +as input. + + +Libraries and applications +########################## + +Emerging Sculpt OS variant for the PinePhone +============================================ + +Genode on the PinePhone has come a long way, most of which is covered by the +[https://genode.org/documentation/genode-platforms-22-05.pdf - Genode Platforms] +document. Device-driver work accounts for the majority of the effort, which is +nicely wrapped up with the current release as described in +Section [PinePhone drivers for audio, camera, and power control]. +With the fundamental device drivers for the PinePhone covered, we can now turn +our attention to system-integration work, ultimately raising the question of +how a Genode-based phone should best present itself to the user. + +[image sculpt_pinephone_22_11] + The forthcoming phone variant of the user interface of Sculpt OS. + +We take this question as an opportunity for exploration. Similarly to +how the so-called Leitzentrale of [https://genode.org/download/sculpt - Sculpt OS] +provides the user with an administrative view on the system that is separate +from the user-defined desktop runtime, we pursued the division of the phone's +UI into two faces that can be toggled with a simple touch gesture. The first +one accommodates the role of the device as a fixed-function appliance similar +to the functionality of a feature phone whereas the second one can be shaped +entirely by the user. The screenshots above give a glimpse of the user +interface of the appliance side. It covers low-level device parameters, voice +calls, establishing network connectivity, and the installation and management +of the software running on the user-defined side. One can see several cues +from Sculpt OS such as the component graph. + +The clear-cut separation of the two roles of the device opens up new ways to +leverage Genode's component architecture. For example, observing that the +appliance role needs only a subset of components, we can orchestrate the +startup of the system such that those components are started first. This way, +the device's basic functions like voice calls become available in under 7 +seconds when powering-on the device. + +Regarding the built-in feature set, we implemented the fundamental device +functions that everyone takes for granted, like displaying the battery state, +triggering the charging when a charger gets connected, controlling the +brightness of the display, or powering down the device. + +The phone variant of Sculpt OS evolves in the +[https://github.com/nfeske/genode-allwinner - genode-allwinner] repository, +specifically within the _sculpt/_ and _src/app/phone_manager/_ directories. +It can be built via the following command: + +! build/arm_v8a$ make run/sculpt KERNEL=hw BOARD=pinephone SCULPT=phone + +For loading the system on the PinePhone, please follow the instructions given +in the following article. + +:Booting Genode on the PinePhone: + + [https://genodians.org/nfeske/2021-09-20-pine-fun-pinephone-boot] + +Note that the current version is still at a rather developer-focused stage. +To avoid testimonies of a prematurely released version, we decided to postpone +the release of a ready-to-use image until the feature set generally expected +from a phone is complete and well tested. + + +ARM virtual machine monitor +=========================== + +The hardware-assisted virtual machine monitor (VMM) for ARM developed for +Genode is part of the framework since release +[https://genode.org/documentation/release-notes/15.02#Virtualization_on_ARM - 15.02]. +Over the years, it got extended to support recent ARMv8 hardware, VirtIO +device models for console, network, block, and so on. Nevertheless, the given +device models, memory dimensions, and Linux specifics like initramfs size +remained hard-coded within the VMM component, and not easily configurable. + +Now, the VMM accepts a configuration that enables one to define various +aspects of the virtual machine and guest OS. The VMM is still focused on Linux +OS guests though. Formerly, a pre-compiled flattened device-tree binary (DTB) +was used by the VMM to boot the Linux guest. The new version of the VMM +generates the DTB based on its own configuration. + +An example configuration looks like the following: + +! +! +! +! +! + +The RAM size and CPU count attributes are mandatory. All other attributes are +optional and use default values. However, it is noteworthy that you should use +the correct values for the CPU type and the Generic Interrupt Controller (GIC) +version that matches your underlying hardware. Due to the usage of +hardware-dependent virtualization extensions, the VMM and guest OS should see +the correct hardware description for CPU and interrupt controller. + + +Seoul VMM +========= + +The Seoul/Vancouver VMM - introduced to Genode with release 11.11 - is an +x86 based VMM which runs on Genode@NOVA, Genode@seL4, and Genode@Fiasco.OC on +Intel and on AMD hardware. It is used with 32-bit Linux VMs typically. + +Over the last and this year, the VMM got VirtIO support with the goal to +improve the usability when used day-to-day, e.g., on Sculpt OS. Given the +observation that most Linux guests come readily (or easy to install) equipped +with VirtIO driver support, we can avoid fiddling with building or integrating +guest drivers manually. The Seoul VMM got extended by implementations for the +VirtIO input device model, VirtIO GPU device model (2D by now) and VirtIO +audio device model. + +With the new input model, absolute mouse positions are supported, so that the +mouse pointer positions in Genode's Sculpt OS and in the guest VM can be kept +in sync. Beforehand, it was hardly possible when solely using the PS/2 model +using relative motion vectors. +With the new 2D GPU model, the mouse pointer shape of the guest VM can be +exported and shown by Genode's GUI multiplexer instead of the native mouse +pointer, which improves the visual impression and avoids confusion. +Additionally, with the new GPU model, resizeable and arbitrary resolution +dimension are possible, which was not feasible with the former VGA/VESA model. +The overall painting overhead is more manageable since partial updates are +supported by the device model. +The VirtIO audio model enables playback of music when streaming & surfing in +the VM, which was beforehand not possible because no audio model was +available. The new VirtIO models of the Seoul VMM were finally mapped to +Genode's GUI, input and audio-out session interfaces. + +Combined, the new device models improve the overall usability when using Seoul +on Sculpt OS. Several packages of alex-ab's depot are available to get +started, ranging from a full on target Debian installation over pre-packed and +ready to use VMs to up-to-date Firefox and Thunderbird VMs based on Tiny Core +Linux. Whereas the Firefox VM is entirely disposable - as mentioned in +[https://genodians.org/alex-ab/2019-03-06-disposal-browser-vm] - +the Thunderbird VM relies on persistent storage. + + +Device drivers +############## + +Uniform use of new platform-driver interface +============================================ + +In release +[https://genode.org/documentation/release-notes/22.02#Platform_driver - 22.02], +Genode's generic platform API for all architectures got introduced and the +x86-specific platform API got deprecated. However, at that point, all +x86-based device drivers still used the deprecated API and the deprecated +platform driver. With this release, all device drivers are now reworked to use +the generic platform API, and driver. The deprecated platform driver and API +have been removed. + +To make all previous scenarios work again, several changes were necessary. The +changes - especially concerning the _pci_decode_ and _platform_drv_ +components - are described in the following. + +PCI decoder +----------- + +The PCI decoder, introduced in release +[https://genode.org/documentation/release-notes/22.05#Platform_driver - 22.05], +consumes ACPI information delivered by the ACPI driver and additional platform +information from the core component. It uses this information to find and scan +PCI buses for devices and their capabilities. Finally, it creates a report +about all PCI devices found. + +While using more and more device drivers with the generic platform driver and +PCI decoder, we realized that on some platforms, not all PCI bridges are +necessarily enabled, which leaves the devices behind such a bridge unusable. +This is now fixed by enabling all PCI bridges. + +The information about reserved memory regions for PCI devices is already used +in the boot process, e.g., memory for video graphic cards is discovered by the +ACPI driver. However, the PCI decoder did not yet offer this information in +its devices report. Therefore, the platform driver did not know about the +reserved memory, and could not set up an IOMMU appropriately. From now on, +the PCI decoder reports such memory regions as follows. + +! +! ... +! +! + +The PCI memory _Base Address Registers_ (BARs) provide information about +pre-fetchable memory. This information is now additionally exported by the PCI +decoder and can be used by the platform driver (see the next section for +details). The information is presented in the following form: + +! +! ... +! +! + +Currently, the PCI decoder decides about the type of interrupt which can be +used for a PCI device. The background is that several kernels, like OKL4, +do not support the use of _Message-Signaled-Interrupts_ (MSI) or MSI-X. Older +kernels, like Pistachio, do not even support the I/O _Advanced Programmable_ +_Interrupt Controller_ (IOAPIC), and are even more limited regarding available +interrupt pins. +On kernels that support all kinds of interrupts, devices with support for MSI +or MSI-X were reported to prefer MSI-X. However, in rare cases we observed +problems with the WiFi driver on MSI-X capable hardware. Therefore, we switch +the priority of reporting MSI over MSI-X if both are available. +In addition, we experienced problems with some Intel HDAUDIO cards and MSIs. +Therefore, we do not report the MSI capability on those devices for the +time being. + + +Platform driver +--------------- + +The generic platform driver got re-worked to support the newly provided +information from the PCI decoder. The given reserved memory regions of a +device are used to add corresponding entries in the IOMMU. + +The new "prefetchable" attribute for corresponding I/O memory regions - +typically only "stolen memory" of the video graphics card - is used to decide +when I/O memory can be mapped as write-combined into the address space of the +client. Now that the platform driver decides for which I/O memory these +special paging attributes are sensible to use, the actual driver no longer +needs to distinguish special paging attributes for I/O memory. +Therefore, we removed those details from the 'io_mem' call. + +PCI devices on x86 without MSI or MSI-X support may still share the same +interrupt line. To make the generic platform driver functional on these +platforms, we had to add shared interrupt support. When the platform driver +receives its devices report, it iterates over all devices and their interrupt +resources, and detects any shared interrupts. For those interrupts, the +platform driver provides a custom IRQ service, thereby realizing the sharing. +For all other interrupts, it hands out the IRQ capability as obtained from +core directly. + +The generic platform driver can now set up MSI-X within the PCI configuration +space of a device, if the devices ROM instructs it to do so. + +The ability to power and reset PCI devices was also missing in the generic +platform driver so far. We caught up on implementing this feature. + +Several PCI enablement quirks are needed for correctly running devices and +drivers. Especially the hand-off of devices in between BIOS/UEFI and OS are an +example for this. We encountered problems when doing this too late. Therefore, +we moved the PCI quirks from the moment of first usage to the startup of the +platform driver. Moreover, PCI quirks for EHCI and HDAUDIO were added. + +VirtIO PCI devices hide several important information about their queues inside +the PCI configuration space. Now that we do not provide direct access to the +PCI configuration space to device drivers, the platform driver needs to +identify VirtIO devices, and provide the necessary information via the devices +ROM to the driver. It does so in the following way: + +! +! +! ... +! +! +! + +Sometimes a device driver is needed to set up a device but doesn't necessarily +need to stay present while the device is active. The PCIe host controller for +the i.MX 8MQ SoC described in +Section [New PCI and network drivers for NXP i.MX] is such an example. +To be able to destruct a platform resp. single device session at the platform +driver without automatically powering it off or resetting it, we introduced +the "leave_operational" attribute. As the name suggests, it leaves a device +untouched when its session gets closed. The attribute is part of the policy +node for the client within the platform driver's configuration. + +Platform driver for PC hardware +------------------------------- + +The vanished and deprecated x86-specific platform driver was able to reset a +machine via I/O port access. It did so upon observing the 'state' attribute of +the system ROM having the value "reset". +This feature is mainly used within Sculpt OS. To not lose this ability, +a platform driver specific to PCs is now part of the _repos/pc_ repository. +It shares all code and semantics with the generic platform driver, but adds +this single functionality. + +Platform API clients +-------------------- + +All remaining x86-centered device drivers got reworked to use the generic +platform API and its helper utilities in _platform_session/device.h_ and +_platform_session/dma_buffer.h_. + +The lx_kit and lx_emul layers within the _repos/dde_linux_ repository now use +one and the same generic layer too. While reworking these libraries, we +addressed a performance penalty in the interrupt handling. The multiple +opening and closing of interrupt sessions is now eliminated. +Moreover, we removed the legacy_pc_usb_host_drv from _repos/dde_linux_. + +All run-scripts and packages were revised to use the new drivers. + + +PinePhone drivers for audio, camera, and power control +====================================================== + +Over the past 18 months, we have steadily expanded the base of device drivers +for the PinePhone, initially addressing the +[https://genodians.org/nfeske/2021-12-21-pine-fun-display - display] and +[https://genodians.org/nfeske/2022-03-16-pine-fun-touchscreen - touchscreen], +later covering the +[https://genode.org/documentation/release-notes/22.02#PinePhone_modem_access - modem], +[https://genode.org/documentation/release-notes/22.05#Custom_system-control_processor__SCP__firmware - system control], +[https://genode.org/documentation/release-notes/22.08#GPU_and_Mesa_driver_for_Mali-400 - GPU], and +[https://genode.org/documentation/release-notes/22.08#SD-card_driver_for_the_PinePhone - SD-card]. +With the current release, we wrap up this line of work with drivers for +audio, camera, and power control. + +As a prerequisite step for enabling the camera, we changed the version of the +Linux kernel that we use as donor of the driver code. Up to now, we relied on +the vanilla Linux kernel for the Allwinner SoC. However, the camera support +still resides on [https://xnux.eu - Ondrej Jirman's] custom kernel +(orange-pi-5.14), which is apparently the kernel of choice for most Linux +distributions for the PinePhone. We follow suit. + + +Audio +----- + +The added audio support consists of two separate components, namely an +audio-control driver and audio in/out driver. The former controls the audio +routing and mixing on the hardware level. It is responsible to route the mic +to the modem during voice call, control the gain, or enable/disable the +speaker. The privacy-sensitive audio-control driver is meant to be part of the +base system of Sculpt. It operates according to its configuration, which can +be updated dynamically. + +Volumes can be configured by nodes within the '' node using a volume +attribute (range 0-100) where 0 implies turning off the input or output +device. Supported nodes are '', '', and ''. +Furthermore, a '' node can be used to switch the audio path between the +modem and the ARM application processor (SoC). Its 'target' attribute can be +set to either "soc" (default) or "modem". The "soc" mode implicitly sets the +codec's sample rate to 44.1 KHz whereas "modem" mode sets the sample rate to +48 KHz. This distinction is required because the modem is compatible with 8 +KHz only. The modem's 8 KHz can be cleanly converted to 48 KHz. + +In contrast to the audio-control driver, the audio in/out driver is concerned +with streaming PCM audio data to/from the ARM application processor. It allows +audio applications hosted in the user-defined runtime of Sculpt OS to record +and play audio via Genode's audio-in and audio-out session interfaces. +The combination of both drivers can be exercised via the +[https://github.com/genodelabs/genode-allwinner/blob/master/run/audio_pinephone.run - audio_pinephone.run] +script. + + +Power control +------------- + +The new power-control driver is based on our custom firmware for the A64's +system-control processor (SCP) in combination with Genode's dedicated +scp-session interface that allows Genode components to interact with the SCP. + +To properly arbitrate the access to the power-management IC (PMIC) between the +SCP firmware and the ARM application processor, the PMIC driver has been moved +entirely to the SCP side. This way, both the SCP firmware and Genode-based SCP +clients become able to safely access the PMIC without stepping on each other's +toes. In particular, the platform driver acts as an SCP client to toggle power +controls. Since the platform driver now depends on the SCP, we co-located the +formerly separate SCP driver component with the platform driver. + +Built upon this infrastructure, a new power driver exercises control over +several low-level aspects of the PinePhone hardware such as: + +* Platform reboot (via the PMIC), +* Powering down the system (via the PMIC), +* Switching between the power profiles "performance" and "economic", + which clock the ARM CPU at 1296 MHz and 816 MHz respectively, +* Reporting the remaining battery capacity, power draw, or charge current, +* Triggering the charging when connecting a charger, and +* Adjusting the backlight brightness. + +Besides being integrated in Sculpt OS, the driver can be exercised in +isolation using the +[https://github.com/genodelabs/genode-allwinner/blob/master/run/power_pinephone.run - power_pinephone.run] +script. + + +Camera +------ + +The added camera driver component consists of a port of the Linux SUN6I-CSI as +well as OV5640 and GC2145 drivers. It renders the captured camera image data +into a GUI session according to the following configuration attributes. + +The 'camera' attribute selects the camera. Supported values as "front" and +"rear". The 'width' and 'height' attributes select the horizontal and vertical +resolution. Valid configurations are 640x480 as well as 1280x720. The 'fps' +attribute selects the capture rate of the camera. Valid values are "15" and +"30". The 'format' attribute selects the capture format. The only valid value +is "yuv", which selects YUV420. The 'convert' attribute specifies if the +captured image data is converted to the pixel format suitable for the GUI +display. Default is "true". The 'rotate' attribute specifies if the capture +image data is rotated counter-clockwise and flipped. Default is 'true'. + +The integration of the driver is exemplified by the +[https://github.com/genodelabs/genode-allwinner/blob/master/run/camera_pinephone.run - camera_pinephone.run] script. +The test scenario displays the camera image on the framebuffer. It repeatedly +switches between front and rear camera. + + +New PCI and network drivers for NXP i.MX +======================================== + +PCIe host controller for i.MX 8MQ +--------------------------------- + +The i.MX 8MQ SoC includes two PCI-express host controllers. The MNT Reform 2 +laptop for example exposes both via one M.2 and one miniPCIe socket, e.g., to +drive an NVMe card and a WiFi card. In contrast to x86-based PCs, those PCIe +controllers are not set up by boot-firmware like BIOS or UEFI, but need to be +driven by the OS first. Therefore, this release contains a new PCIe driver for +the mentioned SoC. This driver does not provide a special API. It uses the +platform driver to obtain the device resources of the PCIe controller, and +enables and configures it appropriately. It then parses the PCI configuration +space of the device behind the controller, which in fact acts as PCI host +bridge. The collected device and PCI information is then exposed via the +report service analogously to the PCI decode component available for x86. +Finally, the platform driver resp. another incarnation of the platform driver +can consume this report as devices ROM, and provide the device resources to a +driver of the PCI device. + +In practice, we have tested the PCIe host controller driver in combination +with an NVMe card used in the MNT Reform 2 laptop only. Moreover, it got +integrated in Sculpt OS for the MNT Reform 2. Therefore, we had to add an +i.MX 8MQ specific driver manager. This management component is able to check +for the availability of an NVMe device, controls the driver's lifetime, and +assembles a block-device report that covers both SD-card and NVMe devices. + + +FEC Network driver +------------------ + +There is long-standing support for the _Freescale Ethernet Controller_ (FEC) +within Genode available, supporting a broad range of SoCs from i.MX 53 up to +i.MX 8. +But the existing driver port taken from Linux 4.16.3 was running shakily on +the i.MX 8MQ SoC and the i.MX 6 Sabrelite board. Instead of trying to +investigate potentially violated semantics in the legacy DDE Linux emulation +code, we ported the Linux device driver for FEC from scratch. Thereby, we've +used the recent DDE Linux porting approach, first described in the +[https://genode.org/documentation/release-notes/21.08#Linux-device-driver_environment_re-imagined - 21.08] +release. +The new driver is based on the vanilla Linux kernel 5.11 plus the MNT Reform 2 +patches provided by Lukas Hartmann, which we already use for other drivers +available in the genode-imx repository. + +To enable the driver to work correctly, it needs information about its clock +frequencies. Therefore, we have extended the platform driver for i.MX 53, and +introduced new rudimentary platform drivers specific to i.MX 6 and 7, which +expose the needed clock frequencies. + + +USB-C on i.MX 8MQ EVK +--------------------- + +The USB host controller driver for the i.MX 8MQ EVK board did not enable the +second USB host controller yet, which is connected to the USB-C socket of the +board. Now this host controller gets driven too. + + +Intel graphics +============== + +The Intel display driver was enabled to run on Intel Alderlake graphics PCs, +tested on the 12th Gen +[https://frame.work/de/en/products/laptop-12-gen-intel - Framework Laptop]. +Furthermore, the driver now supports 4K displays, tested specifically on Dell +Ultrasharp and LG 27MU67 hardware. Additionally, the driver may now be +configured to set up an upper resolution bound to avoid out-of-service +exceptions due to unexpectedly high memory needs. This feature is used by +default on Sculpt to limit resolutions to WQHD aka 1440p aka 2560x1440 pixels +and can be changed in _repos/gems/sculpt/fb_drv/default_. + + +Audio driver updated to OpenBSD 7.1 +=================================== + +We updated the audio-driver component to OpenBSD version 7.1 that brings in +support for playback on more recent 12th Gen Intel machines. Besides the +update, we remedied a long-standing shortcoming when handling multiple +HD-Audio devices and removed the support for old audio devices. + +The component contained a simple check to exclude known non-working devices +but depending on the machine's configuration, this check was incomplete. Rather +than extending the check, we took a step back and changed the probing +behavior of the component: + +![init -> audio_drv] azalia0 [8086:160c] +![init -> audio_drv] : +![init -> audio_drv] azalia0: no supported codecs +![init -> audio_drv] azalia1 [8086:9ca0] +![init -> audio_drv] : +![init -> audio_drv] azalia1: codecs: Realtek ALC292 +![init -> audio_drv] audio0 at azalia1 + +It now checks all available devices and picks the first one it can use. This +comes in handy in configurations where the virtual PCI-bus is populated with +all audio devices found in a machine and some of them contain unsupported +codecs as, among others, found on GPUs. + +Furthermore, we decided to remove the _eap_ and _auich_ drivers as these +drivers rely on I/O port access, which still had to be enabled in the +component after the switch to the new platform driver and due to being of +minor importance in daily use. The first one was mainly used to initially +develop the component and later on for testing in QEMU. The second one on the +other hand was merely enabled to provide a shot at getting audio in VirtualBox +VMs where the component did not work with the HDA device model at the time. + + +Improved ACPICA driver +====================== + +The ACPICA driver got improved support for Thinkpad notebooks to report ACPI +events and in particular battery state changes. The frequency of checking of +state changes, which are not triggered by an ACPI event, can now be configured +explicitly, which is documented in the README file of the component. + +Additionally, the ACPICA component got extended to support ACPI suspend & +resume functionality. On the one hand the component can be configured to +determine and report the supported ACPI sleep states (S1-S5) of a PC machine. +On the other hand, the component can now react on 'system' ROM changes and +participate on sleep state preparation and the subsequent wakeup procedure +using the ACPICA library, e.g., AcpiEnterSleepStatePrep, +AcpiLeaveSleepStatePrep and AcpiLeaveSleepState. + + +Wireless-networking improvements +================================ + +In the process of enabling the Intel AX211 WiFi card, DDE-Linux and the WiFi +driver were enhanced to support loading PNVM firmware files. Ultimately, a +[https://github.com/QubesOS/qubes-linux-kernel/commit/5fcfe0f19ed5ff2bd3514644afce0af642c326c6 - workaround] +from QubesOS was needed to make the card work, highlighting shared challenges +that both our projects face when using Linux drivers in unconventional ways to +improve system security. + + +Platforms +######### + +Low-level mechanism for suspend/resume on PC platforms +====================================================== + +On modern PC platforms, suspend and resume is realized by using a mechanism +provided by ACPI. The Advanced Configuration and Power Interface defines +(besides many other things) several global states (Gx) and six sleep states (Sx) +an operating system (OS) can choose. Oversimplified, the S0 state is the +normal working state, S1-S2 are light sleeping states, S3 is known as +"suspend to RAM" state, S4 is called "suspend to disk" and S5 is mostly "off". +See [https://en.wikipedia.org/wiki/ACPI#OSPM_responsibilities] for a basic +overview and further pointers for reading. + +The supported sleep states vary between PCs, some of which do not even support +all states. An operating system has to look up and determine the supported Sx +states, which are part of ACPI tables and ACPI AML code. Beginning with this +Genode release, we can use the ACPICA driver to lookup the supported Sx +states. The sleep states themselves are represented as two values (TYP_SLPa +and TYP_SLPb in ACPI specification) and are reported by the ACPICA driver. + +In order to trigger/program the intended sleep state, an OS like Genode + used +kernel has to look up and set up several ACPI tables, e.g., FACS & FADT. Via +the tables, the OS deposits a wakeup vector, which is called by the UEFI +firmware on wakeup. Before actually going to sleep, the OS has to take care to +flush all kinds of hardware cached state either to memory or persistence +storage, depending on the Sx state. + +With this release, we added principal support for S3 "suspend to RAM" in +Genode using the NOVA kernel. The kernel now supports a privileged suspend +syscall, which is solely available to Genode's core roottask. The invocation +is triggered and guarded by Genode's 'Pd::managing_system' RPC function, which +takes both TYP_SLPa and TYP_SLPb values as parameters representing the +intended Sx state. On invocation, Genode's core will check that the component +holds Genode's managing-system capability. On success, the suspend syscall of +the NOVA kernel is invoked and will lead to holding all CPUs, depositing the +wakeup vector in the ACPI tables, flushing cached state of Genode's components +to memory, like CPU registers, FPU state, IO-APIC state and virtualization +state of Intel' VMX or AMD's SVM. Finally, both TYP_SLP values will be used to +trigger the sleep state. + +On ACPI wakeup, the UEFI/BIOS firmware wakes up the NOVA kernel via the +deposited wakeup vector. The kernel re-initializes the CPU and wakes up all +other CPUs. Finally, control will be transferred to Genode's roottask (core), +which can thereby return from the 'Pd::managing_system' RPC call. + +Before and after the actual suspend and resume, the ACPICA driver should +be used to run ACPI AML methods to prepare and post-process the system state +change, which may affect the success of the Sx state transfer depending on the +used PC platform. Additionally, after resume, all hardware and their drivers +must be considered to be re-initialized. The re-initialization and re-starting +of drivers and hardware, e.g., PCI, is not finished currently. + +An early prototype for exercising this scenario is available in the form of +the _acpi_suspend.run_ script in the _libports_ repository. This test scenario +periodically suspends and resumes the hardware and also restarts the used +display driver. The low level ACPI suspend and resume can be observed to work +quite reliable, which we could validate across several generations of Intel +notebooks and some AMD desktop machines. However, the re-starting of the +display driver is not always reliable. Restarting the Intel display driver +worked notably well on older Thinkpad notebooks, e.g., X201 and T420. + +Note that the suspend/resume feature is still work in progress. The next +potential work items are the addition of suspend/resume support to the base-hw +kernel, ways to power-off and power-on (PCI) hardware, e.g.,via the new +platform driver, and re-initializing and/or re-starting drivers. Additionally, +a convenient way to debug resume issues is desired when no serial output is +working anymore after resume. + + +Base-HW microkernel +=================== + +The base-hw kernel, which was specifically developed for Genode, did not +provide the use of _Message-Signaled-Interrupts_ (MSI), and MSI-X yet. With +this release, x86 architectural support for MSI and MSI-X entered the base-hw +kernel. The usage of MSI or legacy interrupts is transparent to the user. It +gets determined in the interplay of the PCI decode component, platform driver, +and core. + + +NOVA microhypervisor +==================== + +Besides the added ACPI suspend/resume support described in +Section [Low-level mechanism for suspend/resume on PC platforms], the kernel +received principal support to run on more than 32 CPUs. By default, Genode's +and the kernel's CPU limit is set to 64, configurable by the constants +MAX_SUPPORTED_CPUS in Genode's core respectively NUM_CPU in the kernel. +In our tests, up to 250 CPUs were usable in Qemu. + + +Build system and tools +###################### + +Streamlined building of libraries +================================= + +The release adds special handling for 'lib/' arguments to the build +system, which supersedes the former 'LIB=' mechanism. Whereas the old +mechanism was limited to a single library, the new convention allows multiple +library arguments, similar to regular targets. + +The change brings two immediate benefits. First, the streamlining of library +and target arguments allows for the building of libraries via the 'build' +command of the run tool. Second, it alleviates the need for pseudo _target.mk_ +files for building shared libraries that have no direct dependencies, in +particular VFS plugins. + +Note that _target.mk_ files located under _src/lib/_ are no longer reachable. +Therefore, all run scripts that used to trigger the build of a shared library +via a pseudo target must be adapted. E.g., 'build lib/vfs/tap' must be +replaced by 'build lib/vfs_tap'. + +The former 'LIB=' option is no longer supported. + + +Boot-loading over HTTP +====================== + +The standard network-boot approach for x86 at Genode Labs has been a +combination of the PC-integrated Preboot Execution Environment (PXE), the +Pulsar boot loader, and the TFTP protocol for years. Because Pulsar is tied +to legacy BIOS interfaces, UEFI-only hardware demands for alternatives. iPXE +is a field-tested, UEFI-compatible alternative that is already supported in +Genode's run tool via _load/ipxe_. + +One of the prominent features of iPXE is the support for additional network +(boot) protocols beyond TFTP with HTTP as a tempting option to improve boot +performance. This release enhances the _load/ipxe_ run module to optionally +configure and spawn the lightweight HTTP server _lighttpd_ to serve the boot +image to iPXE using the following declarations in _etc/build.conf_. + +! RUN_OPT += --include load/ipxe +! RUN_OPT += --load-ipxe-base-dir /tftpboot +! RUN_OPT += --load-ipxe-boot-dir /ipxe +! RUN_OPT += --load-ipxe-lighttpd +! RUN_OPT += --load-ipxe-lighttpd-port 2209 + +The HTTP server is run only while the run tool is executed, killed on exit, +and limited to serve the contents of the test-specific directory under +_var/run/_ in your build directory. Your iPXE boot loader should be configured +to chain the automatically generated _boot.cfg_ file as follows. + +! #!ipxe +! chain http://:2209/boot.cfg + +For more details, please refer to the dedicated Genodians.org article. + +:Getting Fujitsu U7411 up and running - Network Boot: + + [https://genodians.org/chelmuth/2022-11-24-u7411-up-and-running] + + +Configurable Intel HWP mode +=========================== + +We updated our version of the Bender chain-boot loader to be configurable +regarding the mode in which to run Intel's Hardware P-States (HWP). When +running Genode on NOVA, the HWP mode can now be controlled via the new run +option '--bender-intel-hwp-mode'. The option responds to the values 'off', +'performance', 'balanced', and 'power_saving'. The default value is +'performance' in order to stay backwards compatible. On kernels other than +NOVA, HWP remains turned off in general. diff --git a/doc/release_notes/23-02.txt b/doc/release_notes/23-02.txt new file mode 100644 index 0000000000..8d655639cb --- /dev/null +++ b/doc/release_notes/23-02.txt @@ -0,0 +1,887 @@ + + + =============================================== + Release notes for the Genode OS Framework 23.02 + =============================================== + + Genode Labs + + + +With Genode's February release, almost everything goes +[https://genode.org/about/road-map - according to plan]. +As envisioned on our road map, it features the first ready-to-install +system image of Sculpt OS for the PinePhone, which is not merely a re-targeted +version of the PC version but comes with a novel user interface, a new +mechanism for rapidly switching between different application scenarios, and +system-update functionality. +Section [First system image of mobile Sculpt OS (PinePhone)] gives an +overview and further links about running Genode on your PinePhone. + +While enabling substantial application workloads on devices as constrained as +the PinePhone, we engaged in holistic performance optimizations, ranging from +kernel scheduling (Section [Base-HW microkernel]), over the framework's VFS +infrastructure (Section [VFS optimization and simplification]), to the +interfacing of GPU drivers (Section [GPU performance optimizations]). + +For stationary ARM-based platforms like the MNT-Reform laptop, +interactive graphical virtual machines have become available now, which +brings us close to mirror the experience of the PC version of Sculpt OS on +such devices (Section [Interactive graphical VMs on ARM]). This development +is accompanied by several device-driver improvements for NXP's i.MX family. + +For embedded devices based on Xilinx Zynq, the release introduces custom +FPGA fabric for implementing DMA protection that is normally not covered by +Zynq SoCs. This line of work - as outlined in +Section [Custom IP block for DMA protection on AMD/Xilinx Zynq] - exemplifies +how well Genode and reconfigurable hardware can go hand in hand. + +Also, PC platforms got their share of attention, benefiting from the +new distinction between Intel's P&E cores, or the principle support of +suspend/resume on both NOVA and Genode's custom base-hw microkernel. + +When it comes to running applications on top of Genode, the release brings +good news as well. Our custom Goa tool for streamlining +application-development work flows received the ability to largely automate +the porting and packaging of 3rd-party libraries using CMake +(Section [Build system and tools]). + + +First system image of mobile Sculpt OS (PinePhone) +################################################## + +Just in time for our +[https://fosdem.org/2023/schedule/event/genode_on_the_pinephone/ - public presentation] +of Genode on the PinePhone at FOSDEM in the beginning of February, +we published a first ready-to-use system image: + +:First system image of mobile Sculpt OS: + + [https://genodians.org/nfeske/2023-02-01-mobile-sculpt] + +It features a +[https://genodians.org/nfeske/2023-01-05-mobile-user-interface - custom user interface], +voice calls and mobile-data connectivity, on-target software installation and +system update, device controls (battery, brightness, volume, mic, reset, +shutdown), and a variety of installable software. Among the installable +applications, there is the Chromium-based Morph web browser, an OpenGL demo +using the GPU, tests for the camera and microphone, as well as a light-weight +Unix-like system shell. + +The underpinnings of the Genode system image for the PinePhone are nearly +identical to Sculpt OS on the PC. However, besides the new user interface +specifically designed for the touch screen of the phone, two noteworthy +differences set it apart from the regular version of Sculpt OS. + +[image pinephone_presets] + +First, the phone variant allows the user to rapidly switch between different +runtime configurations, called presets. This way, the limited resources of the +phone can be accounted and fully leveraged for each preset individually, while +making the system extremely versatile. The loading of a preset can be imagined +as the boot into a separate operating system, but it takes only a fraction of +a second. The structure of the running system is made fully transparent to the +user by the component graph known from Sculpt OS. + +[image pinephone_scenarios] + The variety of presets includes the Morph browser, GLMark2, a system shell, + a simple oscilloscope, and camera test. + +Second, the system is equipped with an on-target system update mechanism that +allows the user to install new versions of the system image when they become +available. System updates are secured by cryptographic signatures. The +mechanism does not only allow for updating the system but also for the +rollback to any previously downloaded version. This way, the user can try +out a new version while being able to fall back to the previous one in the +case of a regression. This reinforces the end user's ultimate control. + +[image pinephone_update] + + +Interactive graphical VMs on ARM +################################ + +The virtual-machine monitor (VMM) using hardware-assisted virtualization on +ARM started as a case study eight years ago for Samsung's Exynos 5250 SoC. +Originally, it supported virtualization of CPU, timer, interrupt-controller, +and a UART-device only. Since then, it received several extensions like +support for 64-bit ARMv8 systems, VirtIO devices for network, console, and +block access. With release 22.11, the VMM's I/O device access, RAM +consumption, and CPU count have come configurable. + +With the current release, we further enhance the VMM for ARM devices to +provide all the means necessary to become a useful virtualization solution for +interactive scenarios. + +[image mnt_interactive_debian_vm] + Sculpt OS running Debian in a virtual machine on the MNT Reform laptop + +Two additional VirtIO device models are available now: A GPU model and one for +input. Both models are mapped to Genode's GUI service under the hood. One can +extend the configuration of the VMM accordingly: + +! +! +! +! ... +! + +For now, only one GPU and one input device can be declared. Both devices get +mapped to the very same GUI service, according to the service routing of the +VMM. + +Caution: the GPU and input model are still in an experimental state, and there +are known corner cases, e.g., when the graphical window size of the VMM gets +changed dynamically. + +Formerly, the VMM always expected an initial RAM file system to be provided as +ROM dataspace, which got loaded together with the Linux kernel into the VM's +memory. Now, it is possible to omit the "initrd_rom" configuration option. +If omitted, no initrd is provided to the Linux guest. + + +Custom IP block for DMA protection on AMD/Xilinx Zynq +##################################################### + +As a continuation of the hardware-software co-design efforts presented in the +[https://genode.org/documentation/release-notes/22.11#Hardware-software_co-design_with_Genode_on_Xilinx_Zynq - previous release], +we turned towards enabling bulk-data transfer between the Zynq's CPU and its +FPGA. In a first step, we built a custom hardware design that implements a DMA +loopback device based on Xilinx' AXI DMA IP. Since we were particularly +interested in testing out the Zynq's accelerator coherency port (ACP), we +implemented two loopback devices: one attached to the ACP and one to the +high-performance (HP) AXI port of the Zynq. In order to test the design in +Genode, we added a port of Xilinx' embeddedsw repository that hosts standalone +driver code for the Xilinx IP cores. Based on this port, we implemented the +xilinx_axidma library as a Genode wrapper in order to simplify development of +custom drivers using Xilinx' AXI DMA IP. A newly written test component takes +throughput measurements for varying transfer sizes. A more detailed account of +this story is published in an +[https://www.hackster.io/johannes-schlatow/using-axi-dma-on-genode-6482d2 - article on hackster.io]. + +Knowing that DMA bypasses any memory protection on the Zynq as it does not +feature an IOMMU, we further spent some development efforts on implementing a +custom IP block, called DMA Guard, for protecting against unintended DMA +transfers from/to the FPGA. The DMA Guard is configured with a limited set of +address ranges for which DMA transfers will be granted. Any out-of-range +transfer will be denied. The configuration of the DMA Guard is conducted by +the Zynq's platform driver based on the allocated DMA buffers. For the time +being, we applied several changes to the platform driver. These modifications +are currently hosted in the genode-zynq repository but are going to find their +way into the generic platform driver for the next release. + +More details about the DMA Guard are covered by the dedicated article: +[https://www.hackster.io/johannes-schlatow/taking-control-over-dma-transactions-on-zynq-with-genode-fd60b6 - Taking control over DMA transactions on Zynq with Genode]. +To follow this line of work, keep watching our +[https://www.hackster.io/genode - hackster.io channel]. + + +Base framework and OS-level infrastructure +########################################## + +VFS optimization and simplification +=================================== + +For regular applications executed on Genode, input and output involves the +virtual file system (VFS). In contrast to traditional monolithic operating +systems (which host the VFS in the kernel) or traditional microkernel-based +operating systems (which host the VFS in a dedicated server component), +Genode's VFS has the form of a library, giving each component an individual +virtual file system. The feature set of the VFS library is not fixed +but extensible by so-called VFS plugins that come in the form of optional +shared libraries. These plugins can implement new file-system types, but also +expose other I/O facilities as pseudo files. For example, TCP/IP stacks like +lwIP and lxIP (IP stack ported from Linux) have the form of VFS plugins. +The extensibility of the VFS gives us extreme flexibility without compromising +Genode's simplicity. + +On the other hand, the pervasiveness of the VFS - being embedded in Genode's C +runtime - puts it on the performance-critical path whenever application I/O is +involved. The ever-growing sophistication of application workloads like +running a Chromium-based web browser on the PinePhone puts merciless pressure +on the VFS, which motivated the following I/O-throughput optimizations. + +Even though the VFS and various VFS plugins work asynchronously, the batching +of I/O operations is not consistently effective across different kernels. It +particularly depends on the kernel's scheduling decision upon the delivery of +asynchronous notifications. Kernels that eagerly switch to the signal receiver +may thereby prevent the batching of consecutive write operations. We could +observe variances of more than an order of magnitude of TCP throughput, +depending on the used kernel. In the worst case, when executing a kernel that +eagerly schedules the recipient of each asynchronous notification, the +application performance is largely dominated by context-switching costs. + +Based on these observations, we concluded that the influence of the kernel's +scheduler should better be mitigated by scheduling asynchronous notifications +less eagerly at the application level. By waking up a remote peer not before +the application stalls for I/O, all scheduled operations would appear at the +remote side as one batch. + +The implementation of this idea required a slight redesign of the VFS, +replacing the former implicit wakeup of remote peers by explicit wakeup +signalling. The wakeup signalling is triggered not before the VFS user settles +down. E.g., for libc-based applications, this is the case when the libc goes +idle, waiting for external I/O. In the case of a busy writer to a non-blocking +file descriptor or socket (e.g., lighttpd), the remote peers are woken up once +a write operation yields an out-count of 0. The deferring of wakeup signals is +accommodated by the new 'Remote_io' mechanism (_vfs/remote_io.h_) that is +designated to be used by all VFS plugins that interact with asynchronous +Genode services for I/O. + +Combined with additional adjustments of I/O buffer sizes - like the request +queue of the file-system session, the TCP send buffer of the lwIP stack, or +the packet buffer of the NIC session - the VFS optimization almost eliminated +the variance of the I/O throughput among the different kernels and generally +improved the performance. On kernels that suffered most from the eager context +switching, netperf +[https://github.com/genodelabs/genode/issues/4697#issuecomment-1342542399 - shows a 10x] +improvement. But even on kernels with more balanced scheduling, the effect is +impressive. + +While we were at it, and since this structural change affected all VFS plugins +and users anyway, we took the opportunity to simplify and modernize other +aspects of the VFS-related code as well. + +In particular, the new interface 'Vfs::Env::User' replaces the former +'Vfs::Io_response_handler'. In contrast to the 'Io_response_handler', which +had to be called on a 'Vfs_handle', the new interface does not require any +specific handle. It is merely meant to prompt the VFS user (like the libc) to +re-attempt stalled I/O operations but it does not provide any immediate hint +about which of the handles have become ready for reading/writing. This +decoupling led to welcome simplifications of asynchronously working VFS +plugins. + +Furthermore, we removed the 'file_size' type from read/write interfaces. The +former C-style pair of (pointer, size) arguments to those operations have been +replaced by 'Byte_range_ptr' and 'Const_byte_range_ptr' argument types, which +make the code safer and easier to follow. Also, the VFS utilities offered by +_os/vfs.h_ benefit from this safety improvement. + + +GPU performance optimizations +============================= + +Session interface changes +------------------------- + +The GPU session interface was originally developed along the first version of +our GPU multiplexer for Intel devices. For this reason, the interface +contained Intel specific nomenclature, like GTT and PPGTT for memory map and +unmap operations. With the introduction of new GPU drivers with different +architectures (e.g., Mali and Vivante), the Intel specifics should have gone +away. With the current Genode release, we streamlined the map and unmap +functions to semantically be more correct on all supported hardware. There are +two map functions now: First, _map_cpu_ which maps GPU graphics memory to be +accessed by the CPU. And second, _map_gpu_ which establishes a mapping of +graphics memory within the GPU. + +Additionally, we removed the concept of buffers (as used by Mesa and Linux +drivers) to manage graphics memory and replaced it by the notion of video +memory (VRAM) where VRAM stands for the actual graphics memory used by a GPU - +may it be dedicated on-card memory or system RAM. The change makes it possible +to separate the graphics-memory management from the buffer management as +required by the Mesa library. + + +Intel graphics +-------------- + +When porting 3D applications using Mesa's OpenGL, we found that Mesa allocates +and frees a lot of small GPU buffer objects (data in GPU memory) during +operation. This is sub optimal for component-based systems because the Mesa +library has to perform an RPC to the GPU multiplexer for each buffer +allocation and for each buffer mapping. As mentioned above, we changed the +session semantics from buffer object to video memory and implemented this +feature within Intel's GPU multiplexer, which now only hands out VRAM. This +made it possible to move the buffer handling completely to the Mesa client +side (libdrm). Libdrm now allocates large chunks of video memory (i.e., 16MB) +and hands out memory for buffer objects from this pool. This brings two +advantages: First, the client-side VRAM pool acts as cache, which reduces the +number of RPCs required for memory management significantly. Second, because +of the larger VRAM allocations (compared to many 4K or 16K allocations before) +fewer capabilities for the actual dataspaces that back the memory are +required. Measurements showed that almost an order of magnitude of +capabilities can be saved at Mesa or the client side this way. + + +Mali graphics +------------- + +The 22.08 release introduced a +[https://genode.org/documentation/release-notes/22.08#GPU_and_Mesa_driver_for_Mali-400 - driver] +for the GPU found in the PinePhone. Since it was merely a rapid prototype, it +was limited to one client at a time, and was normally started and stopped +together with its client. With this release, we remedied these limitations and +enabled support for multiple concurrent clients and also revised our libdrm +backend for Mesa's Lima driver. + +We have not yet explored applying the same VRAM optimizations that are employed +by our Intel graphics stack. One VRAM allocation still correlates to one +buffer-object. + + +More flexible ACPI-event handling +================================= + +The _acpica_ component uses the Intel ACPICA library to parse and interpret +ACPI tables and AML code. One designated feature is the monitoring of several +ACPI event sources including optional reporting of information about state +changes. The supported event sources are: + +* Lid, which can be open or closed +* Smart battery (SB), information about battery parameters (e.g., capacity) + and charging/discharging status +* ACPI fixed events, e.g., power buttons +* AC adapters, which reflect power cable plug/unplug +* Embedded controller (EC), events like Fn-* keys, Lid, AC, SB changes +* Vendor-specific hardware events, e.g., Fujitsu FUJ02E3 key events + +Acpica optionally reports information about state changes. These reports can +be monitored by other components as ROMs. The following configuration +illustrates the feature: + +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! ... +! +! + +One such ACPI monitor component is _acpi_event_ that maps ACPI events to key +events of a requested Event session based on its configuration. This way, ACPI +state changes can be processed like ordinary key press-release events via, for +example, the _event_filter_. The following configuration illustrates how to +map the ACPI event types to key events: + +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! ... +! +! + +In the current release, we replaced the limited list of supported key names by +a general mechanism, which supports the use of all key names declared in +_repos/os/include/input/keycodes.h_. + + +Base API changes +================ + +As part of our continuous motive to streamline and simplify the framework's +base API as much as possible, the current release removes the interfaces +_base/blocking.h_, _base/debug.h_, and _base/lock_guard.h_ as those headers +contained parts of the API that have become obsolete by now. As a further +minor change, the 'abs' function of _util/misc_math.h_ got removed. + +The string utilities _util/string.h_ received the new 'Const_byte_range_ptr' +type complementing the existing 'Byte_range_ptr'. Both types are designated +for passing arguments that refer to a byte buffer, e.g., the source buffer of +a write operation. + + +On-target system-update and rollback mechanism +############################################## + +For the mobile version of Sculpt OS as covered in +Section [First system image of mobile Sculpt OS (PinePhone)], +we envisioned easy-to-use system updates that would enable us to quickly +iterate based on the feedback of early field testers. + +This topic confronted us with a variety of concerns. Just to name a few, +conventions for booting that would not require changes in the future, +equipping (system) images with self-reflecting version information, tools for +generating and publishing digitally-signed images, on-target discovery of new +image versions, secure downloading and cryptographic checking of new images, +directing the machine's boot loader to use the new version, and possibly +reverting to an earlier version. + +Fortunately, most of these concerns have a lot in common with the problems +we had to address for Genode's +[https://genode.org/documentation/release-notes/18.02#On-target_package_installation_and_deployment - package management]. +For example, the off-target and on-target tooling for digital signatures, +the notion of a depot, and the concept of federated software providers +(depot users) are established and time-tested by now. + + +Self-reflecting version information +----------------------------------- + +To allow a running Sculpt system to know its own version, the sculpt.run +script generates an artificial boot module named "build_info", which can be +evaluated at runtime by the sculpt-manager component. + +! + + +Formalism for generating images and image metadata +-------------------------------------------------- + +To enable the Sculpt system to easily detect new versions, system images must +be accompanied by metadata discoverable at a known location. This information +is provided by a so-called image-index file located at +_depot//image/index_. The image index of a depot user lists the +available images in XML form, e.g., + +! +! +! +! +! ... +! + +The 'os', 'board', and 'version' attributes can be used to infer the file name +of the corresponding image file. The '' nodes contain a summary of +changes as information for the end user. + +The new _gems/run/sculpt_image.run_ script provides assistance with generating +appropriately named images, placing them into the depot, and presenting a +template for the manually curated image index. + + +Signing and publishing +---------------------- + +For signing and publishing system images and image indices, we extended the +existing _tool/depot/publish_ tool. To publish a new version of an image +index: + +! ./tool/depot/publish /image/index + +Each system image comes in two forms, a bootable disk image and an archive of +the boot directory. The bootable disk image can be used to install a new +system from scratch by copying the image directly to a block device. It +contains raw block data. The archive of the boot directory contains the +content needed for an on-target system update to this version. Within the +depot, this archive has the form of a directory - named after the image - that +contains the designated content of the boot directory on target. Depending on +the board, it may contain only a single file loaded by the boot loader (e.g., +uImage), or several boot modules, or even the boot-loader configuration. The +following command publishes both forms: + +! ./tool/depot/publish /image/ + +This results in the following - accompanied by their respective .sig +files - in the public directory: + +! /image/.img.xz (disk image) +! /image/.tar.xz (boot archive) +! /image/.zip (disk image) + +The .zip file contains the .img file. It is provided for users who download +the image on a system with no support for .xz. + + +On-target image discovery, download, and verification +----------------------------------------------------- + +To enable a running Sculpt system to fetch image index files and images, the +existing depot-download component accepts the following two new download +types: + +! +! + +Internally, the depot-download subsystem employs the depot-query component to +determine the missing depot content. This component accepts the following two +new queries: + +! +! + +If present in the query, depot_query generates reports labeled as "images" and +"image_index" respectively. These reports are picked up by the depot-download +component to track the completion of each job. The reported information is +also used by the system updater to get hold of the images that are ready to +install. + + +On-target image installation and rollback +----------------------------------------- + +Once downloaded into the local depot of a Sculpt system, the content of the +boot directory for a given image version is readily available, e.g., + +! depot/nfeske/image/sculpt-pinephone-2023-02-02/uImage + +The installation comes down to copying this content to the _/boot/_ directory. +On the next reboot, the new image is executed. + +When subsequently downloading new image versions, the old versions stay +available in the depot as sibling directories. This allows for an easy +rollback by copying the boot content of an old version to the _/boot/_ +directory. + + +Device drivers +############## + +NXP i.MX Ethernet & USB +======================= + +The Ethernet driver for i.MX53, i.MX6, and i.MX7 got updated to use a more +recent Linux kernel version (5.11). These drivers got aligned with the +source-code base originally ported for the i.MX8 SoC. + +Using the recent approach to port Linux device drivers, trying to preserve the +original semantic, it is necessary to provide the correct clock rates to the +driver. Therefore, specific platform drivers for i.MX6 and i.MX7 were created +that enable the network related clocks and export their rate values. +The i.MX53 related platform driver got extended to support these clocks. + +The USB host-controller driver for the i.MX 8MQ EVK is now able to drive the +USB-C connector of this board too. + + +Realtek Wifi +============ + +As a welcoming side effect of switching to the new DDE-Linux approach, +enabling other drivers that are part of the same subsystem has become less +involved. In the past, we mostly focused on getting wireless devices supported +by the iwlwifi driver to work as those are the devices predominantly found in +commodity laptops. That being said, every now and then, one comes across a +different vendor and especially with the shifting focus on ARM-based systems +covering those as well became necessary. + +As a first experiment, we enabled the rtlwifi driver that provides support +for Realtek-based wireless devices. Due to lacking access to other hardware, +the driver has been so far tested only with a specific RTL8188EE based device +(10ec:8179 rev 01). Of course, some trade-offs were made as power-management +is currently not available. But getting it to work, nevertheless, took barely +half a day of work, which is promising. + + +Platforms +######### + +Base-HW microkernel +=================== + +Cache-maintenance optimization +------------------------------ + +On ARM systems, the memory view on instructions and data of the CPUs, as well +as between CPUs and other devices is not necessarily consistent. When dealing +with DMA transfers of devices, developers of related drivers need to ensure +that corresponding cache lines are cleaned before a DMA transfer gets +acknowledged. When dealing with just-in-time compilation, where instructions +are generated on demand, the data and instruction caches have to be aligned +too. + +Until now, the base-API functions for such cache-maintenance operations were +mapped to kernel system calls specific to base-hw. Only the kernel was allowed +to execute cache maintenance related instructions. On ARMv8 however, it is +possible to allow unprivileged components to execute most of these +instructions. + +With this release, we have implemented the cache maintenance functions outside +the kernel on ARMv8 where possible. Thereby, several device drivers with a lot +of DMA transactions, e.g. the GPU driver, benefit from this optimization +enormously. The JavaScript engine used in the Morph and Falkon browsers +profits as well. + + +ACPI suspend & resume +--------------------- + +In the previous release, we started to support the low-level +[https://genode.org/documentation/release-notes/22.11#Low-level_mechanism_for_suspend_resume_on_PC_platforms - ACPI suspend and resume] +mechanism with Genode for the NOVA kernel. With the current release, we added +the required low-level support to Genode's base-hw kernel for x86 64bit +platforms. Similar to the base-nova version, on base-hw the +'Pd::managing_system' RPC function of Genode's core roottask is used to +transfer the required ACPI values representing the S3 sleep state to the +kernel. The kernel then takes care to halt all CPUs and flush its state to +memory, before finally suspending the PC using the ACPI mechanism. On resume, +the kernel re-initializes necessary hardware used by the kernel, e.g., all +CPUs, interrupt controller, timer device, and serial device. One can test +drive the new feature using the _run/acpi_suspend_ scenario introduced by the +former release. + + +Scheduling improvements for interactive workloads +------------------------------------------------- + +As Genode conquers the PinePhone, the base-hw kernel, for the first time, has +to perform real-life multimedia on a daily basis given a resource-limited +mobile target. One particularly important and ambitious use case has become +video conferencing in the Morph browser. A combination of an already demanding +browser engine with an application that not only streams video and audio in +both directions over network but also handles video and audio I/O at the +device, and all that fluently and at the same time. + +A lot of thinking went into how to optimize this scenario on each level of +abstraction and one rather low-level lever was the scheduling scheme of the +base-hw kernel. The base-hw scheduling scheme consists of a combination of +absolute priority bands with execution-time quotas that prevent higher +prioritized subjects from starving lower ones. There is the notion of a super +period and each subject owns only a fraction of that super period as quota +together with its priority. Once a subject has depleted its quota, it can't +use its priority until the end of the current super period where its quota +will be re-filled. However, during that time, the subject is not blocked - It +can become active whenever there is no subject with priority and remaining +quota present. + +So, this "zero" band below all the priority bands temporarily accommodates all +subjects that have a priority but that are out of quota. It contains, however, +also subjects that have no priority in general. These might be tasks like a GCC +compilation or a ray tracer. While prioritized tasks would be user input +handlers or the display driver. Now, one difficult problem that arises with +this scheduling scheme is that system integration has to decide how much quota +is required by a prioritized task. The perfect value can't be determined as it +depends on many factors including the target platform. Therefore, we have to +consider that an important task like the audio driver in the video-conference +scenario runs out of quota shortly before finishing its work. + +This is already bad as is as the audio driver now has to share the CPU with +many unimportant tasks until the next super period. But it became even worse +because, in the past implementation, subjects always entered the zero band at +the tail position. It meant that, e.g., the remaining audio handling had to +wait at least until all the unprioritized tasks (e.g. long-taking computations) +had used up their zero-band time slice. In order to mitigate this situation, we +decided that prioritized tasks when depleting their quota become head of the +zero-band, so, they will be scheduled first whenever the higher bands become +idle. + +This change relaxes the consequences of quota-depletion events for +time-critical tasks in a typical system with many unprioritized tasks. +At the same time, it should not have a significant impact on the overall +schedule because depletion events are rare and zero-band time-slices short. + + +NOVA microhypervisor +==================== + +ACPI suspend & resume +--------------------- + +As an extension to the principal +[https://genode.org/documentation/release-notes/22.11#Low-level_mechanism_for_suspend_resume_on_PC_platforms - ACPI suspend and resume] +support introduced with the Genode 22.11 release, the NOVA kernel now supports +also the re-enablement of the IOMMU after ACPI resume. The IOMMU as a hardware +feature has been supported by Genode since +[https://genode.org/documentation/release-notes/13.02#DMA_protection_via_IOMMU - release 13.02] +and extended in +[https://genode.org/documentation/release-notes/20.11#NOVA_microhypervisor - release 20.11], +which sandboxed device hardware and (malicious/faulty) drivers to avoid +arbitrary DMA transactions. + +Intel P/E cores +--------------- + +Starting with [https://en.wikipedia.org/wiki/Intel_Core#12th_generation - Intel CPU generation 12], +Intel introduced CPUs with heterogeneous cores, similar to +[https://en.wikipedia.org/wiki/ARM_big.LITTLE - ARM's big/LITTLE] concept. +The new CPUs have a number of so called P-cores (performance) and E-cores +(efficient), which differ in their performance and power characteristics. +The CPU cores +([https://en.wikipedia.org/wiki/Alder_Lake#CPUID_incoherence - should be]) +instruction compatible and are reported as identical via x86's CPUID +instruction nowadays. However, an operating system such as Genode must be able +to differentiate the cores in order to take informed decisions about the +placement and scheduling of Genode components. + +With the current release, we added support to the NOVA kernel to propagate the +information about P/E cores to Genode's 'core' roottask. In Genode's core, +this information is used to group the CPU cores into Genode's +[https://genode.org/documentation/release-notes/13.08#Management_of_CPU_affinities - affinity space]. +With +[https://genode.org/documentation/release-notes/20.05#NOVA_microhypervisor - release 20.05], +we introduced the grouping of hyperthreads on the y-axis, which we keep in +case the P-cores have the feature enabled. Following the P-cores and +hyperthreads, all remaining E-cores are placed in the affinity space. + +The following examples showcase the grouping in the affinity-space on x/y axis: + +Core i7 1270P - 4 P-cores (hyperthreading enabled) and 8 E-cores: + +! x-axis 1 2 3 4 5 6 7 8 +! ---------------------------------- +! y-axis 1 | P\ P\ P\ P\ E E E E +! 2 | P/ P/ P/ P/ E E E E +! +! hyperthreads \ / of same core + +Core i7 1280P - 6 P-cores (hyperthreading enabled) and 8 E-cores: + +! x-axis 1 2 3 4 5 6 7 8 9 10 +! ----------------------------------------- +! y-axis 1 | P\ P\ P\ P\ P\ P\ E E E E +! 2 | P/ P/ P/ P/ P/ P/ E E E E +! +! hyperthreads \ / of same core + +The information about the P/E cores is visible in the kernel and Genode's +log output and is reported in the 'platform_info' ROM, e.g. + +! kernel: +! +! [ 0] CORE:00:00:0 6:9a:3:7 [415] P 12th Gen Intel(R) Core(TM) i7-1270P +! ... +! [15] CORE:00:17:0 6:9a:3:7 [415] E 12th Gen Intel(R) Core(TM) i7-1270P +! ... + +! Genode's core: +! +! mapping: affinity space -> kernel cpu id - package:core:thread +! remap (0x0) -> 0 - 0: 0:0 P boot cpu +! remap (0x1) -> 1 - 0: 0:1 P +! remap (1x0) -> 2 - 0: 4:0 P +! remap (1x1) -> 3 - 0: 4:1 P +! remap (2x0) -> 4 - 0: 8:0 P +! remap (2x1) -> 5 - 0: 8:1 P +! remap (3x0) -> 6 - 0:12:0 P +! remap (3x1) -> 7 - 0:12:1 P +! remap (4x0) -> 8 - 0:16:0 E +! remap (4x1) -> 9 - 0:17:0 E +! remap (5x0) -> 10 - 0:18:0 E +! remap (5x1) -> 11 - 0:19:0 E +! remap (6x0) -> 12 - 0:20:0 E +! remap (6x1) -> 13 - 0:21:0 E +! remap (7x0) -> 14 - 0:22:0 E +! remap (7x1) -> 15 - 0:23:0 E +! ... + +! platform_info ROM: +! +! ... +! +! +! ... +! +! ... +! +! ... + + +Build system and tools +###################### + +Building and packaging CMake-based shared libraries (via Goa) +============================================================= + +The [https://github.com/nfeske/goa - Goa] tool streamlines the work of +cross-developing, testing, and publishing Genode application software +using commodity build tools like CMake. The tool is particularly suited for +porting existing 3rd-party software to Sculpt OS. + +Until recently, Goa was solely focused on applications whereas the porting of +3rd-party libraries required the use of the traditional approach of hand +crafting build rules for Genode's build system. This limitation of Goa got +lifted now. + +In the new version, a Goa project can host an _api_ file indicating that +the project is a library project. The file contains the list of headers that +comprise the library's public interface. The build artifact of a library +is declared in the _artifacts_ file and is expected to have the form +_.lib.so_. The ABI symbols of such a library must be listed +in the file _symbols/_. With these bits of information supplied +to Goa, the tool is able to build and publish both the library and the API as +depot archives - ready to use by Genode applications linking to the library. +The way how all those little pieces work together is best illustrated by the +accompanied +[https://github.com/nfeske/goa/tree/master/examples/cmake_library - example]. +For further details, please consult Goa's builtin documentation via 'goa help' +(overview of Goa's sub commands and files) and 'goa help api' (specifics of +the _api_ declaration file). + +When porting a library to Genode, one manual step remains, which is the +declaration of the ABI symbols exported by the library. The new sub command +'goa extract-abi-symbols' eases this manual step. It automatically generates a +template for the _symbols/_ file from the library's built shared +object. Note, however, that the generated symbols file is expected to be +manually reviewed and tidied up, e.g., by removing library-internal symbols. + +_Thanks to Pirmin Duss for having contributed this welcomed new feature, which_ +_makes Goa much more versatile!_ + + +New tool for querying metadata of ports +======================================= + +The integration of third-party software into Genode is implemented via _ports_ +that specify how to retrieve, verify, and patch the source code in preparation +for use with our build system. Ports are managed by tools residing in the +_tool/ports_ directory. For example, _tool/ports/prepare_port_ is used to +execute all required preparation steps. + +Currently, the base Genode sources support 90 ports (you may try +_tool/ports/list_ yourself) and, thus, it's not trivial to keep track of all +the ports in the repo directories. Therefore, we introduce the +_tool/ports/metadata_ tool to extract information about license, upstream +version, and source URLs of individual ports. The tool can be used as follows: + +!./tool/ports/metadata virtualbox6 +! +!PORT: virtualbox6 +!LICENSE: GPLv2 +!VERSION: 6.1.26 +!SOURCE: http://download.virtualbox.org/virtualbox/6.1.26/VirtualBox-6.1.26.tar.bz2 (virtualbox) +!SOURCE: http://download.virtualbox.org/virtualbox/6.1.26/VirtualBoxSDK-6.1.26-145957.zip (virtualbox_sdk) + + +Harmonization of the boot concepts across ARM and PC platforms +============================================================== + +To make the system-update functionality covered in +Section [On-target system-update and rollback mechanism] equally usable across +PC and ARM platforms, the conventions of booting the platforms had to be +unified. + +Traditionally, a bootable disk image for the PC contains a _boot/_ directory. +E.g., when using NOVA, it contains the GRUB boot-loader config + the hypervisor + +the bender pre-boot loader + the banner image + the Genode system image. +This structure corresponds 1:1 to the _boot/_ directory as found on the 3rd +partition of the Sculpt system, which is very nice. A manual system update of +Sculpt comes down to replacing these files. However, on ARM platforms, SD-card +images used to host a _uImage_ file and a U-Boot environment configuration +file in the root directory. The distinction of these differences complicates +both the build-time tooling and the on-target handling of system updates. + +The current release unifies the boot convention by hosting a _boot/_ directory +on all platforms and reinforces the consistent naming of files. On ARM, the +_uImage_ and _uboot.env_ files now always reside under _boot/_. Thanks to this +uniform convention, Genode's new system update mechanism can now equally +expect that a system update corresponds to the mere replacement of the content +of the _boot/_ directory. + + +Minor run-tool changes +====================== + +The functionality of the _image/uboot_fit_ plugin has been integrated into the +regular _image/uboot_ plugin as both plugins were quite similar. +FIT images can now be produced by adding the run option '--image-uboot-fit'. + diff --git a/doc/release_notes/23-05.txt b/doc/release_notes/23-05.txt new file mode 100644 index 0000000000..6253f0f116 --- /dev/null +++ b/doc/release_notes/23-05.txt @@ -0,0 +1,861 @@ + + + =============================================== + Release notes for the Genode OS Framework 23.05 + =============================================== + + Genode Labs + + + +Besides our annual documentation update, our major tool-chain update as +scheduled every two years, and the switch to C++20, version 23.05 puts the +spotlight on the Goa tool, which allows us to leverage existing SDKs like +Lomiri and Rust's cargo for Genode applications. In line with the previous +versions, DDE-Linux is prominently featured as enabler of our cross-platform +Wifi stack and the updated (6.1.20) drivers for Intel graphics and USB. + +:
+:

+:

+:

+ +Before getting to the technical achievements, we'd like to draw your attention +to the books "Genode Foundations" and "Genode Platforms", which have been +updated to reflect the most recent state of the framework. Whereas the +"Foundations" cover Genode's architecture, developer work flows, and reference +material, the "Platforms" document is focused on low-level hardware topics and +provides plenty of practical guidance. + +:
+ +Every two years, we update Genode's tool chain to the latest stable releases +of GCC and binutils. This time, we took the update as opportunity to switch +Genode's default from C++17 to C++20 so that modern C++ niceties can be used +for regular Genode components. The new tool chain is covered by +Section [New tool chain based on GCC 12.3, C++20 enabled by default]. + +For application developers, the evolving Goa tool is certainly the most +interesting feature of the current release. As detailed in +Section [Goa tool updated to Sculpt OS 23.04, initial support for Rust], +this tool enables us to reuse existing SDKs to target Genode. In particular, +we enabled the use of the Lomiri mobile UI toolkit (formerly known as Ubuntu +Touch UI toolkit) for targeting the PinePhone, and Rust's cargo. + +System integrators may appreciate our continued development of the Linux +device-driver environment, which received an update to Linux 6.1.20 +(Section [Device drivers]) and ultimately enabled us to use the same Wifi +stack across PC and ARM platforms +(Section [Uniform Wifi stack across PC and ARM platforms]). + +Even though not end-user facing yet, two noteworthy development milestones of +the current release are the new use of our custom base-hw microkernel as x86 +hypervisor (Section [Base-HW microkernel]) and the profound work on storage +encryption covered in +Section [Revision of Genode's custom block-encryption infrastructure]. +Further topics making an appearance in version 23.05 range from RISC-V, over +WireGuard, VirtualBox, to seL4. + + +Goa tool updated to Sculpt OS 23.04, initial support for Rust +############################################################# + +Last month, we [https://genode.org/news/sculpt-os-release-23.04 - released] +Sculpt OS 23.04 for PC and PinePhone. The new release comes with various +[https://genodians.org/nfeske/2023-05-11-sculpt-os - usability improvements] +such as presets and on-target system updates. + +[image mobile_sculpt_23_04] + Interactive software management on the mobile variant of Sculpt OS + +In particular, with Sculpt OS 23.04 running on the PinePhone, we have carved +out the base for hosting mobile apps on a Genode-based system. Yet, there are +only very few apps available right now. Since an OS is of no practical use +without apps, this urgently called for an SDK to simplify (mobile) app +development. After careful investigation, we opted for porting the +Ubuntu-Touch-UI toolkit to Genode and integrate it into Goa (Section +[Using Goa for bringing apps based on the Ubuntu-Touch-UI toolkit to Genode]), +our streamlined workflow tool for application development. In addition, we +integrated initial support for Rust's _cargo_ to make Goa palatable to a +broader developer audience (Section [Initial Rust support]). + +The growing attention of the Goa tool prompted us to move it under the +[https://genodians.org/nfeske/2023-05-02-goa-genode-labs - umbrella of Genode Labs] +as we are increasing our development and maintenance efforts for the tool. +Aligned with the Sculpt release, the Goa tool has been updated with the +corresponding depot archive versions. With this Genode release, we put a +cherry on top and added bash completion to improve the user experience even +further. Having Goa installed, bash completion is enabled by the following +commands: + +! goa update-goa master +! GOA_DIR=$(realpath $(which goa) | sed s#bin/goa##) +! echo "source ${GOA_DIR}/share/bash-completion/goa" >> ~/.bashrc + +:Goa tool: + + [https://github.com/genodelabs/goa/] + + +Using Goa for bringing apps based on the Ubuntu-Touch-UI toolkit to Genode +========================================================================== + +While writing mobile apps might be fun, it is outside our core expertise. +Therefore, we have looked into ways of supporting established open-source SDKs +for app development on Genode. We investigated two possible options in depth, +namely Ubuntu Touch's UI toolkit now called [https://lomiri.com - Lomiri] and +the [https://docs.sailfishos.org/Tools/Sailfish_SDK - Sailfish SDK]. We have +tried to port applications for both stacks and after many iterations settled +with the Ubuntu UI toolkit. The full story can be read +[https://genodians.org/ssumpf/2023-05-06-ubunutu_ui - here]. Therefore, a port +of the Ubuntu UI toolkit is available on Genode right now and support for it +has been added to the Goa tool. + +The workflow for crafting an app for the PinePhone using the Goa tool is a +fairly streamlined experience now: + +# Since the UI toolkit depends on Qt5, add "genodelabs/api/qt5" to your + [https://genodians.org/nfeske/2019-11-25-goa - _used_apis_ file] + +# Add "ssumpf/pkg/ubuntu_ui_toolkit" to your _archives_ + [https://genodians.org/nfeske/2019-11-25-goa - file] to have the UI toolkit + available within your package + +# In order to have your QML code within your packet installed, add + ".tar: install/" to your + [https://genodians.org/nfeske/2019-11-25-goa - _artifacts_ file] + +# Configure your + [https://genodians.org/nfeske/2019-12-19-goa-unix-terminal - _runtime_ file] + +# Execute your scenario on Linux for development + ! goa run + +# Build for the PinePhone + ! goa build --arch arm_v8a + +# [https://genodians.org/nfeske/2020-01-16-goa-publish - Publish] your package + ! goa publish --depot-user john --depot-overwrite + +Examples using QML, Qt5, and C++ can be found +[https://github.com/ssumpf/goa-projects - here] + + +Initial Rust support +==================== + +The Rust programming language has grown in popularity in the recent years. +The Genode OS Framework had support for the Rust programming language +before, contributed to Genode release 16.05 by Waylon Cude. However, as an +on-off contribution it never got traction and the support was eventually +removed with release 20.05. +While the original support focused on some low-level runtime libraries and +integration into the Genode build system, our new attempt has a somewhat +different objective, which is to facilitate the use of the existing Rust +ecosystem on the Genode OS Framework. The removal note already envisioned a +possible comeback using the Goa tool and Rust's cargo build system, for which +we have added initial support with this release. + +Our objective led to the following guidelines for Rust integration: + +# Make use of the native build system, cargo, to make the existing ecosystem + accessible. +# Aim for a seamless integration into the Genode OS Framework using the Goa + build tool. +# Instead of introducing our own Genode + [https://doc.rust-lang.org/nightly/rustc/platform-support.html - target triples], + leverage Genode's FreeBSD-based C library interface to use existing + supported standard library targets like 'x86_64-unknown-freebsd'. +# Strive to use the upstream tool chain, or at least stay as close to upstream + as possible. + +While we largely succeeded in following these guidelines, our initial +proof-of-concept implementation relies on a marginally adapted tool chain to +work around missing support for versioned library symbols in our linker. +We are exploring avenues to overcome these limitations and expand the support +to cover more complex use cases in the next release. + +To learn more about our Rust support, head over to the +[https://genodians.org/atopia/2023-05-30-bringing-rust-back-to-genode - article on Genodians.org]. + + +Uniform Wifi stack across PC and ARM platforms +############################################## + +Support for wireless LAN was mostly focused on the +[https://genode.org/documentation/release-notes/14.11#Intel_wireless_stack - PC platform] +as it was the platform predominately used for using Genode and, in extension, +Sculpt on a daily basis. In the last couple of years, however, we started to +embrace ARM-based platforms like the MNT Reform 2 and the PinePhone as well, +longing for thorough support of Sculpt OS on such systems. Thanks to our Linux +device-driver environment, we have now taken the opportunity to reuse the +existing wireless stack on vastly different platforms. + + +Making the wireless stack globally accessible +--------------------------------------------- + +The +[https://genode.org/documentation/release-notes/23.02#Realtek_Wifi - previous release] +already featured additional support for a different wireless LAN device driver - +the rtlwifi driver that supports Realtek-based devices - giving us a good +intuition on how easy it has become to extend even a complex Linux-based +driver component stack such as our wifi-driver component ('wifi_drv'). + +The first step was making it less x86-centric. We started by making the various +ingredients of the driver available on the ARM platforms. + +On the one hand, that includes the WPA supplicant and its dependencies like +the 'nl80211' driver that in turn depends on 'libnl'. Enabling them was +straight-forward because they are already pretty platform independent and +the platform-dependent portions, e.g. libcrypto, are readily available for ARM. + +On the other hand, the wireless stack was slightly more complicated because +the hardware integration of wireless networking devices on ARM platforms +varies from platform to platform. In case of the MNT Reform 2 and PC, the +integrated wireless devices are normally connected via PCIe. In contrast, the +PinePhone relies on SDIO. We separated the code to allow for a "mix-and-match" +way of selecting the necessary compilation units as the used Linux +configuration might differ between each target and could result in compilation +issues otherwise. + +The next step was to make the wireless stack globally accessible by moving it +from the _pc_ to the _dde_linux_ repository. This move was motivated by the +fact that the _dde_linux_ repository is already available in all platform or +rather board-specific repositories while the _pc_ repository is not. It is +in itself a board-specific repository and therefore having it appear as +dependency for other such repositories feels unnatural. + +So the bulk of the driver code now lives in the _dde_linux_ repository from +where it can be referenced by other repositories. + +While moving the code, we noticed that in contrast to all other Linux-based +drivers the 'wifi_drv' is special. Since the binary itself is a libc component, +care was taken to isolate the application code, the 'wpa_supplicant', from +the driver code, the library containing the Linux wireless stack and drivers. +On all platforms, the binary stays the same while the driver library contains +all the platform-specific code. For this reason, the 'wifi_drv' binary is now +delegated to be a generic harness that includes all configuration and +management functionality shared by all wireless device driver components, +e.g., the WPA supplicant. The code of the device driver emulation environment +is located in _repos/dde_linux/src/lib/wifi_. It is referenced by the +platform-specific driver library that resides in the corresponding platform +repository. The runtime configuration needs to point the driver to a proper +driver library. + +The platform-specific library is in charge of orchestrating the 3rd-party +sources utilized by the driver as well as providing the _source.list_ and +_dep.list_ files. It must include the generic library snippet +_repos/dde_linux/lib/wifi.inc_ that deals with managing the emulation +environment code. The amount of code added by the platform-specific libraries +is unimposing as it mostly consists of the dummy implementations needed by +the Linux configuration. + +[image wifi_drv_architecture] + Composition of the wireless LAN driver component + +All recipes for the depot archives are prefixed to the specific driver, for +example 'pkg/pc_wifi' contains a reference to 'src/pc_wifi_drv' as well as to +'raw/pc_wifi_firmware'. + +Thanks to the steps outlined above, we now have three different wireless LAN +drivers, one for the PinePhone, one for the MNT Reform 2, and one for the PC +that nicely follow the same approach. + + +New firmware loading mechanism +------------------------------ + +Additionally to making it easier to enable and use the driver for new +platforms, we also refined how the driver loads its firmware images. In the +past, the driver contained a list of well-known working firmware images that +needed to be updated every now and then when new devices where enabled or the +firmware version changed due to a Linux update. In particular using the driver +with new devices was cumbersome as the driver itself already supported the +device most of the time, but it solely missed the corresponding entry in the +firmware list and adding that required recompiling the driver. + +[image wifi_firmware_loading] + Firmware image loading sequence + +So instead, the driver now loads the firmware images via its local VFS rather +than requesting a predetermined ROM module. Since the platform-specific driver +library has no direct access to the VFS - after all both worlds are +intentionally isolated from each other - a request/response interface was +added. The library submits a request to the _wifi_drv_ binary and will suspend +its execution waiting for the completion of the request. The binary will +acquire the firmware image and notify the driver library in return. +Streamlining the firmware acquisition in such a manner allows for using the +original probing mechanism available in Linux. Rather than following the +firmware list the actual driver code is now free to probe as it sees fit, +exactly pointing to the required uAPI revision in case the firmware is +missing. + +The following snippet illustrates the configuration of the driver on the +PinePhone (omitting any integration-related routes for the config ROM as well +as state and scan reports): + +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! […] +! child/> +! +! + +In this configuration, the firmware images are provided as a _.tar_ archive +that itself is requested via a ROM connection. The driver will always look +into the _/firmware_ directory to access any firmware related files. How the +directory is populated is up to the integrator of the driver. + +As a further simplification step, we removed the need for the firmware library +used to contain firmware images. It is superseded by the use of a plain data +depot archive, e.g., _raw/pc_wifi_firmware_. + + +Additional device support and updates +------------------------------------- + +We updated the firmware images to the most recent ones supported by +Linux version 6.1.20. + +We enabled the ath9k PCIe driver that can be used on the MNT Reform 2 and the +PC. As the ath9k device (168c:0034) used to test the driver on the PC exhibited +problems when using MSIs, we disable their usage in the 'pci_decoder'. Similar +treatment might be necessary if other ath9k-based devices are used. + +The device support in the 'rtlwifi' driver got extended by additionally +enabling support for RTL8192CE devices. + +Furthermore, we updated the WPA supplicant to its latest v2.10 release and +introduce preliminary support for joining networks secured by WPA3. + + +Base framework and OS-level infrastructure +########################################## + +New tool chain based on GCC 12.3, C++20 enabled by default +========================================================== + +Following a regular cycle of two years, we updated our tool chain to recent +versions again, this time in particular to GCC 12.3.0, binutils 2.40, and GDB +13.1 while taking the opportunity to enable C++20 by default. + +A noticeable change with GCC 12 is that auto-vectorization with the +'-ftree-vectorize' option is now enabled by default when building with the +'-O2' optimization level. This has the effect that more SIMD instructions are +generated, which required adaptations throughout our code base, for example by +making sure that memory allocations in ported Linux drivers adhere a suitable +address alignment and by saving and restoring ARMv8 FPU registers in the +dynamic linker. + +In addition to that, GCC 12 reports new warnings and errors, which we had to +rectify at various places, the most common ones being: + +* Deprecated arithmetics between different enumeration types, + +* Deprecated use of '++' and '--' operators with volatile variables, and + +* Undefined references to 'strlen' inside custom implementations + of 'strlen'-like functions, related to the + '-ftree-loop-distribute-patterns' option. + +As an extra feature, we added Genode's library name patterns to the linker so +that the '-l' option has become able to find the corresponding libraries. +This is useful while porting 3rd-party software based on Autoconf, whenever a +'configure' script checks for a library dependency by linking a test program +with this option. This change thereby removes the need for dummy libraries +that were formerly used to satisfy the probing. + + +API changes +=========== + +As part of Genode's +[https://genode.org/documentation/release-notes/16.08#Cultivation_of_the_new_text-output_API - great API revision] +in 2016, we largely *abolished* the use of *format strings* throughout the +framework. This is desirable because a code base without format strings cannot +have format-string vulnerabilities. Still, a few occurrences, specifically the +interface for passing session-construction arguments, remained untouched since +then. With version 23.05, we finally attained our initial goal by wrapping up +the transition. + +In particular, we revised 'Genode::Connection', which now accepts the session +label, affinity, and session-specific parameters as constructor arguments, +whereas the parameters are passed as a 'Genode::String'. This eliminates the +need for rendering a format string. Given this new interface, we were able to +remove format strings from all connection types, updated all components that +still happened to rely on format strings, and ultimately removed format +strings from Genode's base API. + +Format strings still play a role to accommodate 3rd-party code ported +to Genode. Whenever the 3rd-party code targets the C runtime, format +strings are readily available via the libc. For free-standing ports that +avoid the dependency from the full C runtime, e.g., ported device drivers, +a new 'format' library based on Genode's former _base/snprintf.h_ and +_base/console.h_ provides rudimentary format-string support. The library +is hosted in the libports repository. + +As another matter of housekeeping, we removed the _util/avl_string.h_ utility. +The use case of organizing objects by using strings as keys is covered by the +_util/dictionary.h_ now. + + +Towards kernel-agnostic DMA protection +====================================== + +As sketched in our [https://genode.org/about/road-map - road map], we plan +having a feature-complete PC version of Sculpt OS based on base-hw by the end +of this year. One of the reasons why we are still sticking to base-nova for +the PC version is the fact that we are relying on NOVA's IOMMU support. One +necessary step to decouple Sculpt OS from base-nova is to integrate the IOMMU +handling into the platform driver. + +Motivated by our +[https://genode.org/documentation/release-notes/23.02#Custom_IP_block_for_DMA_protection_on_AMD_Xilinx_Zynq - custom IP block for DMA protection on AMD/Xilinx Zynq], +we integrated the notion of IOMMU-like devices into the platform driver with +this release as a preparatory step. The platform driver automatically acquires +known IOMMU-like devices for itself by looking at the device types. Other +devices can then reference these devices by using '' nodes. This is +best illustrated by looking at the devices ROM for the Zynq's dma_guard IP +block: + +! +! +! +! +! +! +! +! +! +! +! +! + +This tells the platform driver that, whenever a DMA buffer is allocated/freed +for the session owning the 'axi_dma_0' device, the 'dma_guard_0' must be +configured accordingly in order to allow/deny access to the corresponding +memory ranges. With the structural changes to the platform driver, the support +for dma_guard devices is simply added by implementing specific 'Io_mmu' and +'Io_mmu_factory' objects. You can find the code in the _dma_guard.h_ within +the +[https://github.com/genodelabs/genode-zynq/blob/master/src/drivers/platform/zynq/dma_guard.h - genode-zynq repo]. + +For the PC version of the platform driver, we implemented a _kernel_iommu_ +device that still uses device PDs to pass IOMMU configuration to the NOVA +kernel. The _kernel_iommu_ is automatically instantiated and used as a default +for each device until we replaced this by a kernel-agnostic implementation in +a future release. + +With these preparations, we paved the way for implementing configuration logic +for arbitrary IOMMU-like devices within the platform driver. In particular, +the platform driver has been made capable of managing multiple IOMMU-like +devices at the same time. However, there is one limitation that comes from the +fact that DMA buffers are not device-specific but allocated per session: All +IOMMU-like devices must either operate as MMU (virtual addressing) or as MPU +(physical addressing). + + +Revision of Genode's custom block-encryption infrastructure +=========================================================== + +Tresor library +~~~~~~~~~~~~~~ + +For about two years, our Ada/SPARK-based CBE block encryption and its GUI +front-end, the file vault, served us well with rather manageable workloads +such as configuration and credential files in Sculpt OS on the PC. However, +with the rise of mobile Sculpt on the PinePhone, the CBE ecosystem was +suddenly confronted with new challenges and requirements. + +First, mobile platforms are usually less forgiving when it comes to +performance and the CBE still exhibited a lot of potential for optimization. +Second, we envision encrypted storage to become an integral part of the base +system - the "appliance role" of mobile Sculpt OS - which shifts the role of +the component from an optional feature to a foundational mechanism. With this +role shift, however, maintainability becomes increasingly important. Third, +now that we decided to settle on this block-encryption approach and to +increasingly expose it to real workloads, we can expect new requirements to +pop up more frequently and with higher priority. Last but not least, our +Ada/SPARK runtime, so far, lacks ARM support. + +This prospect forced us to carefully reconsider our relation to the existing +CBE approach, and especially to the fact that its core logic and crypto +back-end were entirely written in Ada/SPARK. When we started developing the +CBE in Ada/SPARK, we were positive that the language might become popular +among the core developers of Genode and that, eventually, other, especially +critical parts of the framework could benefit from it as well. But this idea +didn't come to fruition. Only a few of us came in touch with the new language +and, of those, even fewer acquired profound experience with it. We ultimately +realized that the friction caused by the added language boundary that emerged +with the CBE approach became a bottleneck, inhibiting the further evolution of +our block-encryption stack with a strong sense of collective code ownership. + +This observation in mind, and the above-mentioned challenges in sight, we +decided to drop the CBE library and create a new implementation strongly +inspired by the CBE design but in C++, our "mother tongue". The new library is +called tresor, brings the same feature set as the CBE and is compatible with +containers created with the CBE. The file vault has been adapted to run with +the tresor library. So file-vault users can continue using their containers as +usual without further ado. The entire tresor-based ecosystem is +architecture-agnostic, which lifts the former restriction to x86. + + +File Vault +~~~~~~~~~~ + +Some new features have been added to the file vault. For instance, the +component can now be driven with one of two available user interfaces: The +usual graphical front-end or the new non-interactive interface that is driven +by a textual configuration and provides feedback through a report. This allows +for the integration of the file vault with automated controls respectively +lower or higher-level UIs. The interactive interface remains the default, but +one can replace it with the text-based variant using the new "user_interface" +configuration attribute. An example of operating the text-based interface is +provided by the new _file_vault_config_report.run_ script. + +As another rather small but handy feature, a file vault can now be locked and +unlocked without having to restart the component. In the locked state, all key +material is removed from the cryptographic back end and the block-encryption +driver is shut down. The user is then prompted to provide the correct +credentials in order to re-establish access to the container. + + +Custom virtual machine monitor on ARM +===================================== + +The +[https://genode.org/documentation/release-notes/23.02#Interactive_graphical_VMs_on_ARM - previous release], introduced interactive graphical VMs on ARM systems. +Genode's custom virtual machine monitor was enhanced by VirtIO device models +for input events and GPU. However, dynamic changes of the virtual GPU's +framebuffer resolution weren't yet handled by the initial version. With the +current release, these restrictions got removed. Now, the user is able to +resize the window of a virtual machine as expected. + + +NetBSD rump kernel on RISC-V +============================ + +We have added RISC-V to our port of the +[https://wiki.netbsd.org/rumpkernel - rump kernel]. +This enables Genode to access commodity file-systems on RISC-V based devices. + + +Strengthened fault tolerance of on-target package management +============================================================ + +Genode's way of safely installing and deploying packages on-target - as +introduced in +[https://genode.org/documentation/release-notes/18.02#On-target_package_installation_and_deployment - version 18.02] - +is a corner stone of Sculpt OS. The recent move of Sculpt OS to mobile +devices, however, revealed a couple of limitations that we address with the +current release. + +First, in contrast to the PC version of Sculpt OS that allows for the +straight-forward management and editing of files using a regular command-line +interface, a touch-based user interface as present on the phone is far more +constrained. Problems that can be solved by manual intervention on the PC +without second thought can become insurmountable showstoppers on the phone. +The most prominent problem is recovery from the situation where package +dependencies remain incomplete due to an interruption of the installation +process or due to packaging mistakes. On the PC, such a situation can be +resolved by simply clearing the depot using a single terminal command, +followed by a reinstall of the package. On the phone, the user was left out in +the cold with the message "package installed but incomplete" but with no +obvious or non-obvious way of recovery. The new version gracefully handles +this failure state by offering the retry of the package installation. + +Second, network connectivity is far more fluctuating on mobile devices, which +increases the likelihood for download errors. The previous version that +regarded download errors as rare and sporadic issues, responded to such errors +by repeated and silent retries. We found that a mobile phone demands a more +graceful way to reflect such failure situations to the user, and to limit the +rate of futile download attempts. The new version preserves information about +download failures for user inspection and re-issues new downloads only if not +already flagged as unavailable. + +Finally, we encountered the manual addition of software providers to the +system as a hurdle on the phone. On the PC, a new software provider can be +added by manually placing the provider's _download_ and _pubkey_ files in a +local depot directory, which is straight-forward when using a shell. However, +on a touch-screen device, there is no obvious and simple way to supplement the +system with such information. To still accommodate the user's desire to +download and install software from arbitrary providers, we added the option to +explicitly skip the signature verification for downloads. This is useful in +scenarios where the lack of integrity of downloaded content does not pose a +risk, e.g., for untrusted applications that are rigidly sandboxed, or during +development. + +Whenever the depot-download subsystem encounters the attribute 'verify="no"' +for an '' item, it accepts the installation even if no key is +available. It still applies verification for dependencies whenever possible. +E.g., if a package of the provider "john" gets installed via 'verify="no"' and +the package depends on an archive by "genodelabs", for which the public key is +known, the integrity of the content originating from "genodelabs" is verified. + + +Libraries and applications +########################## + +Qt5 reorganization +================== + +When the Goa tool is used to build an application, all libraries of the used +API packages get linked to the application and the single Qt5 API package with +big libraries like QtWebEngine was a bit too much for simple Qt applications. +For this reason, we split the Qt5 API into smaller packages according to the +corresponding Qt modules. + +As preparation for the release of a binary version of the Qt5 host tools, we +also reduced the external dependencies of these tools for improved +compatibility with different host systems and changed their install location +to the location of the other Genode host tools. + +And finally, we added a 'ubuntu-ui-toolkit' meta package in the genode-world +repository which pulls in all dependencies for the Ubuntu UI toolkit, +including a runtime with the required ROMs. + + +WireGuard improvements +====================== + +There are two smaller changes related to Genode's port of WireGuard. First, +peers can now be removed from WireGuard at runtime by removing the +corresponding '' tags from the component's configuration. This operation +enforces the same assurances as removing a peer from a native WireGuard driver +in Linux. + +The second change has to do with the nature of the port. The WireGuard port is +one of the rare examples where we use our Linux device driver environment +(dde_linux) for porting software that is not exactly a driver. The component +does not depend on a specific hardware configuration and therefore, the +emulated Linux kernel can be platform-agnostic. Consequently, while porting, +we created such a variant of the Linux emulation specifically for WireGuard. + +However, we realized that this variant can come in handy for ports of other +hardware-agnostic kernel parts (for instance, lxip) as well. Therefore, we now +cut it out of the WireGuard port in order to make it a self-contained version +of the 'lx_emul' library. The new library is called 'virt_lx_emul' and is +accompanied by the 'virt_linux' target that can be used to build the +corresponding Linux kernel and run it in Qemu. + + +Updated or removed 3rd-party software +===================================== + +VirtualBox updated to version 6.1.44 +------------------------------------ + +Our port of VirtualBox underwent some maintenance work published in this +release. With the tool chain updated to GCC 12, it became necessary to update +VirtualBox to version 6.1.44 to keep up with the tool-chain changes and fix +many upstream bugs alongside. Also, we improved several aspects of the port to +improve robustness of networking, USB, multi-threading, and VM reboot. After +thorough testing in every-day scenarios, we finally adopted the handling of +the x86 time-stamp counter from version 5 and disabled the VM exit for the +RDTSC instruction, which improves the performance of selected scenarios +significantly. For Windows guests, it has become crucial to configure the +paravirtualization provider like follows in the _machine.vbox6_ file. +Otherwise, the guest's TSC calibration fails resulting in a bogus CPU +frequency assumption. + +! + + +Removed ports of pcre16 and icu libraries +----------------------------------------- + +The pcre16 and icu libraries had been used by Qt5 in the past but were not +used anymore since the last Qt updates. So we removed them from the _libports_ +repository. + + +Device drivers +############## + +Linux device driver environment updated to Linux 6.1.20 +======================================================= + +According to [https://genode.org/about/road-map - our roadmap], the update of +Genode's Linux device driver environment (DDE) to a more recent 6.x Linux +version was planned for release 23.08. Now, we decided to tackle this update +with this version already. + +Besides the Wireguard port to Genode, the following ported drivers use the +latest Linux kernel 6.1.20 version now: + +* Zynq SD-card driver +* PCI Wifi driver for i.MX 8MQ +* all PC drivers (USB host, Wifi, Intel display) + +Note that a few drivers are not listed above. The existing drivers for the +Allwinner and i.MX 8MQ SoC still use older 5.x Linux kernel versions as base. +However, the Linux device driver environment has been tweaked carefully to +support a range of Linux kernel versions from 5.11 till 6.1.20. + +While doing the update work, we investigated a more sustainable link between +the Linux kernel drivers for USB and display drivers (DRM/KMS) on the one +hand, and the Genode API on the other. The outcome is explained in the next +two sections. + + +Intel display driver +==================== + +During the update of DDE Linux to the Linux 6.1.20 version, the dependency on +internal structures of the Intel framebuffer driver (intel_fbdev) became a +hassle. Although the update was successful finally, we decided to remove the +direct usage of intel_fbdev in our ported Intel display driver, in order to +ease future updates. Nevertheless, the functionality of intel_fbdev is +required to manage the framebuffer memory to provide a working Genode GUI +interface by the driver. For that, we investigated the use of the +[https://www.kernel.org/doc/html/v5.0/gpu/drm-kms.html - Linux DRM/KMS] +interface, specifically to allocate and manage so called +[https://www.kernel.org/doc/html/v5.0/gpu/drm-kms.html#dumb-buffer-objects - dumb buffer objects]. +As described in the linked article, the dumb buffers are a standardized and +streamlined way to make early boot graphics possible driven by user-land +tools. We adjusted our port along the ioctl's of the dumb buffer functionality +to manage the framebuffer in our ported display driver. + + +USB +=== + +Connecting different USB clients to a USB host controller driver is a delicate +task. When using a port of a Linux kernel driver, it can quickly become +brittle because the USB driver API in the Linux kernel is complex and contains +some semantic dependencies, for instance regarding synchronization, which are +not always obvious. However, the Linux kernel offers a USB device I/O API to +the user-land that is used for instance by libusb. This API has to guard the +USB subsystem against wrong usage, and implements the necessary semantics +regarding synchronization and dynamic changes of clients and devices. In the +past, we repeatedly encountered corner-case issues, if clients or devices +vanished and appeared at a high rate. For the sake of robustness, we decided +to redesign our internal linking in between the Genode USB API and Linux to +use the user-level device I/O API of the latter. Moreover, we extended the +capacity of USB packets in-flight that can be handled by the controller in +parallel to 32, to enhance the throughput for some USB devices. + + +NVMe storage +============ + +Our custom NVMe driver received the following improvements. First we added +'host-memory-buffer' (HMB) support to the driver, which is a performance +optimization for NVMe devices that do not make use of a DRAM cache for its +operational data. + +The amount of memory used for the HMB can be set by adding the 'max_hmb_size' +attribute in the '' node of the driver. This value is checked against +the constraints imposed by the device. Should the value be less than the +minimal required amount of memory, it will not be used and a warning is +issued. On the other hand, if the specified value is larger than the preferred +amount of memory as favored by the device, it will be capped to the useful +amount instead. + +Naturally, when using the HMB, the required RAM quota of the driver component +increases by that amount. + +Second, we fixed a problem detecting the block size (LBA format) of a given +namespace. The lower 4 bits of the 'FLABS' register indicate which of the (up +to) 16 supported LBA formats is used by the namespace. However, instead of +only making use of those bits, the driver looked at the whole register that +also includes other information. This led to using the wrong index for reading +the LBA format and, on certain devices, rendered the driver unusable as the +assumed block size was detected wrong. + + +Audio-driver update +=================== + +We updated the audio driver for HDA devices ported from OpenBSD to version 7.3. +The functional changes are minimal, but the new version supports more recent +PC platforms and recognizes more codecs. + + +Platforms +######### + +Base-HW microkernel +=================== + +Principle x86 virtualization support (on Qemu) +---------------------------------------------- + +This release brings limited support for AMD's Secure Virtual Machine (SVM) +vCPUs to Genode's custom base-hw microkernel. Supporting SVM is meant as an +intermediate step towards enabling advanced virtualization workloads using +VirtualBox on Intel VMX later this year. The approach allows us to craft the +kernel's virtualization infrastructure using Qemu - which is able to emulate +SVM in software - and cross-test our implementation against other hypervisors +in a tightly controlled setting. For reference, we used the time-tested Qemu +version 4.2 for this line of work. + +Implementing principle vCPU support revealed a few points of friction between +base-hw's kernel interface, which had been designed for the needs of our +custom ARM VMM, and our kernel-agnostic VM interface on x86 that has been +carefully crafted to support a range of 3rd party hypervisors, but relies on +more logic in the kernel-specific VMM library to manage the vCPU state. + +The current implementation is able to run several test VM workloads like the +artificial 'vmm_x86' test, our seoul VMM run scripts with Linux, and - of +course - Genode VMs on one vCPU. It has thereby reached an important stepping +stone towards our actual goal of hosting VirtualBox on Intel hardware. + +Having shown that base-hw can support the generic x86 VM interface, we will +mature our implementation and may adapt our interface to make it a better fit +to base-hw's vCPU execution model in the future. + + +Boot-time RAM detection on the PinePhone +---------------------------------------- + +For the PinePhone, we implemented dynamic detection of the system RAM size by +parsing the values of the DRAM controller as programmed by U-Boot. This way, 2 +and 3 GB models of the PinePhone are supported by Genode. + + +Updated seL4 microkernel +======================== + +With this release, we updated the support of the seL4 kernel from 9.0.1 to +12.1.0 for i.MX6 Sabrelite board and x86_64 PC. The support for 32-bit PC got +removed since it is unused, and the i.MX7 Sabrelite support got removed since +it is not supported by the new seL4 kernel anymore. + +The updated seL4 kernel requires additional host tools installed, namely +CMake, Ninja and additional Python3 modules, jinja2, jschonschema, and pyfdt. +Depending on the distribution, the modules are available as distribution +package or need to be installed with the python pip3 tool. diff --git a/doc/release_notes/23-08.txt b/doc/release_notes/23-08.txt new file mode 100644 index 0000000000..a88c3baa83 --- /dev/null +++ b/doc/release_notes/23-08.txt @@ -0,0 +1,786 @@ + + + =============================================== + Release notes for the Genode OS Framework 23.08 + =============================================== + + Genode Labs + + + +The headline features of Genode 23.08 are concerned with developer tooling. +First, we re-approached Genode's GDB debugging support with the grand vision +of easy on-target debugging directly on Sculpt OS. Our new debug monitor +introduced in Section [Multi-component debug monitor] combines the GDB +protocol with Genode's init component. Thereby, the monitor can transparently +be integrated in Genode subsystems and can be used to debug multiple +components simultaneously. + +Second, the Goa tool, which started as an experiment in 2019, has been shaped +into an all-encompassing alternative to Genode's traditional work flows for +developing, porting, and publishing applications. The tool got vastly more +flexible with respect to runtime testing, and even became able to handle +dependencies between Goa projects. The massive improvements are covered in +Section [Goa tool gets usability improvements and depot-index publishing support]. + +Besides the headline features of the release, we admittedly deviated from the +original plans laid out on our [http:/about/road-map - road map]. Early-on in +the release cycle, we found ourselves drawn to code modernization, the +retiring of legacies, and quality assurance. E.g., we finally updated some of +the most veteran internals of the framework to our modern-day coding +practices, we urged to continue the success story of our new Linux +device-driver environment (DDE) by replacing old USB drivers by new components +leveraging the modern approach, and created a new DDE-Linux-based NIC driver +for PC hardware while retiring the aged iPXE-based traditional driver. The +outcome of this tireless work may hardly be visible from a feature perspective. +But it greatly improves the velocity and quality of the code to maintain down +the road. + +It goes without saying that the other topics of the road map haven't been +disregarded. In fact we celebrated a break-through with x86 virtualization +on our base-hw kernel, are diving deep into the latest Intel platforms, and +working on the user-visible side of the mobile version of Sculpt OS. But since +those topics are not wrapped up yet, we all have to stay tuned for the next +release. + + +Multi-component debug monitor +############################# + +The debugging of Genode components using the GNU debugger (GDB) was already +an anticipated feature when we introduced the first version of the GDB monitor +component in version +[https://genode.org/documentation/release-notes/11.05#GDB_monitor_experiment - 11.05] +and refined it in the subsequent releases +[https://genode.org/documentation/release-notes/12.02#GDB_monitor_refinements_and_automated_test - 12.02], +[https://genode.org/documentation/release-notes/13.11#GNU_Debugger - 13.11] (on-target GDB), and +[https://genode.org/documentation/release-notes/16.05#Enhanced_GDB_support_on_NOVA - 16.05] (supporting NOVA). +Despite these efforts, the feature remained rarely used in practice. +In most situations, manual instrumentation with debug messages or the use +of GDB with the Linux version of Genode remain to be the instruments of choice. +Driven by the vision of easy on-target debugging on Sculpt OS, we identified +the following limitations of the existing GDB monitor that stand in the way. + +# The GDB monitor supports only one component as debugging target, which makes + the debugging of scenarios where components closely interact difficult. + +# The existing implementation re-uses the gdbserver code and thereby inherits + many POSIX peculiarities that must be stubbed for Genode, yet make the + overall implementation complex. Genode is not POSIX after all. + +# The integration of the GDB monitor into an existing scenario is a fairly + invasive change that requires too much work. + +Given these limitations as a backdrop, two key ideas motivated a new approach +for the revision of Genode's GDB support for this release: + +First, by using Genode's sandbox API as foundation for a new debug monitor, +we would become able to use the monitor as drop-in replacement for 'init', +potentially going as far as using the monitor for Sculpt's runtime subsystem. +Wouldn't that approach vastly simplify the integration issue (3)? +Second, GDB supports the debugging of multiple processes (called inferiors) +within one session, which would in principle allow us to inspect and debug +component compositions, addressing the first limitation. +And third, the casual review of the documentation of the GDB protocol left +the impression that a Genode-tailored implementation shouldn't be that +complicated. + +The result of these ideas is the new *monitor* component at _os/src/monitor_ +as the designated successor of the traditional gdb_monitor. By leveraging the +sandbox API, it can be used as a drop-in replacement for the init component +and monitor multiple components. In real-world scenarios like Sculpt's +runtime, we deliberately want/need to restrict the debugging to a few selected +components, however, which calls for the support of a mix of monitored and +regular components hosted side by side. Given this requirement, the sandbox +API had to be enhanced to support the selective interception of PD and CPU +sessions. + +Like the original gdb_monitor, the new monitor speaks the GDB remote serial +protocol over Genode's terminal session. But the protocol implementation does +not re-use any gdbserver code, sidestepping the complexities of POSIX. +The monitor supports the essential GDB remote protocol commands for reading +and writing of memory and registers, for stopping and resuming of threads +including single-stepping, and it reports the occurrence of page faults and +exceptions to GDB. Breakpoints are managed by GDB using software breakpoint +instructions. The GDB protocol is operated in GDB's 'non-stop' mode, which +means that threads of multiple inferiors can be stopped and resumed +individually or in groups, depending on the GDB commands issued by the user. + +As of now, the monitor supports NOVA on 64-bit x86 as well as Genode's custom +base-hw kernel on 64-bit ARM and x86. The 64-bit ARM support required a change +in Genode's customized GDB port to enable shared-library support for this +architecture. So in order to use Genode's host GDB with the monitor on 64-bit +ARM, the Genode tool chain needs to be rebuilt with the _tool/tool_chain_ +script. + +There exist three run scripts illustrating the new component. The +_os/run/monitor.run_ script exercises memory inspection via the 'm' command +and memory modification via the 'M' command by letting a test program monitor +itself. The _os/run/monitor_gdb.run_ script performs automated tests of various +GDB commands and the _os/run/monitor_gdb_interactive.run_ script allows for the +interactive use of GDB to interact with monitored components. + +Details about the configuration of the monitor component are given by the +README file at the _os/src/monitor/_ directory. + + +Goa tool gets usability improvements and depot-index publishing support +####################################################################### + +Moving the Goa tool under the umbrella of Genode Labs in the previous release +unleashed a wave of substantial improvements. + +Most significantly, we were able to integrate support for depot-index projects +into Goa (Section [Support of index projects]). This greatly simplifies the +publishing of user-specific Goa projects for the upcoming Sculpt release. + +One of the game-changing features of Goa is its ability to easily test-run +applications on the host system leveraging Genode's ABI compatibility between +different kernels. However, in various instances, we still required customized +runtime scenarios in order to render an application runnable by Goa. With this +release, we further streamlined Goa's base-linux runtime with Sculpt OS +(Section [Run-stage generalization]). + +Apart from these major changes, the lately added shared-library support and +Rust support have seen practical improvements. + + +Support of index projects +========================= + +With an increasing number of Genode applications being developed with Goa, +being able to manage and publish a personal depot index with Goa became due. +In the past, we needed to build, export, and publish each individual Goa +project and manually add it to the depot index in order to make it available +for a particular Sculpt release. + +For this purpose, we added support for index projects to Goa. An index project +is defined by an 'index' file. This file follows the structure of a depot index +but only names the archive names (lacking depot user and version). The +'goa export' command augments these names with the current depot user and +version information. By running 'goa publish', the result is published as a +depot index for the current Sculpt version. + +As Goa supports a hierarchical project structure, an index project may +contain subdirectories with other Goa projects that provide the corresponding +pkg archives. The 'goa export' command issued within such an index project +recursively scans the working directory for any Goa project providing the +required depot archives or any of their dependencies, and exports these +subprojects as well. + +To make working with index projects an even more joyful experience, we changed +the way Goa looks up version information. Goa used to expect the current +version of each required depot archive to be specified in a goarc file. For +each Goa project, however, a 'version' file may be used to specify the current +version. This file was only evaluated on export of the particular project. +With this release, Goa now scans the working directory for Goa subprojects in +order to look up their 'version' file. This spares us keeping the 'version' +files and goarc files in sync. The new 'bump-version' command adds another +level of convenience as it automatically updates the 'version' file of a Goa +project. In combination with the '-r' switch, we are now able to update the +version information of all subprojects with a single command. + +An example of an index project is found at _examples/index_ in the Goa +repository. + +:Goa tool: + + [https://github.com/genodelabs/goa/] + + +Run-stage generalization +======================== + +In addition to building, exporting, and publishing of depot archives, Goa +supports test-running an application project directly on the development +system by utilizing base-linux. Similarly to how Goa modularized the build +stage to support various build systems, we generalized the run stage to pave +the way for other targets than base-linux. The interface of the generalized +run stage and the current feature set of the linux target is documented by +'goa help targets'. + +In the course of generalizing the run stage, we introduced various plausibility +checks to further accelerate application development. For instance, we check +for typos in required and provided services of a runtime, and verify the +availability of required ROM modules. + +Furthermore, the linux target underwent a major revision to streamline the +application development for Sculpt OS. + +* Scenarios using a terminal component require a fonts file system. + In Sculpt OS, this is typically provided by instantiating a fonts_fs + component. Doing the same in Goa lifts the need to wrap Goa-managed + Sculpt packages in a separate test project. + +* A route for the mesa_gpu_drv.lib.so ROM module was implicitly added when + a Gpu was required. For consistency with existing packages, we now require + the runtime file to mention the mesa_gpu_drv.lib.so ROM explicitly. + +* For NIC requirements, we used to take the label as the tap-device name to + which the NIC driver was bound. Since the 'label' attribute might be + evaluated differently by Sculpt OS, we introduced the 'tap_name' attribute + instead. For each distinct tap device, we now instantiate a pair of NIC + driver and NIC router. Each router uses a distinct subnet for its default + domain, starting at 10.0.10.0/24 and ending at 10.0.255.0/24. + +* The clipboard ROM and Report requirements are now routed to a report_rom + component. + +* Arbitrary ROM requirements are routed to an lx_fs component that provides + the files found in the project's _var/rom_ directory as individual ROM + modules. An example resides in _examples/external_rom_. Thanks to Pirmin + Duss for this useful contribution. + +* Remaining service requirements that are not handled otherwise will be routed + to a black-hole component. + + +Improved support for building shared libraries +============================================== + +Since release 23.02, we are able to +[https://genode.org/documentation/release-notes/23.02#Building_and_packaging_CMake-based_shared_libraries__via_Goa_ - build CMake-based shared libraries in Goa]. +In this release, this feature has seen a few improvements: + +* If available, Goa now calls 'make install' during build in order to install + artifacts into _/install_. For libraries, this typically also + installs include files into this directory. Having all include files in the + build directory is a prerequisite for extracting these as api artifacts + (see 'goa help api'). + +* We added support for publishing api archives. + +* 'goa export' now respects the 'common_var_dir' configuration variable and + '--common-var-dir' command-line option when exporting api archives. + +* We fixed an issue that resulted in large binaries when building shared + libraries with Goa. + + +Quality assurance and usability tweaks +====================================== + +Increasing our development efforts for the Goa tool demands means to catch +regressions early on. For this purpose, we added a basic testing facility, +which validates that our examples still work as expected. Note that we are +going to address automated testing for arbitrary Goa projects at some point in +the future. + +With this release, we changed the name of the '.goarc' files to 'goarc'. The +original intention of these files was to allow user-specific settings +analogously to, e.g., '.bashrc'. However, these files may contain arbitrary Tcl +code, thus having various '.goarc' files checked into git repositories, made +things a little bit too obscure because those files are hidden. When a user +clones a Git repo and invokes Goa commands, this code gets executed. Hence, it +is only fair to bring this code to the user's attention by not hiding it. + +In addition to all the aforementioned major changes, we added a couple of minor +usability tweaks: + +* We added 'goa help import' in order to document the syntax of the 'import' + file. + +* We added the 'goa depot-dir' command that allows initializing a custom depot + directory with the default depot users. + +* We added a 'goa run-dir' command that prepares the run directory without + actually running the scenario. This is helpful when the run time of 'goa run' + is automatically evaluated by external scripts since 'goa run-dir' may take a + while downloading the required depot archives. + +* We added the 'run_as' configuration variable and '--run-as' command-line + option. This allows changing the depot user from which 'goa run' downloads + the required archives. See 'goa help config' for more details. + + +Support for the mainline Rust toolchain +======================================= + +When we reintroduced Rust on Genode in the +[https://genode.org/documentation/release-notes/23.05#Initial_Rust_support - previous] +release, our implementation relied on a slightly adapted Rust toolchain to +work around missing support for versioned library symbols in our linker. With +this release, we are now able to use the mainline 'x86_64-unknown-freebsd' +target provided by Rust project, eliminating the need for a custom toolchain. + +On top of the streamlined Rust support, we created a Goa package for a popular +Rust command-line application, which will be published along with updated +system packages in the upcoming Sculpt release. + +For details on the mainline Rust toolchain support and the ported package, +take a look at the dedicated +[https://genodians.org/atopia/2023-08-24-enabling-the-upstream-rust-toolchain - blog post on Genodians.org]. + + +Base framework and OS-level infrastructure +########################################## + +Internal core and base-framework modernization +============================================== + +Genode's API received multiple rounds of modernization in the past years. But +some of the framework's deepest internals remained largely unchanged over that +time. Even though one can argue that mature and battle-tested code should +better not be disrupted, our programming practices are not carved in stone. +To make Genode's internal code a delight for reviewers, auditors, and future +maintainers, we revisited the following areas. + +Core's page-fault resolution code got reworked for improved clarity and +safety, by introducing dedicated result types, reducing the use of basic +types, choosing expressive names, and fostering constness. Along the way, we +introduced a number of 'print' hooks that greatly ease manual instrumentation +and streamlines diagnostic messages printed by core. Those messages no longer +appear when a user-level page-fault handler is registered for the faulted-at +region map. So the monitor component produces less noise on the attempt to +dump non-existing memory. + +Closely related to the page-fault handling, we tightened the distinction +between rx and rwx inside core by restricting 'Region_map::attach_executable' +to create read-only mappings, while offering the option to map the full rights +using a new 'attach_rwx' method. The 'attach_rwx' method is now used by the +dynamic linker to explicitly attach the linker area with full rwx rights. With +the old page-fault handling code, the execute flag was evaluated only for leaf +dataspaces, not for managed dataspaces while traversing region-map +hierarchies. With the new page-fault handling code, the execute bit is +downgraded to no-execute when passing a managed dataspace that is not attached +as executable. + +We ultimately removed the last traces of the global 'env_deprecated()' +interface that was still relied-on within core and parts of the base library. +Nowadays, we no longer use global accessors but generally employ +dependency-injection patterns. Since the 'env_deprecated()' interface is +closely related to initialization code, the startup code of core and regular +components got largely refactored, eliminating the reliance on global side +effects. As a collateral change, the legacy 'main' support for native Genode +component as well as the now-obsolete 'Entrypoint::schedule_suspend' mechanism +got removed. + + +API changes +=========== + +Register framework update +------------------------- + +The register framework has been updated to ease its use with '-Wconversion' +warnings enabled, which is the default for Genode components. +When reading from a bitfield, the new version returns the value in the +smallest possible integer type, not the register-access type. This way, +the user of the bitfield value can use appropriate types without the need for +casting. The update also replaces 'bool' access types with 'uint8_t' access +types. + +Thanks to this change, the net lib - used by Genode's low-level network +routing components for parsing protocol headers via the register API - has +been made compliant to strict conversion warnings. + + +Hex-dump utility +---------------- + +To aid the monitoring, implementation, and debugging of binary protocols, a +handy hex-dump utility got added to _util/formatted_output.h_. The new +'Genode::Hex_dump' class can be used to print a hexadecimal dump of a byte +range. The data is printed in a format similar to that used by the 'xxd' +utility. In addition to the 'xxd' format, consecutive duplicate lines are +replaced with a single "*\n". + + +Libraries and applications +########################## + +New NIC server for raw uplink connectivity +========================================== + +With Genode +[https://genode.org/documentation/release-notes/21.02#Pluggable_network_device_drivers - 21.02], +we transitioned all network device drivers to act as session clients in order +to make them pluggable. We achieved this by introducing a new _uplink_ service +interface that is very similar to the NIC service but with the peer roles +switched. Up to now, the only uplink server and uplink-to-NIC adapter was the +NIC router. This is reasonable as it is the standard network multiplexer in +Genode and therefore normally sits in front of each network device driver +anyway. However, there is one major issue with this approach: It binds +physical network access to layer 3 and 4 routing respectively layer 2 +multiplexing, which, in our case, means that NIC clients can talk to the +physical network only with what is protocol-wise supported by the NIC router. + +That's why Genode 23.08 introduces the new NIC-uplink adapter component. It +re-enables raw access to physical networks in Genode by forwarding packets +unmodified and unfiltered between multiple NIC sessions and one uplink +session. The new component is accompanied by a test script _nic_uplink.run_ +that demonstrates the low-level integration and a Sculpt package _pkg/pc_nic_ +that can be used for deployment in more sophisticated systems together with +the PC NIC-driver as back end. + +One constellation, in which the NIC-uplink server will be especially useful for +us is the planned enablement of IPv6 on different layers of Genode's network +stack. More specifically, the tool will allow us to work at IPv6 support in +both Genode's ported TCP/IP stacks and the NIC router at the same time. + + +New depot-remove component +========================== + +_The work described in this section was contributed by Alice Domage._ +_Thanks for this welcome addition._ + +Genode's on-target package management allows for the installation of multiple +versions of the same package side by side, which is useful to roll back the +system to an earlier state, or to accommodate software depending on an older +library version. Software is installed into the so-called _depot_ stored on +the target and populated with downloads on demand. Until now, however, the +on-target depot could only grow, not shrink. Even though this limitation +hasn't been a pressing concern for Sculpt OS on the PC, it impeded embedded +use cases. + +The new depot-remove component lifts this limitation by providing an orderly +way to remove depot content and orphaned dependencies. It operates by reading +its configuration and processes delete operations based on the provided rules. +A typical configuration looks as follows. + +! +! +! +! +! +! +! + +For more details about the configuration options, please refer to the README +file at _/gems/src/app/depot_remove/_. Furthermore, the +_gems/run/depot_remove.run_ script illustrates the component by exercising +several practical use cases. + + +DDE-Linux changes +================= + +With this release, we changed how external events are treated within the +Linux emulation environment. + +Whenever an external event occurred, for example timer or interrupt, the +corresponding I/O signal handler was triggered. This handler unblocked the +task waiting for the event and also initiated the immediate execution of all +unblocked tasks. This, however, could lead to nested execution because these +tasks might hit serialization points, e.g., synchronously waiting for packet +stream operations, that under the hood also require handling of other I/O +signals. Such an execution model is not supported and confusing as it mixes +application and I/O level signal handling. + +So the flagging of the scheduling intent is now decoupled from its execution by +using an application-level signal handler that is run in the context of the +component's main entrypoint. The I/O signal handler now triggers the scheduling +execution by sending a local signal to the EP and only flags the occurrence +of the external event by unblocking the corresponding task. +In this context, we reworked the interrupt handling itself. Previously all +interrupts were immediately processed in the I/O signal handler and only the +currently pending one was handled. Due to the decoupling change the occurrence +of interrupts becomes merely flagging a state and requires recording all +interrupts and dispatch them consecutively in one go. + +To facilitate this convention, the Lx_kit initialization function got extended, +and it is now necessary to pass in a signal handler that is used to perform the +normally occurring scheduler execution. As this signal handler is part of +the main object of the DDE-Linux based component it is the natural place to +perform any additional steps that are required by the component before or after +executing the scheduler. + +As it is sometimes necessary to execute a pending schedule from the EP directly, +in case the scheduler is called from within an RPC function, the scheduler is +extended with the 'execute' member function that performs the check that the +scheduler is called from within the EP and triggers the execution afterwards. + + +Tresor block encryptor +====================== + +Following the introduction of the tresor library in the +[https://genode.org/documentation/release-notes/23.05#Revision_of_Genode_s_custom_block-encryption_infrastructure - previous] +release, we further polished the tresor tester in order to make it run on a +broad spectrum of target platforms. For instance, the test can now be run +without entropy input (permanently warning the user about the security risk) +because some of our test hardware lacks support for it. Besides that, we +mainly worked at the resource consumption of the test - made it more adaptable +or reduced it through improvements. This pleased not only less powerful +hardware but our test management as well. + +Furthermore, we fixed a significant former deficiency with the tresor library. +The library used to work on the raw on-disc data without decoding first. This +worked fine for some platforms but caused alignment faults on others. That +said, the tresor library now always decodes into naturally typed and aligned +C++ structs before accessing the data. + + +Device drivers +############## + +Intel GPU +========= + +The handling of GPUs is somewhat special within the driver world. A GPU is a +standalone execution unit that can be programmed much like a CPU. In the past, +there were fixed function GPUs, which have been gradually replaced by +dynamically programmable units that execute compiled machine code (think +shader compilers like GLSL or general purpose computing like CUDA or OpenCL). +This leads to a situation where a GPU driver cannot trust the client that +sends its machine code to be executed by the GPU. There exists no sufficient +way of inspecting the compiled machine code for malicious behavior by the GPU +driver. Therefore, the only reasonable solution for a GPU driver is to send +the code to the GPU and hope for the best. In case the code execution is not +successful, GPUs tend to just hang and the only thing a driver can do is to +make sure via an IOMMU that the code does not access arbitrary memory and +program a watchdog timer and reset the GPU to a graceful state in case there +is no proper response. With the current Genode release, we have implemented +this behavior for GEN9 (HD graphics) and GEN12 (Intel Iris Xe). + + +Intel display +============= + +The ported Linux Intel display driver now supports USB Type-C connectors as +used with modern notebooks. + + +New PC network driver based on DDE-Linux +======================================== + +Since 2010, we use Ethernet drivers ported from the iPXE project in a tiny +emulation layer on Genode. While those drivers did a good job for the common +cases, they always had some rough edges that may not hurt in the original +network-booting use case but had become a nuisance in Sculpt OS and Genode +in general. Most prominently the dropped link speed with Intel E1000e cards +on cable unplug/plug and the moderate throughput on GBit links had to be +addressed. + +Our new DDE Linux approach introduced this year makes the porting of drivers +from the Linux kernel much easier and less labour-intensive as in the past. +Also, Linux is a very tempting Ethernet driver donor because of the variety +of supported devices and the well known excellent performance (especially on +Intel devices). Moreover, the Intel E1000e driver addresses all issues we +had with the iPXE implementation and promises a smooth interplay with Intel +AMT/ME. Note, Intel AMT Serial-over-LAN is still an important debug console +while deploying Genode on Intel-based notebooks. + +Hence, the current release brings the new _pc_nic_drv_ for Intel e1000/e1000e, +Realtek 8169, and AMD PCnet32 (Qemu) devices on PC and is fully integrated +into Sculpt OS. Performance-wise the driver easily saturates 1 GBit links in +our throughput tests. + + +USB host controller +=================== + +The USB host controller driver ports for Raspberry Pi 1 and i.MX 6 Quad got +updated to Linux kernel version 6.1.37 resp. 6.1.20. Both driver ports share +the renewed device-driver environment approach for Linux introduced in release +[https://genode.org/documentation/release-notes/21.08#Linux-device-driver_environment_re-imagined - 21.08]. + +Besides the update of the last remaining outdated USB host controller drivers, +we have reworked the common C/C++ Linux-to-Genode USB back end used by all USB +host controller driver incarnations. The internal changes were necessary to +address issues regarding races during USB session close attempts, resets of +USB endpoints, and potential stalls during synchronous USB RPC calls. + + +PC audio refinements +==================== + +In this release, we simplified the memory allocator in the OpenBSD-based +audio-driver component and thereby decreased its memory usage. The memory +subsystem implementation was initially brought over from DDE Linux and is +geared towards use cases where a high-performing allocator is desired. For the +audio driver with its clear memory usage pattern, such an allocator is not +necessary and since no other driver that could benefit from it was ported in +the meantime, we opted for replacing the implementation with a simpler one +with less overhead. + +We also adapted the mixer state report mechanism to always generate a new +report on head-phone jack sense events. + +Furthermore, we decreased the internal buffer size to implicitly limit the +number of blocks provisioned for recording that brings them in line with the +number of blocks used for playback (2). + + +Wifi +==== + +With the [DDE-Linux changes] in place, we had to adapt the initialization +procedure in the wireless LAN driver since it behaves differently to all other +DDE-Linux-based driver components. The driver is actually a 'Libc::Component' +due to its incorporation of the 'wpa_spplicant' application and the driver +itself is confined to its own shared-object to better separate the Linux code. + +Since we implement the Linux initcalls as static constructors, we have to +initialize the Lx_kit before those are executed. This is normally not a +problem because they are executed manually from within the drivers main object +on construction. However, in a 'Libc::Component' this happens before our main +object is constructed. In the past, we used a VFS plugin to perform the +initialization - as the VFS is also constructed beforehand - but this is no +longer possible as the driver's main signal handler that now dispatches the +Lx_kit event signals is not available at this point. + +We decided therefore to perform a multi-staged boot-up process where the +component is now implemented as regular 'Genode::Component' that triggers the +'Libc::Component' construction manually after performing the Lx_kit +initialization. This change enabled us to remove the VFS 'wifi' plugin that no +longer has to be specified in the VFS configuration. + +Furthermore, we removed the handcrafted MAC address reporter in favor of the +Genode C API utility that was recently made available. + + +PinePhone support for buttons and screensaver +============================================= + +To equip the mobile version of Sculpt OS on the PinePhone with a proper +screensaver, we added drivers for detecting user interactions with the +PinePhone's physical buttons, namely the volume buttons and the power button. + +The volume buttons are connected via cascaded resistors to a single ADC of the +A64 SoC. The corresponding driver has been added to the genode-allwinner +repository at _src/drivers/button/pinephone/_ and is accompanied by the +_button_pinephone.run_ script. It reports KEY_VOLUMEUP and KEY_VOLUMEDOWN +input events to an event session. + +Sensing the power button has been a slightly more delicate issue because the +power button is connected to the power-management IC (PMIC), which shall only +be accessed via the system-control processor (SCP). To detect state changes, +the PMIC's IRQ (routed through the R_INTC to the GIC) is now handled by the +power driver. This has the added benefit that also other interesting PMIC +events (like connecting AC) get immediately reported. + +With the button drivers in place, we finally equipped Sculpt OS with a +screensaver as a crucial battery-conserving feature. The screensaver kicks in +after the user remained inactive in the administrative user interface for some +time. It also can be manually activated by pressing the power button. While +the screen is blanked, a press of the power button enables the display again. + +Under the hood, Sculpt completely removes the drivers for the display and the +touchscreen while the screen is blanked, which considerably reduces the power +draw. The system also switches the CPU to economic mode while the screen is +blanked. Here are some illustrative data points: + +! Max brightness in performance mode: 2.8 W +! Max brightness in economic mode: 2.6 W +! Low brightness in economic mode: 1.7 W +! Screensaver: 1.1 W + +You can find the screensaver feature integrated in the latest mobile Sculpt OS +images published by _nfeske_. + + +Platforms +######### + +NXP i.MX SoC family +=================== + +Certain parts of i.MX specific code, like the base support for the hw kernel, +and the GPIO driver for i.MX got moved from Genode's main repository to the +corresponding genode-imx repository. + +Sculpt OS image creation for MNT Reform2 +---------------------------------------- + +With this release, we introduce mainline support for Sculpt OS on the MNT +Reform2. To build a Sculpt OS image for this board you can use the common +_gems/run/sculpt_image.run_ script, like the following: + +! make run/sculpt_image KERNEL=hw BOARD=mnt_reform2 DEPOT=omit + +To be effective, you need to extend your RUN_OPT variable accordingly: + +! RUN_OPT += --include image/imx8mq_mmc + + +seL4 microkernel +================ + +With the update of the seL4 kernel in the +[https://genode.org/documentation/release-notes/23.05#Updated_seL4_microkernel - previous] +release we now added several improvements, which reduce the boot-up time of +Genode's 'core' roottask on seL4 by converting untyped memory to I/O memory on +demand. + + +Build system and tools +###################### + +Depot autopilot on-target test orchestrator +=========================================== + +As the rough plan to support automated testing in Goa is shaping up, it makes +sense to share one convention about expressing the success criteria for a +package under test between the depot autopilot and Goa. This prospect motivated +us to review the convention that was used with the depot autopilot up until +now. The old syntax looked as follows: + +! +! +! +! +! [init -> rom_logger] ROM 'generated':* +! [init -> dynamic_rom] xray: change (finished) +! +! child exited +! Error: +! +! ... +! + +We applied the following simplifications to this syntax: +* Dropped the intermediate '' tag, +* Replaced '' by '', +* Replaced '' by '', +* Replaced '' by an 'after_seconds' + attribute of the '' or '' tags. + +So, the above example becomes the following: +! +! +! +! [init -> rom_logger] ROM 'generated':* +! [init -> dynamic_rom] xray: change (finished) +! +! child exited +! Error: +! ... +! + +For now, the depot autopilot maintains backwards-compatibility to allow Genode +users to adapt to the change progressively. The old scheme is used whenever +the package runtime contains an '' tag. Note that backwards +compatibility will be removed after a short transition period. +All test packages of the official Genode repositories have been updated +to the new convention. + +Furthermore, we took the opportunity to also add a new feature. The optional +'log_prefix' attribute in the '' and '' tags is a simple but +handy white-list filter when it comes to typical Genode logs. When matching +the test log against the pattern given in the affected '' or '' +tag, the depot autopilot considers only those log lines that start with the +given prefix. This is an easy way to watch only specific Genode components and +solve problems with the log order of simultaneously running components. + +Last but not least, the transition prompted us to fix a minor issue with the +depot autopilot log-processing. Color sequences will now be forwarded correctly +from the test runtime to the log output of the depot autopilot, making the +analysis of test batteries a more pleasant experience. + + +Updated run-tool defaults for x86_64 +==================================== + +With the update of the seL4 kernel and the update of the toolchain to GNU GCC +12 in the previous release, certain x86 assembly instructions like POPCNT are +generated, which are not supported by the Qemu CPU models we used. +Previously, the used CPU model was either the default model, or +'-cpu core2duo' for NOVA, or '-cpu phenom' for SVM virtualization. +The current release changes the default model to '-cpu Nehalem-v2', and +selects '-cpu EPYC' for SVM virtualization. + +Note that the _build.conf_ file in the x86 build directory must be +re-generated by you, which otherwise may contain an older Qemu "-cpu " model, +which can collide with the new default Qemu CPU settings. diff --git a/doc/release_notes/23-11.txt b/doc/release_notes/23-11.txt new file mode 100644 index 0000000000..8ff6003b64 --- /dev/null +++ b/doc/release_notes/23-11.txt @@ -0,0 +1,799 @@ + + + =============================================== + Release notes for the Genode OS Framework 23.11 + =============================================== + + Genode Labs + + + +Genode 23.11 brings a healthy mix of OS architectural work, curation of the +existing framework, and new features. In an arguably radical move - but in +perfect alignment with microkernel philosophy - we move the IOMMU driver from +the kernel to user space. This way, Genode attains DMA protection independent +of the used kernel. Section [Kernel-agnostic DMA protection] covers the +background and implementation of this novel approach. + +We constantly re-evaluate our existing code base for opportunities of curation +and simplification and the current release is no exception. It bears the fruit +of an intense one-year cross-examination of Genode's existing virtualization +interfaces across CPU architectures and kernels, as a collateral effort of +bringing x86 virtualization to our custom base-hw microkernel. Section +[Modernized virtualization interface] presents the story and outcome of this +deep dive. + +As another curation effort, the release brings Genode's arsenal of USB device +drivers in line with our modern DDE Linux porting approach. +Section [USB device drivers updated to Linux 6.1.20] details this line of work. + +Feature-wise, the release contains the underpinnings of the CPU +frequency/temperature/power monitoring and control feature of the latest +Sculpt OS release +(Section [PC power, frequency, temperature sensing and control]), +showcases the port of the Linphone VoIP stack using the Goa tool +(Section [Ported 3rd-party software]), and equips the Seoul virtual machine +monitor with the ability to host 64-bit guests +(Section [Seoul virtual machine monitor]). + + +Kernel-agnostic DMA protection +############################## + +On our quest towards a PC version of Sculpt OS on our custom (base-hw) +microkernel, we were able to move an essential chunk away to clear another +section of the path. Based on the preparatory changes to the platform driver +regarding IOMMU handling introduced in +[https://genode.org/documentation/release-notes/23.05#Towards_kernel-agnostic_DMA_protection - release 23.05], +we were able to enable kernel-agnostic DMA protection on Intel platforms. + +Similar to how the MMU protects the system against unintended CPU-initiated +memory transactions, the IOMMU protects the system against unintended DMA +transactions. Since components allocate DMA buffers via the platform driver, +the latter sits in the perfect spot to manage DMA remapping tables for its +clients and let the IOMMU know about them. + +[image dma_remap] + +The figure above illustrates how we added remapping to the PC version of +Sculpt OS. IOMMUs are announced in the ACPI DMAR table, which is parsed by our +ACPI driver component. +It particularly evaluates the _DMA Remapping Hardware Unit Defintions_ (DRHDs) +and _Reserved Memory Region Reporting_ (RMRRs) structures and reports the +essential details in form of an _acpi_ report. There are typically multiple +DRHDs with different device scopes. The RMRRs specify memory regions that may +be DMA targets for certain devices. + +The _acpi_ report is used by our PCI decode component, which creates a +_devices_ report. It adds the DRHDs as devices to this report and annotates +the found PCI devices with corresponding '' nodes +according to the DRHDs' device scopes. Moreover, it adds +'' nodes to the particular devices as specified by the +RMRRs. + +By evaluating the _devices_ report, the platform driver has a complete picture +of the DMA remapping hardware units and knows about which PCI devices fall +into their scopes. It takes control over the mentioned _drhdX_ devices on its +own and sets up the necessary structures that are shared between all sessions +and devices. For every Platform session and _drhdX_ device used, it creates an +'Io_mmu::Domain' object that comprises a DMA remapping table. As shown in the +figure, Client A, which acquires devices in the scope of drhd0 and drhd1, the +platform driver sets up two DMA remapping tables. The tables are populated with +the DMA buffers allocated via Client A's platform session. For every acquired +device, the platform driver maps the corresponding remapping table. Note that +DMA buffers are allocated on a per-session basis so that all devices in the +same session will get access to all DMA buffers. To further restrict this, +Client A could open separate platform sessions for distinct DMA-capable +devices. + +A subtle implementation detail (not shown in the figure) concerns the +aforementioned reserved memory. The reserved memory regions of a device must +be added to the corresponding DMA remapping table. Moreover, these regions +must be accessible at all times, i.e. even before the device is acquired by +any client. For this purpose, the platform driver creates a default remapping +table. This table is filled with the reserved memory regions and mapped for +every unused device that requires access to any reserved memory region. + +A particular benefit of moving DMA remapping into the platform driver (apart +from becoming kernel-agnostic) is that DMA remapping tables are now properly +allocated from the session's quota. In consequence, this may increase the RAM +and capability requirements for certain drivers. + +The platform driver's support for Intel IOMMUs is enabled by default on the +NOVA and base-hw kernels. The seL4 and Fiasco.OC kernels are not yet covered. +Nevertheless, we also kept NOVA's IOMMU enablement intact for the following +reasons: + +* To protect the boot-up process from DMA attacks, the IOMMU should be enabled + as early as possible. The platform driver simply takes over control when it + is ready. + +* The platform driver is not (yet) able to manage interrupt remapping because + this requires access to the _I/O Advanced Programmable Interrupt Controller_ + (IOAPIC) controlled by the kernel. Thus, in this release, we still let NOVA + manage the interrupt remapping table. + +* As we have not implemented support for AMD IOMMUs yet, we simply keep NOVA + in charge of this. If there is no Intel IOMMU present, the platform driver + falls back to the device PD for controlling the kernel-managed IOMMU. + +Along with the DMA remapping support, we added an _iommu_ report to the +platform driver. On the PC version of Sculpt OS, this is enabled by default +and routed to _/report/drivers/iommu_. The report summarizes the state of each +DRHD. When the platform driver takes control, it also logs a message like +"enabled IOMMU drhd0 with default mappings". The platform driver can be +prevented from touching the IOMMU by removing the DRHD info from the _acpi_ +report. This can be achieved by supplying the ACPI driver with the following +config: + +! + +_Note that the ACPI driver does not handle configuration updates._ + +Orthogonal to the DMA remapping support, we changed the allocation policy for +DMA buffers in the generic part of the platform driver. The new policy leaves +an unmapped page (guard page) between DMA buffers in the virtual I/O memory +space. This ensures that a simple DMA buffer overflow does not corrupt other +DMA buffers. Since this is only a matter of virtual address allocation, it +does not add any additional RAM costs. + + +Base framework and OS-level infrastructure +########################################## + +PC power, frequency, temperature sensing and control +==================================================== + +PC CPU vendors provide various CPU features for the operating system to +influence frequency and power consumption, like Intel HWP or AMD pstate to +name just two of them. Some of the features require access to various MSR CPU +registers, which can solely be accessed by privileged rdmsr and wrmsr +instructions. + +Up to now, this feature was provided in a static manner, namely before Genode +boots. It was possible to set a fixed desired target power consumption via the +pre-boot chain loader bender. This feature got introduced with +[https://genode.org/documentation/release-notes/20.11#Hardware_P-State_support_on_PC_hardware - Genode version 20.11] +and was refined in +[https://genode.org/documentation/release-notes/22.11#Configurable_Intel_HWP_mode - version 22.11]. + +Another and desired approach is to permit the adjustment of the desired power +consumption depending on the current load of the system. This dynamic way of +power and frequency management has been in casual development since 2021 and +first got presented in one [https://genodians.org/alex-ab/2023-05-29-freq_power - sneak peak] +Genodian article. The feature now found its way into the +[https://genodians.org/alex-ab/2023-10-23-msr - Sculpt 23.10] release. + +With the current Genode release, we have added general support to the +framework that permits guarded access to selected MSRs via Genode's +system-control RPC of the protection domain (PD) session. If the underlying +kernel supports this feature, presently the NOVA kernel, read and write +requests are forwarded via Genode's 'core' roottask to the kernel. A component +needs the explicit [https://genode.org/documentation/release-notes/22.02#Restricting_physical_memory_information_to_device_drivers_only - managing_system] configuration role to get +access to this functionality, which is denied by default. + +The actual knowledge about how to manage Intel HWP and AMD pstate is provided +as a native Genode component, which uses the new 'Pd::system_control' +interface. The component monitors and reports changes of MSR registers for +temperature (Intel), frequency (AMD & Intel), and power consumption (Intel +RAPL). Additionally, it can be instructed - by the means of configuration +changes - to write some of the registers. Besides the low-level MSR component, +a Genode package with a GUI component is provided to make the interactive +usage of the feature more user-friendly. For Sculpt, we added an interactive +dialog to assign the system-control role to a component like the graphical MSR +package via the resource dialog. For a more detailed description please refer +to our [https://genodians.org/alex-ab/2023-10-23-msr - Genodians article] +for the Sculpt 23.10 release. + + +Modernized virtualization interface +=================================== + +When we introduced the +[https://genode.org/documentation/release-notes/19.05#Kernel-agnostic_virtual-machine_monitors - generic Virtual Machine Monitor (VMM) interface] +for x86 virtualization with Genode +[https://genode.org/documentation/release-notes/19.05#Kernel-agnostic_virtual-machine_monitors - version 19.05], +it was largely modeled after our Genode VMM API for ARM with the following +characteristics. + +* A vCPU's state could be requested, evaluated, and modified with the + 'state()' method. + +* The vCPU was started by the 'run()' method. + +* For synchronization, the vCPU could be stopped with the 'pause()' method. + +However, this ostensibly uniform interface for ARM and x86 virtualization +obscures two significant differences between the architectures. + +:Hardware and generic vCPU state: + +On ARM, the VMM directly handles the hardware virtualization state, i.e., the +vCPU state is directly passed to the VMM. In contrast, what is passed to the +VMM on x86 is a generic _Vcpu_state_. This is due to two aspects of x86 +virtualization: First, there are two competing implementations of +virtualization on x86: AMD's _Secure Virtual Machine (SVM)_ / _AMD-V_ and +Intel's _Virtual Machine Extensions (VMX)_. Second, neither interface lends +itself to passing the vCPU state directly to the VMM: VMX requires privileged +instructions to access fields in the _Virtual Machine Control Structure +(VMCS)_. Whereas SVM supports direct access to fields in its _Virtual Machine +Control Block (VMCB)_, the VMCB (as well as the VMCS) does not represent the +whole state of the vCPU. Notably, both the VMCS and the VMCB do not include +the CPU's general purpose registers, thereby warranting a separate data +structure to synchronize the vCPU state with a VMM. + +:vCPU pause and state synchronization: + +On ARM, the 'pause()' method simply stopped the vCPU kernel thread from being +scheduled. Since the VMM's vCPU handler runs on the same CPU core we could be +certain that the vCPU was not running while the VMM's vCPU handler was +executing, and calling 'pause()' made sure the vCPU wasn't rescheduled while +the VMM was modifying its state. In contrast, calling 'pause()' on x86 has +different semantics. It requests a synchronization point from the hypervisor, +which responds by issuing a generic _PAUSE_ or _RECALL_ exit in order to +signal the VMM that state can be injected into the vCPU. The mechanism is +woven deeply into the device models of our x86 VMMs, and therefore +asynchronous state synchronization from the VMM needed to be available in the +VMM. + + +API shortcomings and improvements +--------------------------------- + +On ARM, making the hardware vCPU state unconditionally available to the VMM via +the 'state()' method meant that the API did not enforce any synchronization +between hypervisor / hardware and VMM accesses to the vCPU state. On x86, the +asynchronous semantics of the 'pause()' method required complex state tracking +on the hypervisor side of the interface. + +To address both shortcomings, we replaced the previous API with a single +'with_state()' method that takes a lambda function as an argument. The method +allows scoped access to the vCPU's state and ensures that the vCPU is stopped +before calling the supplied lambda function with the vCPU as parameter. Only +if the lambda function returns 'true', the vCPU is resumed with its state +updated by the VMM. Otherwise, the vCPU remains stopped. + +As a result, the API enforces that the vCPU state is only accessed while the +vCPU is not running. Moreover, we were able to replace the ambiguous 'pause()' +method by a generic mechanism that unblocks the vCPU handler, which in turn +uses the 'with_state()' method to update the vCPU state. Finally, resuming of +the vCPU is controlled by the return value of the lambda function exclusively +and, thus, removes the error-prone explicit 'run()' method. + + +Porting hypervisors and VMMs +---------------------------- + +The new API was first implemented for *base-hw*'s using AMD's SVM +virtualization method and recently +[https://genode.org/documentation/release-notes/23.05#Base-HW_microkernel - introduced] +as part of the 23.05 release. The reduction of complexity was significant: +explicitly requesting the vCPU state via 'with_state()' did away with a vast +amount of vCPU-state tracking in the kernel. Instead, the VMM library +explicitly requests updates to the vCPU state. + +With the first hypervisor ported, we were curious to see how easily our new +interface could be applied to the *NOVA* hypervisor. The initial pleasant +reduction of complex state handling in base-nova's VMM library was closely +followed by the insight that there was no way to match the NOVA-specific +execution model to our new library interface. The asynchronous nature of the +'with_state()' interface meant that we needed a way to synchronize the vCPU +state with the VMM that could be initiated from the VMM. Since NOVA's +execution model is based on the hypervisor calling into the VMM on VM exits, +we had to extend NOVA's system call interface to allow for an explicit setting +and getting of the vCPU state. This was needed because the 'with_state()' +interface requires that the vCPU state is made available to the caller within +the method call, so the old model of requesting a _RECALL_ exit that would be +processed asynchronously couldn't be used here. For the same reason, the vCPU +exit reason had to be passed with the rest of the vCPU state in the UTCB since +in this case this information wasn't provided through the VMM portal called +from the hypervisor. The new 'ec_ctrl' system call variants proved to be a +simple addition and allowed us to adapt to the new interface while still using +NOVA's execution model for processing regular exits. + +The _blocking system call into the hypervisor_ execution model of *Fiasco.OC* +and *seL4* offered its own unique set of challenges to the new library +interface in the interplay between asynchronous 'with_state()' triggers and +the synchronous vCPU run loop. Fortunately, we were able to meet these +challenges without changing the kernels. + +While adapting our VMMs for ARM and x86, we found varying degrees of +dependency on permanently accessible vCPU state, which we resolved by +refactoring the implementations. As a result, the new interface is already +used since the release of +[https://genode.org/documentation/articles/sculpt-23-10 - Sculpt OS 23.10]. +We haven't experienced any runtime vCPU state access violations and can now be +certain that there aren't any silent concurrent accesses to the vCPU state. + +All in all, the new VMM library interface has succeeded in reducing complexity +while providing a more robust access to the vCPU state, which is shared +between our various hypervisors and VMMs. + + +Dialog API for low-complexity interactive applications +====================================================== + +Since version +[https://genode.org/documentation/release-notes/14.11#New_menu_view_application - 14.11], +Genode features a custom UI widget renderer in the form of a stand-alone +component called _menu view_. It was designated for use cases where the +complexity of commodity GUI tool kits like Qt is unwanted. Menu-view-based +applications merely consume hover reports and produce dialog descriptions as +XML. In contrast to GUI toolkit libraries, the widget rendering happens +outside the address space of the application. + +Today, this custom widget renderer is used by a number of simple interactive +Genode applications, the most prominent being the administrative user +interface of Sculpt OS. Other examples are the touch keyboard, file vault, +text area, and interactive +[https://genodians.org/alex-ab/2023-10-23-msr - system monitoring tools]. + +In each application, the XML processing used to be implemented via a rather +ad-hoc-designed set of utilities. These utilities and patterns started to get +in the way when applications become more complex - as we experienced while +crafting the +[https://genodians.org/nfeske/2023-01-05-mobile-user-interface - mobile variant] +of Sculpt OS. These observations prompted us to formalize the implementation +of menu-view based applications through a new light-weight framework called +dialog API. The key ideas are as follows. + +First, applications are to be relieved from the technicalities of driving a +sandboxed menu-view component, or the distinction of touch from pointer-based +input, or the hovering of GUI elements. These concerns are to be covered by +a runtime library. The application developer can thereby focus solely on the +application logic, the UI representation (view) of its internal state (model), +and the response to user interaction (controller). + +Second, the dialog API promotes an immediate translation of the application's +internal state to its UI representation without the need to create an object +for each GUI element. The application merely provides a 'view' (const) method +that is tasked to generate a view of the application's state. This approach +yields itself to the realization of dynamic user interfaces needing dynamic +memory allocation inside the application. +The 'view' method operates on a so-called 'Scope', which loosely corresponds +to Genode's 'Xml_generator', but it expresses the generated structure using +C++ types, not strings. A scope can host sub scopes similar to how an XML node +can host child nodes. Hence, the _view_ method expresses the application's +view as a composition of scopes such as frames, labels, vbox, or hbox. + +Third, user interaction is induced into the application by three callbacks +'click', 'clack', and 'drag', each taking a location as argument. The location +is not merely a position but entails the structural location of the user +interaction within the dialog. For interpreting of the location, the +application uses the same C++ types as for generating the view. Hence, the C++ +type system is leveraged to attain the consistency between the view and the +controller, so to speak. + +Fourth, structural UI patterns - made out of nested scopes - can be combined +into reusable building blocks called widgets. In contrast to scopes, widgets +can have state. Widgets can host other widgets, and thereby allow for the +implementation of higher-level GUI parts out of lower-level elements. + +The API resides at _gems/include/dialog/_ and is accompanied by the dialog +library that implements the runtime needed for the interplay with the +menu-view widget renderer. Note that it is specifically designed for the needs +of Sculpt's UI and similar bare-bones utilities. It is not intended to become +a desktop-grade general-purpose widget set. For example, complex topics like +multi-language support are decidedly out of scope. During the release cycle, +the administrative user interface of Sculpt OS - for both the desktop and +mobile variants - has been converted to the new API. Also, the text-area +application and the touch keyboard are using the new API now. + +Given that the new API has been confronted with the variety of use cases found +in Sculpt's administrative user interface, it can now be considered for other +basic applications. Since we target Genode-internal use for now, proper +documentation is still missing. However, for the curious, an illustrative +example can be found at _gems/src/test/dialog/_ accompanied by a corresponding +_dialog.run_ script. For a real-world application, you may consider studying +the _app/sculpt_manager/view/_ sub directory of the gems repository. + + +API changes +=========== + +Simplified list-model utility +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The so-called 'List_model' utility located at _base/include/list_model.h_ has +become an established pattern used by Genode components that need to maintain +an internal data model for XML input data. It is particularly useful whenever +XML data changes over time, in particular when reconfiguring a component at +runtime. + +The original utility as introduced in version +[https://genode.org/documentation/release-notes/18.02#API_changes - 18.02] +relied on a policy-based programming pattern, which is more ceremonial than it +needs to be, especially with recent versions of C++. The current release +replaces the original policy-based 'update_from_xml' by a new method that +takes three functors for creating, destroying, and updating elements as +arguments. XML nodes are associated with their corresponding internal data +models by annotating the element type with the 'type_matches' class function +and the 'matches' method. + +Besides the interface change, two minor aspects are worth noting. First, to +improve safety, list model elements can no longer be copied. Second, to foster +consistency with other parts of Genode's API, the 'apply_first' method has +been renamed to 'with_first'. + + +Pruned IRQ-session arguments +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +So far, we have used the 'device_config_phys' argument of the IRQ session to +implicitly request the use of _Message-Signalled Interrupts_ (MSI) to core. +This argument specifies the address to the PCI configuration space. However, +with the addition of Intel IOMMU support to the platform driver, we encountered +an instance where we need an MSI for a non-PCI device in order to receive fault +IRQs from the IOMMU. We therefore added an 'irq_type' argument to the IRQ +session, which allows the explicit specification of whether a LEGACY interrupt +or an MSI is requested. + +Yet, as we exceeded the character limit by adding another argument, we pruned +the IRQ-session arguments: Since 'device_config_phys' is not relevant for +LEGACY interrupts, we removed this from the default _Irq_connection_ +constructor. We further added an alternative constructor for MSI, which sets +'device_config_phys' but omits the 'irq_trigger' and 'irq_polarity' arguments. + + +Libraries and applications +########################## + +Seoul virtual machine monitor +============================= + +The Seoul/Vancouver VMM - introduced to Genode with release 11.11 - is an +experimental x86-based VMM which runs on Genode@NOVA, Genode@seL4, and +Genode@Fiasco.OC, and Genode@hw on Intel and on AMD hardware. It has been up +to now solely used with 32-bit and special crafted VMs. With the addition of +[https://genode.org/documentation/release-notes/22.11#Seoul_VMM - VirtIO support] +for GPU, input, and audio, the usage as specialized tailored +[https://genodians.org/alex-ab/2023-05-09-seoul-23-04 - disposable VMs] became +quite comfortable. + +However, time is ticking for 32bit on x86 and some features aren't provided in +the same quality as for 64bit VMs. For example, when using Firefox on 32bit, +the video playback on some webpages gets denied while functioning on 64bit +without complaints. So, the time came to extend the Seoul VMM by 64bit guest +support to make it fit for today and avoid further hassles. + +Over the year 2023, the Seoul VMM got extended by enabling the instruction +emulator - called Halifax - to decode +[https://wiki.osdev.org/X86-64_Instruction_Encoding - x86_64 instructions] +with additional prefixes and additional 8 general purpose registers. Besides +the necessary deep dive through this special topic, the Seoul VMM required +extensions to handle more than 4G guest physical memory. Several changes to +the guest-memory layout handling and the memory-layout reporting, e.g., +[https://wiki.osdev.org/Detecting_Memory_(x86) - VBios e820], were necessary. + +Once an early prototype successfully booted a 64bit Linux kernel, we found the +initial user task of some Linux distributions to fail by complaining about +unsupported CPUs. As it turned out, glibc-based software (and later also +llvm-based) have several detection mechanism to identify the running CPU - and +if they feel uncomfortable, deny to work. So, we had to extend the support to +report more of the native CPUID values of the host and as an after-effect, +have to emulate more MSR accesses as performed by 64bit Linux guests. +Unfortunately, the MSRs between Intel and AMD differ in subtle ways, so a per +CPU differentiation became necessary in the vCPU model. + +Additionally, during testing of the native 64bit Debian VM installation with +the Seoul VMM, several improvements during early boot, especially for the +interactive usage of the GRUB bootloader were made. Ready to use packages to +test drive the 64bit Seoul VMM on Sculpt OS are available via the "alex-ab" +depot. + +[image seoul_64bit] + Two instances of the Seoul VMM executing 64-bit Linux + + +Ported 3rd-party software +========================= + +Linphone SIP client +------------------- + +Sculpt on the PinePhone used to provide only support for making and receiving +regular phone calls but did not yet provide any VoIP functionality. Now, the +"Linphone Console Client" and the "SIP Client for Ubuntu Touch" got ported to +Genode to expand the available features on the PinePhone when it comes to +mobile communication. + +We decided to port the [https://linphone.org - Linphone-SDK], the console +client in particular, to Genode because it seems to be a time-tested solution +on a range of OSes. Furthermore, it uses the [https://cmake.org - cmake] +build-system, which makes it the ideal candidate for stressing +[https://github.com/genodelabs/goa - Goa] with a reasonably complex project. +Using Goa itself turned out to be straight-forward and by re-using the already +existing back ends for POSIX-like systems, e.g. OSS for handling audio via the +mediastreamer library, we only had to tweak the build-system in very few +places. In the process, we encountered a few short-comings regarding the +handling of shared libraries in cmake-based Goa projects. We were happy to +address these and the fixes are part of the current Goa release. + +Since the user interface of the console client cannot be used comfortably on +the PinePhone, it had to be complemented by a GUI application that handles the +user interaction. While looking for such an application we noticed the +[https://gitlab.com/ubports-linphone/linphone-simple/ - SIP Client for Ubuntu Touch] +that utilizes the Ubuntu Touch UI Toolkit - where a port to Genode already +exists. We adapted that project for our needs and - with the major components +now in place - created a preset for Sculpt on the PinePhone. + +The preset's structure is depicted by the following chart. + +[image linphone_preset] + Structure of the linphone preset + +Each of the two components has its own requirements: The Linphone client needs +access to the network, has to store its configuration, and requires access to +the audio subsystem. It is the driving force behind the operation while it +receives its instructions from the GUI. The GUI needs access to the GPU +driver, as required for fluent rendering of QML on the PinePhone, as well as +access to input events for user interaction. + +Naturally these requirements are satisfied by other components also +incorporated into the preset: + +* The _Dynamic chroot_ component selects and limits the file-system access of + the client to the configured directory. In case of the PinePhone it points + to the '/recall/linphone' directory on the SD-card. + +* The _SNTP_ component provides the client with a correct real-time clock + value. Note that the SNTP component uses a different TCP/IP-stack than the + client itself. + +* The _Audio driver_ component makes the speaker as well as the microphone + available to the client. + +* The _GPU driver_ component allows the GUI to render the interface via OpenGL + on the GPU. + +* The _Touch keyboard_ collects the touch events and translates them into key + events that are then consumed by the GUI. + +The Linphone client and the GUI themselves are connected via the _terminal +crosslink_ component where the control channel is formed by connecting stdout +from the GUI to stdin from the client and vice versa. + +As denoted by the chart, the client actually functions as a _daemon_ that is +running in the background, whereas the GUI is the _app_ the user interacts +with. + +For more information and a usage guide, please refer to the corresponding +[https://genodians.org/jws/2023-11-16-sip-client-for-genode - Genodians article]. + + +Socat +----- + +We ported socat, a multipurpose relay (SOcket CAT), to Genode and created a +ready-to-use pkg archive that allows for making a terminal session available +on port '5555'. + + +SDL libraries +------------- + +This release also makes more SDL-related libraries available on Genode. +The common helper libraries like SDL2-image, SDL2-mixer, SDL2-net, and SDL2-ttf +complement the SDL2 support, while the SDL-gfx library enhances the support +of SDL1.2. All these libraries are located in the _genode-world_ repository. + + +Device drivers +############## + +USB device drivers updated to Linux 6.1.20 +========================================== + +With our ongoing effort to replace our traditional device-driver porting +approach by our new +[https://genode.org/documentation/release-notes/21.08#Linux-device-driver_environment_re-imagined - device-driver environment], +USB-device drivers were subject to this porting effort during this release +cycle. This includes the HID driver for keyboard, mouse, and touch support, +the network driver, which supports USB NICs like AX88179 or the PinePhone's +CDC Ether profile of its LTE Modem, as well as the USB modem driver that +offers basic LTE-modem access for modems relying on the +[https://www.usb.org/document-library/mobile-broadband-interface-model-v10-errata-1-and-adopters-agreement - MBIM] +configuration. + + +Architecture +------------ + +In contrast to the USB host-controller drivers, USB device drivers do not +communicate with the hardware directly, but only send messages to the USB host +controller through Genode's USB-session interface. So, from Genode's point of +view, they can be classified as protocol stacks. Therefore, we based these +drivers not on the DDE Linux version that offers direct hardware access, but +on 'virt_linux' as described in release +[https://genode.org/documentation/release-notes/23.05#WireGuard_improvements - 23.05]. + +We replaced the actual Linux calls that create USB messages (like control, +bulk, or IRQ transfers) by custom implementations that forward these messages +through a USB client session to the host controller. The client-session +implementation is written in C++. Since our DDE Linux strictly separates C++ +from C-code, we introduced a USB-client C-API that can be called directly by +the replacement functions. + +The same goes for the services the USB drivers offer/use. These services +are accessed through the respective C-APIs. For example, the HID driver +communicates with Genode's event session through the event C-API and the NIC +driver through the uplink C-API. + + +USB HID driver +-------------- + +The HID driver is a drop-in replacement of its predecessor. It still offers +support to handle multiple devices at once, and the configuration remains +unchanged. + +Note that we have dropped support for multi-touch devices, like Wacom, because +touch was merely in a proof of concept state that should be redesigned and +rethought for Genode if needed. + + +USB modem +--------- + +The LTE-modem driver (usb_modem_drv) has been integrated into the network +driver (see below). + + +USB net +------- + +The 'usb_net_drv' is a drop-in replacement for its predecessor with the +exception that an additional configuration attribute is available: + +! + +Next to the MAC address (like in the previous version), the USB configuration +profile can be specified with the 'configuration' attribute. For USB devices +that provide multiple configuration profiles, the Linux code will always +select the first non-vendor-specific configuration profile found. This may not +be the desired behavior, and therefore, can now be specified. + +The available configuration profile of a device can be found out under Linux +using: + +! lsusb -s: -vvv + +Currently the driver supports NICs containing an AX88179A chip and that offer +the NCM or the ECM profile. Support for the SMSC95XX line of devices has been +dropped, but may be re-enabled if required. + +As mentioned above, the LTE modem support for MBIM-based modems has been +merged into this driver because an LTE modem is merely a USB networking device +(for data) plus a control channel. In case the driver discovers an LTE modem, +it will announce a Genode terminal session as a control channel. + +Example configuration for the Huawai ME906s modem: + +! +! +! +! +! +! +! +! +! .... +! +! + +The MBIM interface is enabled using configuration profile "3" and the service +"Terminal" is provided. + +We have tested the driver mainly on Lenovo Thinkpad notebooks using Huawai's +ME906e and Fibocoms's L830-EB-00 modems, but different modems might work as +well. + + +Current limitations +------------------- + +The current version of 'virt_linux' does not support arm_v6 platforms like +Raspberry Pi (Zero). We will address this shortcoming with the next release +and update the drivers accordingly. + + +Platforms +######### + +Linux +===== + +Following the official +[https://wiki.libsdl.org/SDL2/MigrationGuide - migration guide] of SDL, the +fb_sdl framebuffer driver was updated from SDL1 to SDL2 by Robin Eklind. +Thanks to this valuable contribution, fb_sdl is now ready to run on modern +Linux installations especially in environments that use the Wayland display +server. Note, to compile the component from source, the installation of +libsdl2 development packages (e.g., libsdl2-dev, libdrm-dev, and libgbm-dev on +Ubuntu/Debian) is required. + + +Build system and tools +###################### + +Debug information for depot binaries +==================================== + +So far, the Genode build system created symbolic links to unstripped binaries +in the _debug/_ directory to provide useful debug information, but binaries +from depot archives did not have this information available. + +With this release, the 'create', 'publish' and 'download' depot tools received +an optional 'DBG=1' argument to create, publish, and download 'dbg' depot +archives with debug-info files in addition to the corresponding 'bin' depot +archives. + +To avoid the storage overhead from duplicated code with archived unstripped +binaries, we now create separate debug info files using the "GNU debug link" +method in the Genode build system and for the 'dbg' depot archives. + + +Decommissioned implicit trigger of shared-library builds +======================================================== + +Since the very first version, Genode's build system automatically managed +inter-library dependencies, which allowed us to cleanly separate different +concerns (like CPU-architecture-specific optimizations) as small static +libraries, which were automatically visited by the build system whenever +building a dependent target. + +When we later +[https://genode.org/documentation/release-notes/9.11#Completed_support_for_dynamic_linking - introduced] +the support for shared libraries, we maintained the existing notion of +libraries but merely considered shared objects as a special case. Hence, +whenever a target depends on a shared library, the build system would +automatically build the shared library before linking it to the target. + +With the later introduction of Genode's ABI's in version +[https://genode.org/documentation/release-notes/17.02#Genode_Application_Binary_Interface - 17.02], +we effectively dissolved the link-time dependency of targets from shared +objects, which ultimately paved the ground for Genode's package management. +However, our build-system retained the original policy of building shared +libraries before linking dependent targets. Even though this is arguably +convenient when using many small inter-dependent libraries, with complex +shared libraries as dependencies, one always needs to locally build those +complex libraries even though the library internals are rarely touched or the +library is readily available as a pre-built binary archive. In the presence of +large 3rd-party libraries, the build system's traditional policy starts to +stand in the way of quick development-test cycles. + +With the current release, we dissolve the implicit built-time dependency of +targets from shared libraries. Shared libraries must now be explicitly listed +in the 'build' command of run scripts. For example, for run scripts that build +Genode's base system along with the C runtime, the build command usually +contains the following targets. + +! core lib/ld init timer lib/libc lib/libm lib/vfs lib/posix + +However, in practice most run scripts incorporate those basic ingredients as +depot archives. So those targets need to be built only if they are touched by +the development work. To incorporate the results of all explicitly built +targets into a system image, the 'build_boot_image' command can be used as +follows. Note that the listing of boot modules does not need to be maintained +manually anymore. + +! build_boot_image [build_artifacts] + +During the release cycle of version 23.11, we have revisited all run scripts +in this respect, and we encourage Genode users to follow suit. The run tool +tries to give aid to implement this change whenever it detects the presence of +a .lib.so 'build_boot_image' argument that is not covered by the prior build +command. For example, on the attempt to integrate 'ld.lib.so' without having +built 'lib/ld', the following diagnostic message will try to guide you. + +! Error: missing build argument for: ld.lib.so +! +! The build_boot_image argument may be superfluous or +! the build step lacks the argument: lib/ld +! +! Consider using [build_artifacts] as build_boot_image argument to +! maintain consistency between the build and build_boot_image steps. + +The inconvenience of the need to adopt existing run scripts notwithstanding, +developers will certainly notice a welcome boost of their work flow, +especially when working with complex 3rd-party libraries. diff --git a/doc/release_notes/24-02.txt b/doc/release_notes/24-02.txt new file mode 100644 index 0000000000..4261c23c19 --- /dev/null +++ b/doc/release_notes/24-02.txt @@ -0,0 +1,677 @@ + + + =============================================== + Release notes for the Genode OS Framework 24.02 + =============================================== + + Genode Labs + + + +Version 24.02 focuses on developer experience and framework infrastructure. +Genode's Goa SDK has reached prominence in the past few releases. It largely +streamlines the porting, development, and publishing of software targeting +Genode and Sculpt OS in particular. +With the current release, Goa has become able to conveniently use Sculpt OS as +a remote test target. Regardless of whether targeting a PC or the PinePhone, +either can be turned into a test target in seconds and the developer's +compile-test cycle looks exactly the same +(Section [Sculpt OS as remote test target for the Goa SDK]). + +A long anticipated infrastructure topic is the rework of Genode's audio stack +to accommodate latency-sensitive scenarios, using flexible sample rates, and +making audio drivers pluggable. +Section [Revised audio infrastructure] gives an overview of the taken +architectural approach, the interfaces, and a low-complexity mixer modelled +as self-sufficient resource multiplexer. + +Speaking of infrastructure, we are excited to report to have wrapped up the +transition to our modern Linux device-driver environment based on Linux 6.x. +The last piece of the puzzle was the TCP/IP stack that was still based +on code originating from Linux 4.4.3. +Section [TCP/IP stack based on DDE-Linux version 6.1.20] details the new +TCP/IP stack. + +According to our [https://genode.org/about/road-map - road map], we plan to +add suspend/resume as feature to Sculpt OS 24.04. As a crucial stepping stone +towards this goal, all drivers that cannot be easily restarted must become +suspend/resume aware. +Section [Suspend/resume awareness of GPU, AHCI, and NVMe drivers] explains +this achievement for the AHCI, NVMe, and Intel GPU drivers. + +Further highlights of the release are the much improved handling of HID +events including the generalized calibration of motion events, API safety +improvements, the prospect of de-privileged tracing in Sculpt OS, and +multi-client support for Vivante GPUs. + +On our road map, we had scheduled two further topics that are notably absent, +namely USB and SMS. But don't fret. Even though the large rework of our USB +infrastructure for fine-grained and dynamic USB access has been completed just +in time, we felt that this far-reaching change should better not be rushed +into the release. It will be merged shortly after, and settle into the upcoming +Sculpt OS version 24.04 just fine. The second topic not covered is SMS support +for the PinePhone, which is a topic actively +[https://github.com/genodelabs/genode/issues/5127 - worked on] but with no +user-visible effect until its integration in Sculpt OS in April. + + +Revised audio infrastructure +############################ + +After first introduced in version +[https://genode.org/documentation/release-notes/10.05#Device-class_interfaces_for_NIC_and_Audio-out - 10.05], +Genode's +[https://genode.org/documentation/genode-foundations/23.05/components/Common_session_interfaces.html#Audio_output - audio support] +slowly evolved over the years, covering audio mixing in +version +[https://genode.org/documentation/release-notes/10.11#Audio_mixer - 10.11], +leveraging OpenBSD's audio driver since version +[https://genode.org/documentation/release-notes/15.05#Audio_drivers_ported_from_OpenBSD - 15.05] +and offering the OSS interface as VFS plugin since version +[https://genode.org/documentation/release-notes/20.11#Streamlined_ioctl_handling_in_the_C_runtime___VFS - 20.11]. +With our recent focus on use cases like +[https://genodians.org/jws/2023-11-16-sip-client-for-genode - VoIP on the PinePhone] or +[https://genode.org/documentation/release-notes/21.05#Webcam_support - video conferencing], +however, we identified limitations that cannot be overcome without an +architectural revision. + +First, in the name of simplicity, we used to tie the inter-component audio +interfaces to a fixed sample rate of 44100 Hz. This has recently become a +problem because some audio drivers tend to support only 48000 Hz. + +Second, in latency-sensitive scenarios, we observed that the existing +interfaces were prone to effects caused by the drifting of time between the +producer and consumer of audio data. One effect are buffer under-runs, which +produce audible noise. The other is the slow accumulation of buffered sample +data, which increases latency over time (affecting the effectiveness of +acoustic echo cancellation) and yields an audible buffer overrun after a +while. + +Third, the mixer is a single client of the audio driver, which makes the mixer +dependent on the liveliness of the driver. Therefore, the driver cannot be +restarted without also restarting the mixer and - transitively - each client +of the mixer. The rigid relation between the audio driver and the mixer also +stands in the way of routing audio between different audio devices operated +by separate drivers. + +After having successfully introduced the concept of _pluggable drivers_ for graphics in version +[https://genode.org/documentation/release-notes/20.08#The_GUI_stack__restacked - 20.08] +and applying the same idea to networking in version +[https://genode.org/documentation/release-notes/21.02#Pluggable_network_device_drivers - 21.02], +the time was ripe for turning the audio infrastructure upside down. + +[image audio_vs_recordplay] + original layered architecture (left) compared to the new pluggable + architecture (right) + +The new architecture as shown on the right turns the mixer into a +self-sufficient resource multiplexer, which offers a service for playing audio +and a service for recording audio. Both audio drivers as well as audio +applications are becoming mere clients of the mixer. With this architecture, +the dynamic starting, removal, and restarting of the driver, of even multiple +drivers, is trivially solved. + +To bridge the gap between audio clients operating at different sample rates, +the mixer automatically detects and converts sample rates as needed. Both play +and record clients are expected to operate periodically. The number of samples +produced per period is up to each client and does not need to be constant over +time. The mixer infers the used sample rates and periods by observing the +behavior of the clients. It measures the jitter of clients to automatically +adjust buffering parameters to attain continuous playback while trying to +optimize for low latency. Those runtime-measurements can be augmented by +explicit configuration values. + +Multi-channel playing and recording are realized by one session per channel +whereas one channel is used to drive the time allocation while all further +channels merely enqueue/obtain data into/from their respective sessions +without any synchronous interplay with the mixer. + +The mixer routes and mixes audio signals produced by play clients to record +clients according to its configuration. Typical play clients are an audio +player or a microphone driver whereas typical record clients are an audio +recorder or an audio-output driver. A simple mixer configuration looks as +follows: + +! +! +! +! +! +! +! +! +! + +This configuration defines two signals "left" and "right" that are mixed from +the audio input of the matching clients. In the example, each play +session labeled as "left" is mixed into the "left" signal. Each node can +host an arbitrary number of nodes. The same policy can appear at +multiple nodes. A node assigns a signal to a record client. In +the example, a record client labeled "left" is connected to the signal +"left". + +The mixer allows for the cascading of nodes. For example, the following +signal "lefty" is a mix of the two signals "left" and "right", weighted by +respective volume attributes. + +! +! +! +! + +[image mixed_waveforms] + Example of the mixer output for a sine wave as the "left" signal (top), + a signal mixed 70:30, a signal mixed 30:70, and a square wave as the + "right" signal (bottom). + +The operation and configuration of the mixer is described in more detail by +the accompanied README at _os/src/record_play_mixer/_. The inter-component +interfaces are located at _os/include/play_session/_ and +_os/include/record_session/_. + +The _gems/run/waveform_player.run_ script illustrates the integration of the +mixer by using a waveform generator as multi-channel play client and an +oscilloscope as record client. + +Current state and next steps +---------------------------- + +The new infrastructure is ready to be exercised by the synthetic example +mentioned above as well as by the _audio_out.run_ and _audio_in.run_ scripts +located at _repos/dde_bsd/run/_. The OpenBSD-based audio driver can be +operated in either of two modes. By default, it is compatible to the old audio +in/out interfaces. The new record/play mode can be enabled by setting the +'record_play="yes"' config attribute. Over the next release cycle, we will +successively convert the other pieces of the audio stack, in particular the +other drivers and the OSS VFS plugin, to the new record and play interfaces. +Following this transition, the original audio in/out interfaces will be +removed. + + +Sculpt OS as remote test target for the Goa SDK +############################################### + +The run-stage generalization from +[https://genode.org/documentation/release-notes/23.08#Run-stage_generalization - release 23.08], +paved the way for the new run-target "sculpt" that allows using Sculpt OS as +a remote test target for 'goa run'. Since Goa already placed all the required +files for running a scenario into a _var/run_ directory, adding this target +merely involved coming up with a solution for synchronizing the run directory +with Sculpt OS and getting a hold of the log output. The implementation in Goa +is accompanied by a _goa_testbed_ package that starts a remotely-controlled +subsystem on Sculpt OS. It particularly hosts a _lighttpd_ and _tcp_terminal_ +component. The former is used for run-directory synchronization based on HTTP +PUT. The latter provides the log output of the test scenario via telnet. For +more details, you may take a look at the corresponding +[https://genodians.org/jschlatow/2024-01-29-goa-sculpt - blog post on genodians.org]. + +In order to integrate support for this mechanism into Sculpt OS, we +supplemented the NIC router configuration with a _http_ and a _telnet_ domain. +Each of these domains is intended to accommodate a single client. Ports 80 and +23 of the _uplink_ domain are then forwarded to the clients in the _http_ and +_telnet_ domain respectively. This is complemented by the _goa_testbed_ preset +added to the PC and PinePhone version of Sculpt OS that turns the system into +a ready-to-use remote test target. You can see this feature in action in our +[https://genodians.org/nfeske/2024-02-15-fosdem-aftermath - FOSDEM talks]. + +When implementing the Sculpt target in Goa, we also had to come up with a way +to supply Goa with the IP address of the remote test target. Goa's modularity +w.r.t. custom run stages motivated us to implement a generic mechanism for +target-specific options. For this purpose, we added the config variable +'target_opt' that is defined as a Tcl array. The Sculpt target evaluates the +array elements 'sculpt-server', 'sculpt-port-http' and 'sculpt-port-telnet'. +We further augmented Goa's command-line parsing such that individual elements +of the 'target_opt' as well as the 'version' config variables, which are both +arrays, can be supplied as command-line arguments. The corresponding arguments +follow the pattern '--target-opt-} -# create single boot image from the compiled program images -build_boot_image "core ld.lib.so init test-cpu_scheduler" +build_boot_image [build_artifacts] -# configure qemu to use 64 MB RAM and avoid GUI mode -append qemu_args " -nographic" +append qemu_args " -nographic" -# execute the test in qemu if the targeted platform is supported -run_genode_until "done.*\n" 10 +run_genode_until "child .test-cpu_scheduler. exited with exit value .*\n" 10 -# check the output -grep_output {\[init -> test-cpu_scheduler\]} -compare_output_to { [init -> test-cpu_scheduler] done } +grep_output {child .test-cpu_scheduler. exited with exit value} + +compare_output_to { [init] child "test-cpu_scheduler" exited with exit value 0 } diff --git a/repos/base-hw/run/double_list.run b/repos/base-hw/run/double_list.run deleted file mode 100644 index e4a699b04e..0000000000 --- a/repos/base-hw/run/double_list.run +++ /dev/null @@ -1,69 +0,0 @@ -# -# \brief Test double-list implementation of core -# \author Martin Stein -# \date 2014-09-30 -# - -# build program images -build "core init test/double_list" - -# create directory where the boot files are written to -create_boot_directory - -# the init config is not used but the build system needs it -install_config { - - - - - - - - - - - - - - - -} - -# create single boot image from the compiled program images -build_boot_image "core ld.lib.so init test-double_list" - -# configure qemu to use 64 MB RAM and avoid GUI mode -append qemu_args " -nographic" - -# execute the test in qemu if the targeted platform is supported -run_genode_until "done.*\n" 10 - -# check the output -grep_output {\[init -> test-double_list\]} -compare_output_to { - [init -> test-double_list] print each - [init -> test-double_list] print each - [init -> test-double_list] 1 - [init -> test-double_list] print each - [init -> test-double_list] 3 - [init -> test-double_list] 2 - [init -> test-double_list] 5 - [init -> test-double_list] 7 - [init -> test-double_list] 6 - [init -> test-double_list] 4 - [init -> test-double_list] 1 - [init -> test-double_list] print each - [init -> test-double_list] 8 - [init -> test-double_list] 9 - [init -> test-double_list] 2 - [init -> test-double_list] 5 - [init -> test-double_list] 1 - [init -> test-double_list] 7 - [init -> test-double_list] 6 - [init -> test-double_list] 4 - [init -> test-double_list] 3 - [init -> test-double_list] print each - [init -> test-double_list] 7 - [init -> test-double_list] 8 - [init -> test-double_list] done -} diff --git a/repos/base-hw/src/bootstrap/board/imx53_qsb/board.h b/repos/base-hw/src/bootstrap/board/imx53_qsb/board.h deleted file mode 100644 index e65079f3af..0000000000 --- a/repos/base-hw/src/bootstrap/board/imx53_qsb/board.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * \brief i.MX53 Quickstart board definitions - * \author Stefan Kalkowski - * \date 2017-03-22 - */ - -/* - * Copyright (C) 2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _SRC__BOOTSTRAP__SPEC__IMX53_QSB__BOARD_H_ -#define _SRC__BOOTSTRAP__SPEC__IMX53_QSB__BOARD_H_ - -#include -#include - -#include -#include - -namespace Board { - - using namespace Hw::Imx53_qsb_board; - - using Hw::Pic; - - bool secure_irq(unsigned irq); -} - -#endif /* _SRC__BOOTSTRAP__SPEC__IMX53_QSB__BOARD_H_ */ diff --git a/repos/base-hw/src/bootstrap/board/imx53_qsb/platform.cc b/repos/base-hw/src/bootstrap/board/imx53_qsb/platform.cc deleted file mode 100644 index bb684bba63..0000000000 --- a/repos/base-hw/src/bootstrap/board/imx53_qsb/platform.cc +++ /dev/null @@ -1,32 +0,0 @@ -/* - * \brief Specific i.MX53 bootstrap implementations - * \author Stefan Kalkowski - * \date 2012-10-24 - */ - -/* - * Copyright (C) 2012-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#include -#include - -using namespace Board; - -bool Board::secure_irq(unsigned) { return true; } - - -Bootstrap::Platform::Board::Board() -: - early_ram_regions(Memory_region { RAM0_BASE, RAM0_SIZE }, - Memory_region { RAM1_BASE, RAM1_SIZE }), - core_mmio(Memory_region { UART_1_MMIO_BASE, UART_1_MMIO_SIZE }, - Memory_region { EPIT_1_MMIO_BASE, EPIT_1_MMIO_SIZE }, - Memory_region { IRQ_CONTROLLER_BASE, IRQ_CONTROLLER_SIZE }) -{ - Aipstz aipstz_1(AIPS_1_MMIO_BASE); - Aipstz aipstz_2(AIPS_2_MMIO_BASE); -} diff --git a/repos/base-hw/src/bootstrap/board/imx53_qsb/platform_trustzone.cc b/repos/base-hw/src/bootstrap/board/imx53_qsb/platform_trustzone.cc deleted file mode 100644 index 912a06bc12..0000000000 --- a/repos/base-hw/src/bootstrap/board/imx53_qsb/platform_trustzone.cc +++ /dev/null @@ -1,59 +0,0 @@ -/* - * \brief Specific i.MX53 bootstrap implementations - * \author Stefan Kalkowski - * \date 2012-10-24 - */ - -/* - * Copyright (C) 2012-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#include -#include -#include -#include - -using namespace Board; - - -bool Board::secure_irq(unsigned i) -{ - if (i == EPIT_1_IRQ) return true; - if (i == EPIT_2_IRQ) return true; - if (i == I2C_2_IRQ) return true; - if (i == I2C_3_IRQ) return true; - if (i == SDHC_IRQ) return true; - - if (i >= GPIO1_IRQL && i <= GPIO4_IRQH) return true; - if (i >= GPIO5_IRQL && i <= GPIO7_IRQH) return true; - return false; -} - - -Bootstrap::Platform::Board::Board() -: - early_ram_regions(Memory_region { Trustzone::SECURE_RAM_BASE, - Trustzone::SECURE_RAM_SIZE }), - core_mmio(Memory_region { UART_1_MMIO_BASE, UART_1_MMIO_SIZE }, - Memory_region { EPIT_1_MMIO_BASE, EPIT_1_MMIO_SIZE }, - Memory_region { IRQ_CONTROLLER_BASE, IRQ_CONTROLLER_SIZE }, - Memory_region { CSU_BASE, CSU_SIZE }) -{ - Aipstz aipstz_1(AIPS_1_MMIO_BASE); - Aipstz aipstz_2(AIPS_2_MMIO_BASE); - - /* set exception vector entry */ - Cpu::Mvbar::write(Hw::Mm::system_exception_vector().base); - - /* enable coprocessor 10 + 11 access for TZ VMs */ - Cpu::Nsacr::access_t v = 0; - Cpu::Nsacr::Cpnsae10::set(v, 1); - Cpu::Nsacr::Cpnsae11::set(v, 1); - Cpu::Nsacr::write(v); - - /* configure central security unit */ - Csu csu(CSU_BASE, false, true, false, true); -} diff --git a/repos/base-hw/src/bootstrap/board/imx6q_sabrelite/board.h b/repos/base-hw/src/bootstrap/board/imx6q_sabrelite/board.h deleted file mode 100644 index 995b75149a..0000000000 --- a/repos/base-hw/src/bootstrap/board/imx6q_sabrelite/board.h +++ /dev/null @@ -1,222 +0,0 @@ -/* - * \brief i.MX6Quad Sabrelite specific board definitions - * \author Stefan Kalkowski - * \date 2019-01-05 - */ - -/* - * Copyright (C) 2019 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _SRC__BOOTSTRAP__SPEC__IMX6Q_SABRELITE__BOARD_H_ -#define _SRC__BOOTSTRAP__SPEC__IMX6Q_SABRELITE__BOARD_H_ - -#include -#include -#include -#include -#include - -namespace Board { - - using namespace Hw::Imx6q_sabrelite_board; - using Pic = Hw::Gicv2; - struct L2_cache; - - static constexpr bool NON_SECURE = false; - - static volatile unsigned long initial_values[][2] { - // (IOMUX Controller) - { 0x20e0004, 0x48613005 }, - { 0x20e0008, 0x0 }, - { 0x20e000c, 0x1e00040 }, - { 0x20e0020, 0xfffd4000 }, - { 0x20e0030, 0xf004490 }, - { 0x20e0034, 0x593e4a4 }, - { 0x20e004c, 0x3 }, - { 0x20e0050, 0x3 }, - { 0x20e0054, 0x3 }, - { 0x20e015c, 0x0 }, - { 0x20e0160, 0x0 }, - { 0x20e0164, 0x0 }, - { 0x20e0168, 0x0 }, - { 0x20e0170, 0x0 }, - { 0x20e0174, 0x0 }, - { 0x20e0178, 0x0 }, - { 0x20e017c, 0x0 }, - { 0x20e0180, 0x0 }, - { 0x20e0184, 0x0 }, - { 0x20e0188, 0x0 }, - { 0x20e018c, 0x0 }, - { 0x20e0190, 0x0 }, - { 0x20e0194, 0x0 }, - { 0x20e0198, 0x0 }, - { 0x20e019c, 0x0 }, - { 0x20e01a0, 0x0 }, - { 0x20e01a4, 0x0 }, - { 0x20e01a8, 0x0 }, - { 0x20e01ac, 0x0 }, - { 0x20e01b0, 0x0 }, - { 0x20e01b4, 0x0 }, - { 0x20e01b8, 0x0 }, - { 0x20e01bc, 0x0 }, - { 0x20e01c0, 0x0 }, - { 0x20e01c4, 0x0 }, - { 0x20e01c8, 0x0 }, - { 0x20e01cc, 0x0 }, - { 0x20e0208, 0x2 }, - { 0x20e020c, 0x2 }, - { 0x20e0218, 0x2 }, - { 0x20e0220, 0x0 }, - { 0x20e0224, 0x3 }, - { 0x20e0230, 0x11 }, - { 0x20e02b8, 0x0 }, - { 0x20e02f4, 0x0 }, - { 0x20e033c, 0x2 }, - { 0x20e0344, 0x3 }, - { 0x20e0348, 0x2 }, - { 0x20e035c, 0x3 }, - { 0x20e0360, 0x130b0 }, - { 0x20e0364, 0x110b0 }, - { 0x20e0368, 0x130b0 }, - { 0x20e036c, 0x10030 }, - { 0x20e0370, 0x10030 }, - { 0x20e0374, 0x10030 }, - { 0x20e0378, 0x10030 }, - { 0x20e037c, 0x10030 }, - { 0x20e0388, 0x10030 }, - { 0x20e03b0, 0xb1 }, - { 0x20e03bc, 0xb0 }, - { 0x20e03c0, 0xb0 }, - { 0x20e0470, 0x10 }, - { 0x20e0474, 0x10 }, - { 0x20e0478, 0x10 }, - { 0x20e047c, 0x10 }, - { 0x20e0484, 0x10 }, - { 0x20e0488, 0x10 }, - { 0x20e048c, 0x10 }, - { 0x20e0490, 0x10 }, - { 0x20e0494, 0x10 }, - { 0x20e0498, 0x10 }, - { 0x20e049c, 0x10 }, - { 0x20e04a0, 0x10 }, - { 0x20e04a4, 0x10 }, - { 0x20e04a8, 0x10 }, - { 0x20e04ac, 0x10 }, - { 0x20e04b0, 0x10 }, - { 0x20e04b4, 0x10 }, - { 0x20e04b8, 0x10 }, - { 0x20e04bc, 0x10 }, - { 0x20e04c0, 0x10 }, - { 0x20e04c4, 0x10 }, - { 0x20e04c8, 0x10 }, - { 0x20e04cc, 0x10 }, - { 0x20e04d0, 0x10 }, - { 0x20e04d4, 0x10 }, - { 0x20e04d8, 0x10 }, - { 0x20e04dc, 0x10 }, - { 0x20e04e0, 0x10 }, - { 0x20e04e4, 0x100b0 }, - { 0x20e04e8, 0x100b0 }, - { 0x20e0508, 0x100b0 }, - { 0x20e05f0, 0x30b0 }, - { 0x20e05f4, 0x17059 }, - { 0x20e0600, 0xb1 }, - { 0x20e061c, 0x30b0 }, - { 0x20e069c, 0x1f0b0 }, - { 0x20e06a4, 0x10059 }, - { 0x20e06e0, 0x10059 }, - { 0x20e0724, 0x1b0b1 }, - { 0x20e072c, 0x1b0b1 }, - { 0x20e0730, 0x1b0b1 }, - { 0x20e0744, 0x130b0 }, - { 0x20e07c4, 0x1 }, - { 0x20e0944, 0x1 }, - // (Global Power Controller) - { 0x20dc008, 0x70f7f01b }, - { 0x20dc00c, 0xff79b60f }, - { 0x20dc010, 0xfffe0003 }, - { 0x20dc014, 0xfef7f9ff }, - // (Power Management Unit) - { 0x20c8140, 0x4c0013 }, - { 0x20c8150, 0x4010088 }, - { 0x20c8160, 0x8000040b }, - { 0x20c8170, 0xff672f67 }, - // (Clock Controller Module) - { 0x20c4018, 0x10204 }, - { 0x20c402c, 0x7348c1 }, - { 0x20c4030, 0x33e71f92 }, - { 0x20c4034, 0x12088 }, - { 0x20c4038, 0x12090 }, - { 0x20c4054, 0x78 }, - { 0x20c4060, 0x10e0101 }, - { 0x20c4064, 0x2fe62 }, - { 0x20c4068, 0xc03f0f }, - { 0x20c406c, 0x30fc00 }, - { 0x20c4070, 0x3ff0033 }, - { 0x20c4074, 0x3f3300c3 }, - { 0x20c4078, 0xc303 }, - { 0x20c4080, 0xf03 }, - { 0x20c8010, 0x80003040 }, - { 0x20c8070, 0x1006 }, - { 0x20c80a0, 0x1028 }, - { 0x20c80b0, 0x0 }, - { 0x20c80c0, 0xf4240 }, - { 0x20c80e0, 0x80182001 }, - { 0x20c80f0, 0xd3d150cc }, - { 0x20c8100, 0x5018d0db } - }; -} - - -struct Board::L2_cache : Hw::Pl310 -{ - L2_cache(Genode::addr_t mmio) : Hw::Pl310(mmio) - { - Aux::access_t aux = 0; - Aux::Full_line_of_zero::set(aux, true); - Aux::Associativity::set(aux, Aux::Associativity::WAY_16); - Aux::Way_size::set(aux, Aux::Way_size::KB_64); - Aux::Share_override::set(aux, true); - Aux::Replacement_policy::set(aux, Aux::Replacement_policy::PRAND); - Aux::Ns_lockdown::set(aux, true); - Aux::Data_prefetch::set(aux, true); - Aux::Inst_prefetch::set(aux, true); - Aux::Early_bresp::set(aux, true); - write(aux); - - Tag_ram::access_t tag_ram = 0; - Tag_ram::Setup_latency::set(tag_ram, 2); - Tag_ram::Read_latency::set(tag_ram, 3); - Tag_ram::Write_latency::set(tag_ram, 1); - write(tag_ram); - - Data_ram::access_t data_ram = 0; - Data_ram::Setup_latency::set(data_ram, 2); - Data_ram::Read_latency::set(data_ram, 3); - Data_ram::Write_latency::set(data_ram, 1); - write(data_ram); - - Prefetch_ctrl::access_t prefetch = 0; - Prefetch_ctrl::Data_prefetch::set(prefetch, 1); - Prefetch_ctrl::Inst_prefetch::set(prefetch, 1); - write(prefetch | 0xF); - } - - using Hw::Pl310::invalidate; - - void enable() - { - Pl310::mask_interrupts(); - write(1); - } - - void disable() { - write(0); - } -}; - -#endif /* _SRC__BOOTSTRAP__SPEC__IMX6Q_SABRELITE__BOARD_H_ */ diff --git a/repos/base-hw/src/bootstrap/board/imx7d_sabre/board.h b/repos/base-hw/src/bootstrap/board/imx7d_sabre/board.h deleted file mode 100644 index b4c8446e8b..0000000000 --- a/repos/base-hw/src/bootstrap/board/imx7d_sabre/board.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * \brief Imx7 Sabrelite specific board definitions - * \author Stefan Kalkowski - * \date 2018-11-07 - */ - -/* - * Copyright (C) 2018 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _SRC__BOOTSTRAP__SPEC__IMX7_SABRELITE__BOARD_H_ -#define _SRC__BOOTSTRAP__SPEC__IMX7_SABRELITE__BOARD_H_ - -#include -#include -#include -#include - -namespace Board { - - using namespace Hw::Imx7d_sabre_board; - using Pic = Hw::Gicv2; - static constexpr bool NON_SECURE = true; -} - -#endif /* _SRC__BOOTSTRAP__SPEC__IMX&_SABRELITE__BOARD_H_ */ diff --git a/repos/base-hw/src/bootstrap/board/imx7d_sabre/platform.cc b/repos/base-hw/src/bootstrap/board/imx7d_sabre/platform.cc deleted file mode 100644 index 17e4a1ad5f..0000000000 --- a/repos/base-hw/src/bootstrap/board/imx7d_sabre/platform.cc +++ /dev/null @@ -1,249 +0,0 @@ -/* - * \brief Parts of platform that are specific to Imx7 sabrelite - * \author Stefan Kalkowski - * \date 2018-11-07 - */ - -/* - * Copyright (C) 2018 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#include -#include -#include -#include - -extern "C" void * _start_setup_stack; /* entrypoint for non-boot CPUs */ - -using namespace Board; - - -Bootstrap::Platform::Board::Board() -: - early_ram_regions(Memory_region { RAM_0_BASE, RAM_0_SIZE }), - core_mmio(Memory_region { IRQ_CONTROLLER_BASE, IRQ_CONTROLLER_SIZE }, - Memory_region { UART_1_MMIO_BASE, UART_1_MMIO_SIZE }) -{ - Aipstz aipstz_1(AIPS_1_MMIO_BASE); - Aipstz aipstz_2(AIPS_2_MMIO_BASE); - Aipstz aipstz_3(AIPS_3_MMIO_BASE); - - /* configure CSU */ - for (addr_t start = 0x303e0000; start <= 0x303e00fc; start += 4) - *(volatile addr_t *)start = 0x00ff00ff; - - static volatile unsigned long initial_values[][2] { - // CCM (Clock Control Module) - { 0x30384000, 0x3 }, - { 0x30384040, 0x3 }, - { 0x30384060, 0x3 }, - { 0x30384130, 0x3 }, - { 0x30384160, 0x0 }, - { 0x303844f0, 0x3 }, - { 0x30384510, 0x0 }, - { 0x30384520, 0x3 }, - { 0x303846d0, 0x0 }, - { 0x303846e0, 0x0 }, - { 0x30384780, 0x0 }, - { 0x30384790, 0x0 }, - { 0x303847a0, 0x0 }, - { 0x303847b0, 0x0 }, - { 0x303847c0, 0x3 }, - { 0x30384880, 0x0 }, - { 0x303848a0, 0x0 }, - { 0x30384950, 0x0 }, - { 0x30384960, 0x0 }, - { 0x30384970, 0x0 }, - { 0x30384980, 0x0 }, - { 0x30384990, 0x0 }, - { 0x303849a0, 0x0 }, - { 0x303849d0, 0x0 }, - { 0x303849e0, 0x0 }, - { 0x303849f0, 0x0 }, - { 0x303600c0, 0xd2605a56 }, - { 0x303600d0, 0xd2d2d256 }, - { 0x303600d4, 0xd2d2d256 }, - { 0x303600d8, 0xd2d2d256 }, - { 0x303600dc, 0xd2d2d256 }, - { 0x303600e0, 0x80000600 }, - { 0x303600f0, 0x101b }, - // IOMUXC (IOMUX Controller) - { 0x30330030, 0x14 }, - { 0x30330034, 0x10 }, - { 0x30330074, 0x2 }, - { 0x30330078, 0x2 }, - { 0x3033007c, 0x2 }, - { 0x30330080, 0x2 }, - { 0x30330084, 0x2 }, - { 0x30330088, 0x2 }, - { 0x3033008c, 0x2 }, - { 0x30330090, 0x2 }, - { 0x30330094, 0x2 }, - { 0x30330098, 0x2 }, - { 0x3033009c, 0x2 }, - { 0x303300a0, 0x2 }, - { 0x303300c4, 0x0 }, - { 0x30330150, 0x10 }, - { 0x30330154, 0x10 }, - { 0x30330210, 0x13 }, - { 0x30330214, 0x13 }, - { 0x3033021c, 0x1 }, - { 0x30330220, 0x1 }, - { 0x30330224, 0x1 }, - { 0x303302e4, 0x1 }, - { 0x303302e8, 0x1 }, - { 0x303302ec, 0x1 }, - { 0x303302f0, 0x1 }, - { 0x303302f4, 0x1 }, - { 0x303302f8, 0x1 }, - { 0x303302fc, 0x1 }, - { 0x30330300, 0x1 }, - { 0x30330304, 0x1 }, - { 0x30330308, 0x1 }, - { 0x3033030c, 0x1 }, - { 0x30330310, 0x1 }, - { 0x30330318, 0x59 }, - { 0x303303c0, 0x7f }, - { 0x303303c4, 0x7f }, - { 0x303303f4, 0x34 }, - { 0x303303f8, 0x59 }, - { 0x303303fc, 0x59 }, - { 0x30330400, 0x59 }, - { 0x30330404, 0x19 }, - { 0x30330408, 0x59 }, - { 0x3033040c, 0x59 }, - { 0x30330410, 0x59 }, - { 0x30330414, 0x59 }, - { 0x30330418, 0x59 }, - { 0x3033041c, 0x59 }, - { 0x30330440, 0x19 }, - { 0x30330444, 0x59 }, - { 0x30330448, 0x59 }, - { 0x3033044c, 0x59 }, - { 0x30330450, 0x59 }, - { 0x30330454, 0x59 }, - { 0x30330458, 0x59 }, - { 0x3033045c, 0x59 }, - { 0x30330460, 0x59 }, - { 0x30330464, 0x59 }, - { 0x30330468, 0x19 }, - { 0x30330480, 0x7f }, - { 0x30330484, 0x7f }, - { 0x3033048c, 0x2 }, - { 0x30330490, 0x2 }, - { 0x30330494, 0x2 }, - { 0x3033049c, 0x1 }, - { 0x303304a0, 0x1 }, - { 0x303304a4, 0x1 }, - { 0x303304a8, 0x1 }, - { 0x303304ac, 0x1 }, - { 0x303304b0, 0x1 }, - { 0x303304b4, 0x1 }, - { 0x303304b8, 0x1 }, - { 0x303304bc, 0x1 }, - { 0x303304c0, 0x1 }, - { 0x303304c4, 0x1 }, - { 0x303304c8, 0x1 }, - { 0x30330544, 0x1 }, - { 0x30330548, 0x1 }, - { 0x3033054c, 0x1 }, - { 0x303305dc, 0x1 }, - { 0x303305e0, 0x1 }, - { 0x303305ec, 0x3 }, - { 0x303305f0, 0x3 } - }; - - unsigned num_values = sizeof(initial_values) / (2*sizeof(unsigned long)); - for (unsigned i = 0; i < num_values; i++) - *((volatile unsigned long*)initial_values[i][0]) = initial_values[i][1]; - -} - - -static inline void switch_to_supervisor_mode(unsigned cpu_id) -{ - using Cpsr = Hw::Arm_cpu::Psr; - - Cpsr::access_t cpsr = 0; - Cpsr::M::set(cpsr, Cpsr::M::SVC); - Cpsr::F::set(cpsr, 1); - Cpsr::I::set(cpsr, 1); - - Genode::addr_t const stack = Hw::Mm::hypervisor_stack().base + - (cpu_id+1) * 0x1000; - - asm volatile ( - "msr sp_svc, sp \n" /* copy current mode's sp */ - "msr lr_svc, lr \n" /* copy current mode's lr */ - "msr elr_hyp, lr \n" /* copy current mode's lr to hyp lr */ - "msr sp_hyp, %[stack] \n" /* copy to hyp stack pointer */ - "msr spsr_cxfs, %[cpsr] \n" /* set psr for supervisor mode */ - "adr lr, 1f \n" /* load exception return address */ - "eret \n" /* exception return */ - "1:":: [cpsr] "r" (cpsr), [stack] "r" (stack)); -} - - -unsigned Bootstrap::Platform::enable_mmu() -{ - static volatile bool primary_cpu = true; - static unsigned long timer_freq = Cpu::Cntfrq::read(); - unsigned cpu = Cpu::Mpidr::Aff_0::get(Cpu::Mpidr::read()); - - /* locally initialize interrupt controller */ - ::Board::Pic pic { }; - - prepare_nonsecure_world(timer_freq); - prepare_hypervisor((addr_t)core_pd->table_base); - switch_to_supervisor_mode(cpu); - - Cpu::Sctlr::init(); - Cpu::Cpsr::init(); - - /* primary cpu wakes up all others */ - if (primary_cpu && NR_OF_CPUS > 1) { - Cpu::invalidate_data_cache(); - primary_cpu = false; - Cpu::wake_up_all_cpus(&_start_setup_stack); - } - - Cpu::enable_mmu_and_caches((Genode::addr_t)core_pd->table_base); - - return cpu; -} - - -void Board::Cpu::wake_up_all_cpus(void * const ip) -{ - struct Src : Genode::Mmio - { - struct A7_cr0 : Register<0x4, 32> - { - struct Core1_por_reset : Bitfield<1,1> {}; - struct Core1_soft_reset : Bitfield<5,1> {}; - }; - struct A7_cr1 : Register<0x8, 32> - { - struct Core1_enable : Bitfield<1,1> {}; - }; - struct Gpr3 : Register<0x7c, 32> {}; /* ep core 1 */ - struct Gpr4 : Register<0x80, 32> {}; /* ep core 1 */ - - Src(void * const entry) : Genode::Mmio(SRC_MMIO_BASE) - { - write((Gpr3::access_t)entry); - write((Gpr4::access_t)entry); - A7_cr0::access_t v0 = read(); - A7_cr0::Core1_soft_reset::set(v0,1); - write(v0); - A7_cr1::access_t v1 = read(); - A7_cr1::Core1_enable::set(v1,1); - write(v1); - } - }; - - Src src(ip); -} diff --git a/repos/base-hw/src/bootstrap/board/nit6_solox/board.h b/repos/base-hw/src/bootstrap/board/nit6_solox/board.h deleted file mode 100644 index b6df2e5c1d..0000000000 --- a/repos/base-hw/src/bootstrap/board/nit6_solox/board.h +++ /dev/null @@ -1,282 +0,0 @@ -/* - * \brief Nit6 SOLOX specific board definitions - * \author Stefan Kalkowski - * \date 2017-10-18 - */ - -/* - * Copyright (C) 2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _SRC__BOOTSTRAP__SPEC__NIT6_SOLOX__BOARD_H_ -#define _SRC__BOOTSTRAP__SPEC__NIT6_SOLOX__BOARD_H_ - -#include -#include -#include -#include -#include - -namespace Board { - - using namespace Hw::Nit6_solox_board; - using Pic = Hw::Gicv2; - struct L2_cache; - - static constexpr bool NON_SECURE = false; - - static volatile unsigned long initial_values[][2] { - // (IOMUX Controller) - { 0x20E006C, 0x0}, - { 0x20E00CC, 0x10}, - { 0x20E00D0, 0x10}, - { 0x20E00D4, 0x10}, - { 0x20E00D8, 0x10}, - { 0x20E00DC, 0x10}, - { 0x20E00E0, 0x10}, - { 0x20E00E4, 0x10}, - { 0x20E00E8, 0x10}, - { 0x20E00EC, 0x10}, - { 0x20E00F0, 0x10}, - { 0x20E00F4, 0x10}, - { 0x20E00F8, 0x10}, - { 0x20E00FC, 0x10}, - { 0x20E0100, 0x10}, - { 0x20E0104, 0x10}, - { 0x20E0108, 0x10}, - { 0x20E010C, 0x10}, - { 0x20E0110, 0x10}, - { 0x20E0114, 0x10}, - { 0x20E0118, 0x10}, - { 0x20E011C, 0x10}, - { 0x20E0120, 0x10}, - { 0x20E0124, 0x10}, - { 0x20E0128, 0x10}, - { 0x20E012C, 0x10}, - { 0x20E0130, 0x10}, - { 0x20E0134, 0x10}, - { 0x20E0138, 0x15}, - { 0x20E013C, 0x10}, - { 0x20E0150, 0x5}, - { 0x20E0154, 0x5}, - { 0x20E0158, 0x5}, - { 0x20E0224, 0x5}, - { 0x20E0268, 0x5}, - { 0x20E026C, 0x5}, - { 0x20E0270, 0x3}, - { 0x20E0274, 0x3}, - { 0x20E035C, 0x1b8b1}, - { 0x20E0360, 0x1b8b1}, - { 0x20E0364, 0x1b8b1}, - { 0x20E0368, 0x1b8b1}, - { 0x20E0380, 0x1b0b0}, - { 0x20E0384, 0x170b1}, - { 0x20E0390, 0x110b0}, - { 0x20E0394, 0x110b0}, - { 0x20E0398, 0x110b0}, - { 0x20E039C, 0x110b0}, - { 0x20E03A0, 0x110b0}, - { 0x20E03A4, 0x110b0}, - { 0x20E03A8, 0x110b0}, - { 0x20E03AC, 0x110b0}, - { 0x20E03B0, 0x110b0}, - { 0x20E03B4, 0x110b0}, - { 0x20E03B8, 0x110b0}, - { 0x20E03BC, 0x110b0}, - { 0x20E03C0, 0x110b0}, - { 0x20E03D4, 0xb0b0}, - { 0x20E03D8, 0xb0b0}, - { 0x20E03DC, 0xb0b0}, - { 0x20E03E0, 0xb0b0}, - { 0x20E03E4, 0xb0b0}, - { 0x20E03E8, 0xb0b0}, - { 0x20E03FC, 0x1b8b1}, - { 0x20E0404, 0xb0b1}, - { 0x20E0408, 0x1b0b0}, - { 0x20E0410, 0x1b8b1}, - { 0x20E0414, 0x1b0b0}, - { 0x20E0418, 0x1b0b0}, - { 0x20E041C, 0x1b0b0}, - { 0x20E0420, 0x1b0b0}, - { 0x20E0424, 0x1b0b0}, - { 0x20E0428, 0x1b0b0}, - { 0x20E042C, 0x1b0b0}, - { 0x20E0430, 0x1b0b0}, - { 0x20E0434, 0x1b0b0}, - { 0x20E0438, 0x1b0b0}, - { 0x20E043C, 0x1b0b0}, - { 0x20E0440, 0x1b0b0}, - { 0x20E0444, 0x1b0b0}, - { 0x20E0448, 0x1b0b0}, - { 0x20E044C, 0x1b0b0}, - { 0x20E0450, 0x1b0b0}, - { 0x20E0454, 0x1b0b0}, - { 0x20E0458, 0x1b0b0}, - { 0x20E045C, 0x1b0b0}, - { 0x20E0460, 0x1b0b0}, - { 0x20E0464, 0x1b0b0}, - { 0x20E0468, 0x1b0b0}, - { 0x20E046C, 0x1b0b0}, - { 0x20E0470, 0x1b0b0}, - { 0x20E0474, 0x1b0b0}, - { 0x20E0478, 0x1b0b0}, - { 0x20E047C, 0x1b0b0}, - { 0x20E0480, 0x1b0b0}, - { 0x20E0484, 0x1b0b0}, - { 0x20E0488, 0xb0b0}, - { 0x20E0490, 0x30b0}, - { 0x20E0498, 0x30b1}, - { 0x20E049C, 0x30b0}, - { 0x20E04A0, 0x30b1}, - { 0x20E04A4, 0xb0b1}, - { 0x20E04AC, 0x30b0}, - { 0x20E04B0, 0x30b0}, - { 0x20E04B4, 0x30b0}, - { 0x20E04E0, 0xb0b0}, - { 0x20E04E8, 0xb0b0}, - { 0x20E04F0, 0xb0b0}, - { 0x20E04F4, 0xb0b0}, - { 0x20E0508, 0x3081}, - { 0x20E050C, 0x3081}, - { 0x20E0510, 0x3081}, - { 0x20E0514, 0x3081}, - { 0x20E0518, 0x3081}, - { 0x20E051C, 0x3081}, - { 0x20E0520, 0x30b1}, - { 0x20E0524, 0x30b1}, - { 0x20E0528, 0x30b1}, - { 0x20E052C, 0x30b1}, - { 0x20E0530, 0x30b1}, - { 0x20E0534, 0x30b1}, - { 0x20E0538, 0x3081}, - { 0x20E053C, 0x3081}, - { 0x20E0540, 0x3081}, - { 0x20E0544, 0x3081}, - { 0x20E0548, 0x3081}, - { 0x20E054C, 0x3081}, - { 0x20E0550, 0x30b1}, - { 0x20E0554, 0x30b1}, - { 0x20E0558, 0x30b1}, - { 0x20E055C, 0x30b1}, - { 0x20E0560, 0x30b1}, - { 0x20E0564, 0x30b1}, - { 0x20E056C, 0x30b0}, - { 0x20E0570, 0x1b0b0}, - { 0x20E0574, 0x1b0b0}, - { 0x20E0578, 0x1b0b0}, - { 0x20E057C, 0x1b0b0}, - { 0x20E0598, 0x10071}, - { 0x20E059C, 0x17071}, - { 0x20E05A0, 0x17071}, - { 0x20E05A4, 0x17071}, - { 0x20E05A8, 0x17071}, - { 0x20E05AC, 0x17071}, - { 0x20E05B0, 0x1b0b0}, - { 0x20E05B4, 0x1b0b0}, - { 0x20E05B8, 0x1b0b1}, - { 0x20E05BC, 0x1b0b1}, - { 0x20E05C0, 0x100f9}, - { 0x20E05C4, 0x170f9}, - { 0x20E05C8, 0x170f9}, - { 0x20E05CC, 0x170f9}, - { 0x20E05D0, 0x170f9}, - { 0x20E05D4, 0x170f9}, - { 0x20E05D8, 0x170f9}, - { 0x20E05DC, 0x170f9}, - { 0x20E05E0, 0x170f9}, - { 0x20E05E4, 0x170f9}, - { 0x20E05E8, 0x17071}, - { 0x20E083C, 0x2}, - // (Global Power Controller} - { 0x20DC000, 0x140000}, - { 0x20DC008, 0x2077fe0b}, - { 0x20DC00C, 0xff7db18f}, - { 0x20DC010, 0xfbfe0003}, - { 0x20DC014, 0xff2ff93f}, - // (Power Management Unit} - { 0x20C8120, 0x11775}, - { 0x20C8140, 0x4c0016}, - { 0x20C8160, 0x8003000a}, - // (Clock Controller Module} - { 0x20C4004, 0x20000}, - { 0x20C4018, 0x269114}, - { 0x20C401C, 0x4510a9c0}, - { 0x20C4020, 0x13212c06}, - { 0x20C4028, 0x0}, - { 0x20C402C, 0x4b600}, - { 0x20C4030, 0x30074792}, - { 0x20C4038, 0x12153}, - { 0x20C4054, 0x78}, - { 0x20C4060, 0x10e008e}, - { 0x20C4064, 0x2fe62}, - { 0x20C4068, 0xf0c03f0f}, - { 0x20C406C, 0x333c0c00}, - { 0x20C4070, 0x3fff003f}, - { 0x20C4074, 0xfff33ff3}, - { 0x20C4078, 0xc0c3fc}, - { 0x20C407C, 0xf030fff}, - { 0x20C4080, 0x3cfc33}, - { 0x20C8000, 0x80002053}, - { 0x20C8010, 0x80003040}, - { 0x20C8020, 0x3840}, - { 0x20C8070, 0x119006}, - { 0x20C80A0, 0x80002025}, - { 0x20C80B0, 0x13a74}, - { 0x20C80C0, 0xf4240}, - { 0x20C80E0, 0x8030200f}, - { 0x20C80F0, 0xd3d1d0cc}, - { 0x20C8100, 0x5258d0db} - }; -} - - -struct Board::L2_cache : Hw::Pl310 -{ - L2_cache(Genode::addr_t mmio) : Hw::Pl310(mmio) - { - Aux::access_t aux = 0; - Aux::Full_line_of_zero::set(aux, true); - Aux::Associativity::set(aux, Aux::Associativity::WAY_16); - Aux::Way_size::set(aux, Aux::Way_size::KB_16); - Aux::Replacement_policy::set(aux, Aux::Replacement_policy::PRAND); - Aux::Ns_lockdown::set(aux, true); - Aux::Data_prefetch::set(aux, true); - Aux::Inst_prefetch::set(aux, true); - Aux::Early_bresp::set(aux, true); - write(aux); - - Tag_ram::access_t tag_ram = 0; - Tag_ram::Setup_latency::set(tag_ram, 2); - Tag_ram::Read_latency::set(tag_ram, 3); - Tag_ram::Write_latency::set(tag_ram, 1); - write(tag_ram); - - Data_ram::access_t data_ram = 0; - Data_ram::Setup_latency::set(data_ram, 2); - Data_ram::Read_latency::set(data_ram, 3); - Data_ram::Write_latency::set(data_ram, 1); - write(data_ram); - - Prefetch_ctrl::access_t prefetch = read(); - Prefetch_ctrl::Data_prefetch::set(prefetch, 1); - Prefetch_ctrl::Inst_prefetch::set(prefetch, 1); - write(prefetch | 0xF); - } - - using Hw::Pl310::invalidate; - - void enable() - { - Pl310::mask_interrupts(); - write(1); - } - - void disable() { - write(0); - } -}; - -#endif /* _SRC__BOOTSTRAP__SPEC__NIT6_SOLOX__BOARD_H_ */ diff --git a/repos/base-hw/src/bootstrap/board/pbxa9/platform.cc b/repos/base-hw/src/bootstrap/board/pbxa9/platform.cc index 8746729b57..6c71be40d1 100644 --- a/repos/base-hw/src/bootstrap/board/pbxa9/platform.cc +++ b/repos/base-hw/src/bootstrap/board/pbxa9/platform.cc @@ -40,12 +40,12 @@ void Board::Cpu::wake_up_all_cpus(void * const ip) * read out this register and jump to it after the cpu received * an interrupt */ - struct System_control : Genode::Mmio + struct System_control : Genode::Mmio<0x38> { struct Flagsset : Register<0x30, 32> { }; struct Flagsclr : Register<0x34, 32> { }; - System_control(void * const ip) : Mmio(SYSTEM_CONTROL_MMIO_BASE) + System_control(void * const ip) : Mmio({(char *)SYSTEM_CONTROL_MMIO_BASE, Mmio::SIZE}) { write(~0UL); write(reinterpret_cast(ip)); diff --git a/repos/base-hw/src/bootstrap/board/usb_armory/board.h b/repos/base-hw/src/bootstrap/board/usb_armory/board.h deleted file mode 100644 index 17540a22bb..0000000000 --- a/repos/base-hw/src/bootstrap/board/usb_armory/board.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * \brief i.MX53 Quickstart board definitions - * \author Stefan Kalkowski - * \date 2017-03-22 - */ - -/* - * Copyright (C) 2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _SRC__BOOTSTRAP__SPEC__USB_ARMORY__BOARD_H_ -#define _SRC__BOOTSTRAP__SPEC__USB_ARMORY__BOARD_H_ - -#include -#include - -#include -#include - -namespace Board { - - using namespace Hw::Usb_armory_board; - - using Hw::Pic; - - bool secure_irq(unsigned irq); -} - -#endif /* _SRC__BOOTSTRAP__SPEC__USB_ARMORY__BOARD_H_ */ diff --git a/repos/base-hw/src/bootstrap/board/usb_armory/platform.cc b/repos/base-hw/src/bootstrap/board/usb_armory/platform.cc deleted file mode 100644 index e055ae8f59..0000000000 --- a/repos/base-hw/src/bootstrap/board/usb_armory/platform.cc +++ /dev/null @@ -1,56 +0,0 @@ -/* - * \brief Specific i.MX53 bootstrap implementations - * \author Stefan Kalkowski - * \date 2012-10-24 - */ - -/* - * Copyright (C) 2012-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#include -#include -#include -#include - -using namespace Board; - - -bool Board::secure_irq(unsigned i) -{ - if (i == EPIT_1_IRQ) return true; - if (i == EPIT_2_IRQ) return true; - if (i == SDHC_IRQ) return true; - return false; -} - - -Bootstrap::Platform::Board::Board() -: - early_ram_regions(Memory_region { Trustzone::SECURE_RAM_BASE, - Trustzone::SECURE_RAM_SIZE }), - core_mmio(Memory_region { UART_1_MMIO_BASE, UART_1_MMIO_SIZE }, - Memory_region { EPIT_1_MMIO_BASE, EPIT_1_MMIO_SIZE }, - Memory_region { IRQ_CONTROLLER_BASE, IRQ_CONTROLLER_SIZE }, - Memory_region { CSU_BASE, CSU_SIZE }) -{ - Aipstz aipstz_1(AIPS_1_MMIO_BASE); - Aipstz aipstz_2(AIPS_2_MMIO_BASE); - - Pic pic {}; - - /* set monitor mode exception vector entry */ - Cpu::Mvbar::write(Hw::Mm::system_exception_vector().base); - - /* enable coprocessor 10 + 11 access for TZ VMs */ - Cpu::Nsacr::access_t v = 0; - Cpu::Nsacr::Cpnsae10::set(v, 1); - Cpu::Nsacr::Cpnsae11::set(v, 1); - Cpu::Nsacr::write(v); - - /* configure central security unit */ - Csu csu(CSU_BASE, true, false, true, false); -} diff --git a/repos/base-hw/src/bootstrap/board/virt_qemu_arm_v7a/board.h b/repos/base-hw/src/bootstrap/board/virt_qemu_arm_v7a/board.h index 4956b88bfc..0aaa5fc957 100644 --- a/repos/base-hw/src/bootstrap/board/virt_qemu_arm_v7a/board.h +++ b/repos/base-hw/src/bootstrap/board/virt_qemu_arm_v7a/board.h @@ -27,6 +27,8 @@ namespace Board { using Psci = Hw::Psci; using Pic = Hw::Gicv2; static constexpr bool NON_SECURE = true; + + static constexpr Genode::size_t NR_OF_CPUS = 2; }; #endif /* _SRC__BOOTSTRAP__SPEC__VIRT__QEMU_H_ */ diff --git a/repos/base-hw/src/bootstrap/board/virt_qemu_arm_v7a/platform.cc b/repos/base-hw/src/bootstrap/board/virt_qemu_arm_v7a/platform.cc index cf8e55cc2f..ead6097701 100644 --- a/repos/base-hw/src/bootstrap/board/virt_qemu_arm_v7a/platform.cc +++ b/repos/base-hw/src/bootstrap/board/virt_qemu_arm_v7a/platform.cc @@ -66,7 +66,7 @@ unsigned Bootstrap::Platform::enable_mmu() ::Board::Pic pic { }; /* primary cpu wakes up all others */ - if (primary_cpu && NR_OF_CPUS > 1) { + if (primary_cpu && ::Board::NR_OF_CPUS > 1) { Cpu::invalidate_data_cache(); primary_cpu = false; Cpu::wake_up_all_cpus(&_start_setup_stack); diff --git a/repos/base-hw/src/bootstrap/board/virt_qemu_arm_v8a/board.h b/repos/base-hw/src/bootstrap/board/virt_qemu_arm_v8a/board.h index 62a197fb70..b3ebd2f231 100644 --- a/repos/base-hw/src/bootstrap/board/virt_qemu_arm_v8a/board.h +++ b/repos/base-hw/src/bootstrap/board/virt_qemu_arm_v8a/board.h @@ -31,6 +31,8 @@ namespace Board { static void wake_up_all_cpus(void*); }; + static constexpr Genode::size_t NR_OF_CPUS = 4; + using Hw::Pic; }; diff --git a/repos/base-hw/src/bootstrap/board/wand_quad/board.h b/repos/base-hw/src/bootstrap/board/wand_quad/board.h deleted file mode 100644 index c52d24e810..0000000000 --- a/repos/base-hw/src/bootstrap/board/wand_quad/board.h +++ /dev/null @@ -1,258 +0,0 @@ -/* - * \brief Pbxa9 specific board definitions - * \author Stefan Kalkowski - * \date 2017-02-20 - */ - -/* - * Copyright (C) 2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _SRC__BOOTSTRAP__SPEC__WAND_QUAD__BOARD_H_ -#define _SRC__BOOTSTRAP__SPEC__WAND_QUAD__BOARD_H_ - -#include -#include -#include -#include -#include - -namespace Board { - - using namespace Hw::Wand_quad_board; - - using Pic = Hw::Gicv2; - - struct L2_cache; - - static constexpr bool NON_SECURE = false; - - static volatile unsigned long initial_values[][2] { - // (IOMUX Controller) - { 0x20e0000, 0x1 }, - { 0x20e0004, 0x48643005 }, - { 0x20e0008, 0x221 }, - { 0x20e000c, 0x1e00040 }, - { 0x20e0034, 0x593e4a4 }, - { 0x20e004c, 0x0 }, - { 0x20e0050, 0x0 }, - { 0x20e0054, 0x0 }, - { 0x20e0090, 0x1 }, - { 0x20e0094, 0x1 }, - { 0x20e0098, 0x1 }, - { 0x20e00a4, 0x16 }, - { 0x20e00a8, 0x4 }, - { 0x20e00ac, 0x2 }, - { 0x20e00b0, 0x2 }, - { 0x20e00b4, 0x2 }, - { 0x20e00b8, 0x2 }, - { 0x20e00c4, 0x11 }, - { 0x20e015c, 0x0 }, - { 0x20e0160, 0x0 }, - { 0x20e0164, 0x0 }, - { 0x20e0168, 0x0 }, - { 0x20e016c, 0x0 }, - { 0x20e0170, 0x0 }, - { 0x20e0174, 0x0 }, - { 0x20e0178, 0x0 }, - { 0x20e017c, 0x0 }, - { 0x20e0180, 0x0 }, - { 0x20e0184, 0x0 }, - { 0x20e0188, 0x0 }, - { 0x20e018c, 0x0 }, - { 0x20e0190, 0x0 }, - { 0x20e0194, 0x0 }, - { 0x20e0198, 0x0 }, - { 0x20e019c, 0x0 }, - { 0x20e01a0, 0x0 }, - { 0x20e01a4, 0x0 }, - { 0x20e01a8, 0x0 }, - { 0x20e01ac, 0x0 }, - { 0x20e01b0, 0x0 }, - { 0x20e01b4, 0x0 }, - { 0x20e01b8, 0x0 }, - { 0x20e01bc, 0x0 }, - { 0x20e01c0, 0x0 }, - { 0x20e01c4, 0x0 }, - { 0x20e01c8, 0x0 }, - { 0x20e01cc, 0x0 }, - { 0x20e01d4, 0x1 }, - { 0x20e01e4, 0x3 }, - { 0x20e0220, 0x0 }, - { 0x20e0224, 0x3 }, - { 0x20e022c, 0x4 }, - { 0x20e023c, 0x16 }, - { 0x20e0248, 0x12 }, - { 0x20e0250, 0x5 }, - { 0x20e0264, 0x5 }, - { 0x20e0268, 0x4 }, - { 0x20e026c, 0x4 }, - { 0x20e0270, 0x4 }, - { 0x20e0274, 0x4 }, - { 0x20e02b8, 0x0 }, - { 0x20e0320, 0x2 }, - { 0x20e0348, 0x0 }, - { 0x20e0354, 0x0 }, - { 0x20e0358, 0x0 }, - { 0x20e035c, 0x0 }, - { 0x20e0360, 0x17059 }, - { 0x20e0364, 0x17059 }, - { 0x20e0368, 0x17059 }, - { 0x20e03a0, 0xf0b0 }, - { 0x20e03a4, 0x100b1 }, - { 0x20e03a8, 0x100b1 }, - { 0x20e03ac, 0x100b1 }, - { 0x20e03b8, 0x1b8b1 }, - { 0x20e03c0, 0x1b0b1 }, - { 0x20e03c4, 0x1b0b1 }, - { 0x20e03c8, 0x1b0b1 }, - { 0x20e03cc, 0x1b0b1 }, - { 0x20e03d8, 0x1b8b1 }, - { 0x20e0470, 0x10 }, - { 0x20e0474, 0x10 }, - { 0x20e0478, 0x10 }, - { 0x20e047c, 0x10 }, - { 0x20e0484, 0x10 }, - { 0x20e0488, 0x10 }, - { 0x20e048c, 0x10 }, - { 0x20e0490, 0x10 }, - { 0x20e0494, 0x10 }, - { 0x20e0498, 0x10 }, - { 0x20e049c, 0x10 }, - { 0x20e04a0, 0x10 }, - { 0x20e04a4, 0x10 }, - { 0x20e04a8, 0x10 }, - { 0x20e04ac, 0x10 }, - { 0x20e04b0, 0x10 }, - { 0x20e04b4, 0x10 }, - { 0x20e04b8, 0x10 }, - { 0x20e04bc, 0x10 }, - { 0x20e04c0, 0x10 }, - { 0x20e04c4, 0x10 }, - { 0x20e04c8, 0x10 }, - { 0x20e04cc, 0x10 }, - { 0x20e04d0, 0x10 }, - { 0x20e04d4, 0x10 }, - { 0x20e04d8, 0x10 }, - { 0x20e04dc, 0x10 }, - { 0x20e04e0, 0x10 }, - { 0x20e05e8, 0xb0 }, - { 0x20e05f0, 0xb0 }, - { 0x20e05f4, 0x17059 }, - { 0x20e05fc, 0xb0 }, - { 0x20e0600, 0xb0b0 }, - { 0x20e060c, 0x1b8b1 }, - { 0x20e0618, 0x1b0a8 }, - { 0x20e0638, 0x130b0 }, - { 0x20e063c, 0x110b0 }, - { 0x20e0640, 0x130b0 }, - { 0x20e0644, 0x130b0 }, - { 0x20e064c, 0x1b0b0 }, - { 0x20e06a4, 0x10059 }, - { 0x20e0704, 0x0 }, - { 0x20e0708, 0x1b0b1 }, - { 0x20e0738, 0x10059 }, - { 0x20e073c, 0x10059 }, - { 0x20e0740, 0x17059 }, - { 0x20e0744, 0x17059 }, - { 0x20e083c, 0x1 }, - { 0x20e0870, 0x0 }, - { 0x20e0874, 0x0 }, - { 0x20e08a8, 0x2 }, - { 0x20e08ac, 0x2 }, - { 0x20e092c, 0x1 }, - { 0x20e0930, 0x1 }, - - // (Global Power Controller) - { 0x20dc008, 0x6a23e613 }, - { 0x20dc00c, 0xff69b64f }, - { 0x20dc010, 0xfffe0003 }, - { 0x20dc014, 0xff30f7ff }, - - // (Power Management Unit) - { 0x20c8120, 0x11775 }, - { 0x20c8140, 0x580016 }, - { 0x20c8160, 0x8000000b }, - { 0x20c8170, 0xc0672f67 }, - - // (Clock Controller Module) - { 0x20c4018, 0x10204 }, - { 0x20c402c, 0x7312c1 }, - { 0x20c4030, 0x32271f92 }, - { 0x20c4034, 0x12680 }, - { 0x20c4038, 0x12090 }, - { 0x20c4054, 0x78 }, - { 0x20c4058, 0x41a0000 }, - { 0x20c4060, 0x10e0101 }, - { 0x20c4064, 0x2fe62 }, - { 0x20c4068, 0xc03f0f }, - { 0x20c406c, 0x30fc00 }, - { 0x20c4070, 0x3ff0033 }, - { 0x20c4074, 0x3ff3303f }, - { 0x20c4078, 0x30c300 }, - { 0x20c407c, 0xf0000f3 }, - { 0x20c4080, 0xc00 }, - { 0x20c8000, 0x80002053 }, - { 0x20c8020, 0x3040 }, - { 0x20c8070, 0x1006 }, - { 0x20c80a0, 0x80002031 }, - { 0x20c80b0, 0x7a120 }, - { 0x20c80c0, 0xf4240 }, - { 0x20c80e0, 0x80002003 }, - { 0x20c80f0, 0x9391508c }, - { 0x20c8100, 0x5058d01b } - }; -} - - -struct Board::L2_cache : Hw::Pl310 -{ - L2_cache(Genode::addr_t mmio) : Hw::Pl310(mmio) - { - Aux::access_t aux = 0; - Aux::Full_line_of_zero::set(aux, true); - Aux::Associativity::set(aux, Aux::Associativity::WAY_16); - Aux::Way_size::set(aux, Aux::Way_size::KB_64); - Aux::Share_override::set(aux, true); - Aux::Replacement_policy::set(aux, Aux::Replacement_policy::PRAND); - Aux::Ns_lockdown::set(aux, true); - Aux::Data_prefetch::set(aux, true); - Aux::Inst_prefetch::set(aux, true); - Aux::Early_bresp::set(aux, true); - write(aux); - - Tag_ram::access_t tag_ram = 0; - Tag_ram::Setup_latency::set(tag_ram, 2); - Tag_ram::Read_latency::set(tag_ram, 3); - Tag_ram::Write_latency::set(tag_ram, 1); - write(tag_ram); - - Data_ram::access_t data_ram = 0; - Data_ram::Setup_latency::set(data_ram, 2); - Data_ram::Read_latency::set(data_ram, 3); - Data_ram::Write_latency::set(data_ram, 1); - write(data_ram); - - Prefetch_ctrl::access_t prefetch = 0; - Prefetch_ctrl::Data_prefetch::set(prefetch, 1); - Prefetch_ctrl::Inst_prefetch::set(prefetch, 1); - write(prefetch | 0xF); - } - - using Hw::Pl310::invalidate; - - void enable() - { - Pl310::mask_interrupts(); - write(1); - } - - void disable() { - write(0); - } -}; - -#endif /* _SRC__BOOTSTRAP__SPEC__WAND_QUAD__BOARD_H_ */ diff --git a/repos/base-hw/src/bootstrap/env.cc b/repos/base-hw/src/bootstrap/env.cc deleted file mode 100644 index 64ab81b271..0000000000 --- a/repos/base-hw/src/bootstrap/env.cc +++ /dev/null @@ -1,22 +0,0 @@ -/* - * \brief Environment dummy implementation needed by cxx library - * \author Stefan Kalkowski - * \date 2016-09-23 - */ - -/* - * Copyright (C) 2016-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#include -#include -#include - -Genode::Env_deprecated * Genode::env_deprecated() -{ - assert(false); - return nullptr; -} diff --git a/repos/base-hw/src/bootstrap/init.cc b/repos/base-hw/src/bootstrap/init.cc index 0cc92720fb..9fcda2fec3 100644 --- a/repos/base-hw/src/bootstrap/init.cc +++ b/repos/base-hw/src/bootstrap/init.cc @@ -18,6 +18,13 @@ #include #include +using namespace Genode; + +static constexpr size_t STACK_SIZE = 0x2000; + +size_t bootstrap_stack_size = STACK_SIZE; +uint8_t bootstrap_stack[Board::NR_OF_CPUS][STACK_SIZE] +__attribute__((aligned(get_page_size()))); Bootstrap::Platform & Bootstrap::platform() { return *unmanaged_singleton(); } diff --git a/repos/base-hw/src/bootstrap/platform.cc b/repos/base-hw/src/bootstrap/platform.cc index 8f56824ac3..93c17f91fb 100644 --- a/repos/base-hw/src/bootstrap/platform.cc +++ b/repos/base-hw/src/bootstrap/platform.cc @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -66,9 +67,9 @@ Platform::Pd::Pd(Platform::Ram_allocator & alloc) using namespace Genode; addr_t const table_virt_base = Hw::Mm::core_page_tables().base; map_insert(Mapping((addr_t)table_base, table_virt_base, - sizeof(Table), Hw::PAGE_FLAGS_KERN_DATA)); + sizeof(Table), Genode::PAGE_FLAGS_KERN_DATA)); map_insert(Mapping((addr_t)array_base, table_virt_base + sizeof(Table), - sizeof(Table_array), Hw::PAGE_FLAGS_KERN_DATA)); + sizeof(Table_array), Genode::PAGE_FLAGS_KERN_DATA)); } @@ -149,6 +150,36 @@ Mapping Platform::_load_elf() } +void Platform::_prepare_cpu_memory_area(size_t cpu_id) +{ + using namespace Genode; + using namespace Hw; + using namespace Hw::Mm; + + size_t slots = cpu_local_memory().size / CPU_LOCAL_MEMORY_SLOT_SIZE; + + if (cpu_id >= slots) { + error("CPU memory area too small for cpu id ", cpu_id); + error("CPU memory area can hold ", slots, " at max"); + return; + } + + Page_flags flags{RW, NO_EXEC, KERN, GLOBAL, RAM, CACHED}; + + addr_t base = cpu_local_memory().base + CPU_LOCAL_MEMORY_SLOT_SIZE*cpu_id; + void * const stack_ram = ram_alloc.alloc_aligned(KERNEL_STACK_SIZE, 1); + void * const cpu_ram = + ram_alloc.alloc_aligned(CPU_LOCAL_MEMORY_SLOT_OBJECT_SIZE, 1); + + core_pd->map_insert(Mapping((addr_t)stack_ram, + base+CPU_LOCAL_MEMORY_SLOT_STACK_OFFSET, + KERNEL_STACK_SIZE, flags)); + core_pd->map_insert(Mapping((addr_t)cpu_ram, + base+CPU_LOCAL_MEMORY_SLOT_OBJECT_OFFSET, + CPU_LOCAL_MEMORY_SLOT_OBJECT_SIZE, flags)); +} + + void Platform::start_core(unsigned cpu_id) { typedef void (* Entry)(unsigned) __attribute__((noreturn)); @@ -157,9 +188,9 @@ void Platform::start_core(unsigned cpu_id) } -static constexpr Genode::Boot_modules_header & header() +static constexpr Core::Boot_modules_header &header() { - return *((Genode::Boot_modules_header*) &_boot_modules_headers_begin); + return *((Core::Boot_modules_header*) &_boot_modules_headers_begin); } @@ -183,7 +214,9 @@ Platform::Platform() /* temporarily map all bootstrap memory 1:1 for transition to core */ // FIXME do not insert as mapping for core core_pd->map_insert(Mapping(bootstrap_region.base, bootstrap_region.base, - (addr_t)&_bss_end - (addr_t)&_prog_img_beg, Hw::PAGE_FLAGS_KERN_TEXT)); + (addr_t)&_bss_end - (addr_t)&_prog_img_beg, Genode::PAGE_FLAGS_KERN_TEXT)); + + board.cpus = _prepare_cpu_memory_area(); /* map memory-mapped I/O for core */ board.core_mmio.for_each_mapping([&] (Mapping const & m) { @@ -195,7 +228,7 @@ Platform::Platform() /* setup boot info page */ void * bi_base = ram_alloc.alloc(sizeof(Boot_info)); core_pd->map_insert(Mapping((addr_t)bi_base, Hw::Mm::boot_info().base, - sizeof(Boot_info), Hw::PAGE_FLAGS_KERN_TEXT)); + sizeof(Boot_info), Genode::PAGE_FLAGS_KERN_TEXT)); Boot_info & bootinfo = *construct_at(bi_base, (addr_t)&core_pd->table, (addr_t)&core_pd->array, diff --git a/repos/base-hw/src/bootstrap/platform.h b/repos/base-hw/src/bootstrap/platform.h index bc6deebe25..f9aa11657b 100644 --- a/repos/base-hw/src/bootstrap/platform.h +++ b/repos/base-hw/src/bootstrap/platform.h @@ -45,9 +45,9 @@ class Bootstrap::Platform { Memory_region_array early_ram_regions { }; Memory_region_array late_ram_regions { }; - Mmio_space const core_mmio; - unsigned cpus { NR_OF_CPUS }; - ::Board::Boot_info info { }; + Mmio_space core_mmio; + unsigned cpus { }; + ::Board::Boot_info info { }; Board(); }; @@ -83,13 +83,12 @@ class Bootstrap::Platform void add(Memory_region const &); void remove(Memory_region const &); - template - void for_each_free_region(FUNC functor) + void for_each_free_region(auto const &fn) { _block_tree().for_each([&] (Block const & b) { if (!b.used()) - functor(Memory_region(b.addr(), b.size())); + fn(Memory_region(b.addr(), b.size())); }); } }; @@ -117,13 +116,13 @@ class Bootstrap::Platform { Elf(addr_t const addr) : Genode::Elf_binary(addr) { } - template void for_each_segment(T functor) + void for_each_segment(auto const &fn) { Genode::Elf_segment segment; for (unsigned i = 0; (segment = get_segment(i)).valid(); i++) { if (segment.flags().skip) continue; if (segment.mem_size() == 0) continue; - functor(segment); + fn(segment); } } }; @@ -135,7 +134,9 @@ class Bootstrap::Platform addr_t core_elf_addr; Elf core_elf; - Mapping _load_elf(); + Mapping _load_elf(); + void _prepare_cpu_memory_area(size_t id); + unsigned _prepare_cpu_memory_area(); public: diff --git a/repos/base-hw/src/bootstrap/platform_cpu_memory_area.cc b/repos/base-hw/src/bootstrap/platform_cpu_memory_area.cc new file mode 100644 index 0000000000..f9c8419315 --- /dev/null +++ b/repos/base-hw/src/bootstrap/platform_cpu_memory_area.cc @@ -0,0 +1,24 @@ +/* + * \brief Platform CPU memory area preparation + * \author Stefan Kalkowski + * \date 2024-04-25 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#include + + +unsigned Bootstrap::Platform::_prepare_cpu_memory_area() +{ + using namespace Genode; + + for (size_t id = 0; id < ::Board::NR_OF_CPUS; id++) + _prepare_cpu_memory_area(id); + return ::Board::NR_OF_CPUS; +} diff --git a/repos/base-hw/src/bootstrap/spec/arm/cortex_a9_mmu.cc b/repos/base-hw/src/bootstrap/spec/arm/cortex_a9_mmu.cc index 1262bd0890..b1e62c1233 100644 --- a/repos/base-hw/src/bootstrap/spec/arm/cortex_a9_mmu.cc +++ b/repos/base-hw/src/bootstrap/spec/arm/cortex_a9_mmu.cc @@ -42,7 +42,7 @@ class Cpu_counter { while (!Genode::cmpxchg((volatile int*)&_locked, UNLOCKED, LOCKED)) ; - _counter++; + _counter = _counter + 1; Genode::memory_barrier(); _locked = UNLOCKED; } @@ -52,7 +52,7 @@ class Cpu_counter }; -struct Scu : Genode::Mmio +struct Scu : Genode::Mmio<0x34> { struct Cr : Register<0x0, 32> { @@ -72,7 +72,7 @@ struct Scu : Genode::Mmio struct Cpu3_way : Bitfield<12, 4> { }; }; - Scu() : Genode::Mmio(Board::Cpu_mmio::SCU_MMIO_BASE) { } + Scu() : Mmio({(char *)Board::Cpu_mmio::SCU_MMIO_BASE, Mmio::SIZE}) { } void invalidate() { diff --git a/repos/base-hw/src/bootstrap/spec/arm/crt0.s b/repos/base-hw/src/bootstrap/spec/arm/crt0.s index 32c42286bc..8c9e6d3023 100644 --- a/repos/base-hw/src/bootstrap/spec/arm/crt0.s +++ b/repos/base-hw/src/bootstrap/spec/arm/crt0.s @@ -63,8 +63,10 @@ mrcne p15, 0, sp, c0, c0, 5 /* read multiprocessor affinity register */ andne sp, sp, #0xff /* set cpu id for non-boot cpu */ - adr r0, _start_stack /* load stack address into r0 */ - adr r1, _start_stack_size /* load stack size per cpu into r1 */ + adr r0, _bootstrap_stack_local /* load stack address into r0 */ + adr r1, _bootstrap_stack_size_local /* load stack size per cpu into r1 */ + ldr r0, [r0] + ldr r1, [r1] ldr r1, [r1] add sp, #1 /* calculate stack start for CPU */ @@ -101,11 +103,8 @@ _bss_local_end: .long _bss_end - _start_stack_size: - .long STACK_SIZE + _bootstrap_stack_local: + .long bootstrap_stack - .align 3 - _start_stack: - .rept NR_OF_CPUS - .space STACK_SIZE - .endr + _bootstrap_stack_size_local: + .long bootstrap_stack_size diff --git a/repos/base-hw/src/bootstrap/spec/arm/gicv3.cc b/repos/base-hw/src/bootstrap/spec/arm/gicv3.cc index 36d5c55a38..8b9015f371 100644 --- a/repos/base-hw/src/bootstrap/spec/arm/gicv3.cc +++ b/repos/base-hw/src/bootstrap/spec/arm/gicv3.cc @@ -15,10 +15,14 @@ Hw::Pic::Pic() : - _distr(Board::Cpu_mmio::IRQ_CONTROLLER_DISTR_BASE), - _redistr(Board::Cpu_mmio::IRQ_CONTROLLER_REDIST_BASE), - _redistr_sgi(Board::Cpu_mmio::IRQ_CONTROLLER_REDIST_BASE + - Board::Cpu_mmio::IRQ_CONTROLLER_REDIST_SIZE / 2), + _distr({(char *)Board::Cpu_mmio::IRQ_CONTROLLER_DISTR_BASE, + Board::Cpu_mmio::IRQ_CONTROLLER_DISTR_SIZE}), + _redistr({(char *)Board::Cpu_mmio::IRQ_CONTROLLER_REDIST_BASE, + Board::Cpu_mmio::IRQ_CONTROLLER_REDIST_SIZE}), + _redistr_sgi({(char *)Board::Cpu_mmio::IRQ_CONTROLLER_REDIST_BASE + + Board::Cpu_mmio::IRQ_CONTROLLER_REDIST_SIZE / 2, + Board::Cpu_mmio::IRQ_CONTROLLER_REDIST_BASE - + Board::Cpu_mmio::IRQ_CONTROLLER_REDIST_SIZE / 2}), _max_irq(_distr.max_irq()) { /* disable device */ diff --git a/repos/base-hw/src/bootstrap/spec/arm/imx6_platform.cc b/repos/base-hw/src/bootstrap/spec/arm/imx6_platform.cc deleted file mode 100644 index b77e33f5d9..0000000000 --- a/repos/base-hw/src/bootstrap/spec/arm/imx6_platform.cc +++ /dev/null @@ -1,79 +0,0 @@ -/* - * \brief Specific bootstrap implementations - * \author Stefan Kalkowski - * \author Josef Soentgen - * \author Martin Stein - * \date 2014-02-25 - */ - -/* - * Copyright (C) 2014-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#include -#include - -using namespace Board; - -Bootstrap::Platform::Board::Board() -: - early_ram_regions(Memory_region { RAM_BASE, RAM_SIZE }), - core_mmio(Memory_region { UART_BASE, - UART_SIZE }, - Memory_region { CORTEX_A9_PRIVATE_MEM_BASE, - CORTEX_A9_PRIVATE_MEM_SIZE }, - Memory_region { PL310_MMIO_BASE, - PL310_MMIO_SIZE }) -{ - Aipstz aipstz_1(AIPS_1_MMIO_BASE); - Aipstz aipstz_2(AIPS_2_MMIO_BASE); - - unsigned num_values = sizeof(initial_values) / (2*sizeof(unsigned long)); - for (unsigned i = 0; i < num_values; i++) - *((volatile unsigned long*)initial_values[i][0]) = initial_values[i][1]; -} - - -bool Board::Cpu::errata(Board::Cpu::Errata err) { - return (err == ARM_764369) ? true : false; } - - -void Board::Cpu::wake_up_all_cpus(void * const entry) -{ - struct Src : Genode::Mmio - { - struct Scr : Register<0x0, 32> - { - struct Core_1_reset : Bitfield<14,1> {}; - struct Core_2_reset : Bitfield<15,1> {}; - struct Core_3_reset : Bitfield<16,1> {}; - struct Core_1_enable : Bitfield<22,1> {}; - struct Core_2_enable : Bitfield<23,1> {}; - struct Core_3_enable : Bitfield<24,1> {}; - }; - struct Gpr1 : Register<0x20, 32> {}; /* ep core 0 */ - struct Gpr3 : Register<0x28, 32> {}; /* ep core 1 */ - struct Gpr5 : Register<0x30, 32> {}; /* ep core 2 */ - struct Gpr7 : Register<0x38, 32> {}; /* ep core 3 */ - - Src(void * const entry) : Genode::Mmio(SRC_MMIO_BASE) - { - write((Gpr3::access_t)entry); - write((Gpr5::access_t)entry); - write((Gpr7::access_t)entry); - Scr::access_t v = read(); - Scr::Core_1_enable::set(v,1); - Scr::Core_1_reset::set(v,1); - Scr::Core_2_enable::set(v,1); - Scr::Core_2_reset::set(v,1); - Scr::Core_3_enable::set(v,1); - Scr::Core_3_reset::set(v,1); - write(v); - } - }; - - Src src(entry); -} diff --git a/repos/base-hw/src/bootstrap/spec/arm/imx_aipstz.h b/repos/base-hw/src/bootstrap/spec/arm/imx_aipstz.h deleted file mode 100644 index 5d6906561c..0000000000 --- a/repos/base-hw/src/bootstrap/spec/arm/imx_aipstz.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * \brief Driver for Freescale's AIPSTZ bridge - * \author Stefan Kalkowski - * \author Martin Stein - * \date 2012-10-24 - */ - -/* - * Copyright (C) 2012-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _SRC__BOOTSTRAP__SPEC__ARM__IMX_AIPSTZ_H_ -#define _SRC__BOOTSTRAP__SPEC__ARM__IMX_AIPSTZ_H_ - -#include - -namespace Bootstrap { - - /** - * AHB to IP Bridge - * - * Interface between the system bus and lower bandwidth IP Slave (IPS) - * bus peripherals. - */ - class Aipstz; -} - - -class Bootstrap::Aipstz : public Genode::Mmio -{ - private: - - /* - * Configuration of the masters - */ - - struct Mpr { enum { ALL_UNBUFFERED_AND_FULLY_TRUSTED = 0x77777777 }; }; - struct Mpr1 : Register<0x0, 32>, Mpr { }; - struct Mpr2 : Register<0x4, 32>, Mpr { }; - - /* - * Configuration of the platform peripherals - */ - - struct Pacr { enum { ALL_UNBUFFERED_AND_FULLY_UNPROTECTED = 0 }; }; - struct Pacr1 : Register<0x20, 32>, Pacr { }; - struct Pacr2 : Register<0x24, 32>, Pacr { }; - struct Pacr3 : Register<0x28, 32>, Pacr { }; - struct Pacr4 : Register<0x2c, 32>, Pacr { }; - - /* - * Configuration of the off-platform peripherals - */ - - struct Opacr1 : Register<0x40, 32>, Pacr { }; - struct Opacr2 : Register<0x44, 32>, Pacr { }; - struct Opacr3 : Register<0x48, 32>, Pacr { }; - struct Opacr4 : Register<0x4c, 32>, Pacr { }; - struct Opacr5 : Register<0x50, 32>, Pacr { }; - - public: - - /** - * Configure this module appropriately for the first kernel run - */ - Aipstz(Genode::addr_t const base) : Genode::Mmio(base) - { - /* avoid AIPS intervention at any memory access */ - write(Mpr::ALL_UNBUFFERED_AND_FULLY_TRUSTED); - write(Mpr::ALL_UNBUFFERED_AND_FULLY_TRUSTED); - write(Pacr::ALL_UNBUFFERED_AND_FULLY_UNPROTECTED); - write(Pacr::ALL_UNBUFFERED_AND_FULLY_UNPROTECTED); - write(Pacr::ALL_UNBUFFERED_AND_FULLY_UNPROTECTED); - write(Pacr::ALL_UNBUFFERED_AND_FULLY_UNPROTECTED); - write(Pacr::ALL_UNBUFFERED_AND_FULLY_UNPROTECTED); - write(Pacr::ALL_UNBUFFERED_AND_FULLY_UNPROTECTED); - write(Pacr::ALL_UNBUFFERED_AND_FULLY_UNPROTECTED); - write(Pacr::ALL_UNBUFFERED_AND_FULLY_UNPROTECTED); - write(Pacr::ALL_UNBUFFERED_AND_FULLY_UNPROTECTED); - } -}; - -#endif /* _SRC__BOOTSTRAP__SPEC__ARM__IMX_AIPSTZ_H_ */ diff --git a/repos/base-hw/src/bootstrap/spec/arm/imx_csu.h b/repos/base-hw/src/bootstrap/spec/arm/imx_csu.h deleted file mode 100644 index 51793ce9af..0000000000 --- a/repos/base-hw/src/bootstrap/spec/arm/imx_csu.h +++ /dev/null @@ -1,235 +0,0 @@ -/* - * \brief Driver for the Central Security Unit - * \author Stefan Kalkowski - * \date 2012-11-06 - */ - -/* - * Copyright (C) 2012-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _SRC__BOOTSTRAP__SPEC__ARM__IMX_CSU_H_ -#define _SRC__BOOTSTRAP__SPEC__ARM__IMX_CSU_H_ - -#include -#include - -namespace Bootstrap { struct Csu; } - - -struct Bootstrap::Csu : Genode::Mmio -{ - template - struct Csl : public Register - { - enum { - SECURE = 0x33, - UNSECURE = 0xff, - }; - - struct Slave_a : Register::template Bitfield<0, 9> { }; - struct Slave_b : Register::template Bitfield<16, 9> { }; - }; - - - struct Master : public Register<0x218, 32> - { - enum { - SECURE_UNLOCKED, - UNSECURE_UNLOCKED, - SECURE_LOCKED, - UNSECURE_LOCKED - }; - - struct Esdhc3 : Bitfield<0,2> { }; - struct Cortex : Bitfield<2,2> { }; - struct Sdma : Bitfield<4,2> { }; - struct Gpu : Bitfield<6,2> { }; - struct Usb : Bitfield<8,2> { }; - struct Pata : Bitfield<10,2> { }; - struct Mlb : Bitfield<14,2> { }; - struct Rtic : Bitfield<18,2> { }; - struct Esdhc4 : Bitfield<20,2> { }; - struct Fec : Bitfield<22,2> { }; - struct Dap : Bitfield<24,2> { }; - struct Esdhc1 : Bitfield<26,2> { }; - struct Esdhc2 : Bitfield<28,2> { }; - }; - - struct Alarm_mask : public Register<0x230, 32> { }; - struct Irq_ctrl : public Register<0x368, 32> { }; - - typedef Csl<0x00> Csl00; - typedef Csl<0x04> Csl01; - typedef Csl<0x08> Csl02; - typedef Csl<0x0c> Csl03; - typedef Csl<0x10> Csl04; - typedef Csl<0x14> Csl05; - typedef Csl<0x18> Csl06; - typedef Csl<0x1c> Csl07; - typedef Csl<0x20> Csl08; - typedef Csl<0x24> Csl09; - typedef Csl<0x28> Csl10; - typedef Csl<0x2c> Csl11; - typedef Csl<0x30> Csl12; - typedef Csl<0x34> Csl13; - typedef Csl<0x38> Csl14; - typedef Csl<0x3c> Csl15; - typedef Csl<0x40> Csl16; - typedef Csl<0x44> Csl17; - typedef Csl<0x48> Csl18; - typedef Csl<0x4c> Csl19; - typedef Csl<0x50> Csl20; - typedef Csl<0x54> Csl21; - typedef Csl<0x58> Csl22; - typedef Csl<0x5c> Csl23; - typedef Csl<0x60> Csl24; - typedef Csl<0x64> Csl25; - typedef Csl<0x68> Csl26; - typedef Csl<0x6c> Csl27; - typedef Csl<0x70> Csl28; - typedef Csl<0x74> Csl29; - typedef Csl<0x78> Csl30; - typedef Csl<0x7c> Csl31; - - Csu(Genode::addr_t base, - bool secure_uart, - bool secure_gpio, - bool secure_esdhc, - bool secure_i2c) : Genode::Mmio(base) - { - /* Power (CCM, SRC, DPLLIP1-4, GPC and OWIRE) */ - write(Csl00::UNSECURE); - - /* AHBMAX S0-S2 */ - write(Csl00::UNSECURE); - write(Csl00::UNSECURE); - write(Csl00::UNSECURE); - - /* AHBMAX M6 */ - write(Csl00::UNSECURE); - - /* Timer (EPIT, GPT) TODO */ - write(Csl00::UNSECURE); - - /* UART 1-5 */ - Csl00::access_t uart_csl = - secure_uart ? Csl00::SECURE : Csl00::UNSECURE; - write(uart_csl); - write(uart_csl); - write(uart_csl); - write(uart_csl); - write(uart_csl); - - /* GPIO */ - Csl00::access_t gpio_csl = - secure_gpio ? Csl00::SECURE : Csl00::UNSECURE; - write(gpio_csl); - write(gpio_csl); - write(gpio_csl); - write(gpio_csl); - - /* IOMUXC TODO */ - write(Csl00::UNSECURE); - - /* SDMA TODO */ - write(Csl00::UNSECURE); - - /* USB */ - write(Csl00::UNSECURE); - - /* TVE */ - write(Csl00::SECURE); - - /* I2C */ - Csl00::access_t i2c_csl = - secure_i2c ? Csl00::SECURE : Csl00::UNSECURE; - write(i2c_csl); - write(i2c_csl); - write(i2c_csl); - - /* IPU */ - write(Csl00::SECURE); - - /* Audio */ - write(Csl00::UNSECURE); - - /* SATA */ - write(Csl00::UNSECURE); - - /* FEC */ - write(Csl00::UNSECURE); - - /* SDHCI 1-4 */ - Csl00::access_t esdhc_csl = - secure_esdhc ? Csl00::SECURE : Csl00::UNSECURE; - write(esdhc_csl); - write(esdhc_csl); - write(esdhc_csl); - write(esdhc_csl); - - /* SPDIF */ - write(Csl00::UNSECURE); - - /* GPU 2D */ - write(Csl00::SECURE); - - /* GPU 3D */ - write(Csl00::SECURE); - - write(Csl00::UNSECURE); - write(Csl00::UNSECURE); - write(Csl00::UNSECURE); - write(Csl00::UNSECURE); // SRTC - write(Csl00::UNSECURE); - write(Csl00::UNSECURE); - write(Csl00::UNSECURE); - write(Csl00::UNSECURE); - write(Csl00::UNSECURE); - write(Csl00::UNSECURE); - write(Csl00::UNSECURE); - write(Csl00::UNSECURE); - write(Csl00::UNSECURE); - write(Csl00::UNSECURE); - write(Csl00::UNSECURE); - write(Csl00::UNSECURE); - write(Csl00::UNSECURE); // SCC - write(Csl00::UNSECURE); - write(Csl00::UNSECURE); // RTIC - write(Csl00::UNSECURE); - write(Csl00::UNSECURE); - write(Csl00::UNSECURE); - write(Csl00::UNSECURE); - write(Csl00::UNSECURE); - write(Csl00::SECURE); //VPU - write(Csl00::UNSECURE); - write(Csl00::UNSECURE); - write(Csl00::UNSECURE); - write(Csl00::UNSECURE); - write(Csl00::UNSECURE); - write(Csl00::UNSECURE); - - /* DMA from graphical subsystem is considered to be secure */ - write(Master::SECURE_UNLOCKED); - - /* all other DMA operations are insecure */ - write(Master::UNSECURE_UNLOCKED); - write(Master::UNSECURE_UNLOCKED); - write(Master::UNSECURE_UNLOCKED); - write(Master::UNSECURE_UNLOCKED); - write(Master::UNSECURE_UNLOCKED); - - Master::access_t esdhc_master = - secure_esdhc ? Master::SECURE_UNLOCKED - : Master::UNSECURE_UNLOCKED; - write(esdhc_master); - write(esdhc_master); - write(esdhc_master); - write(esdhc_master); - } -}; - -#endif /* _SRC__BOOTSTRAP__SPEC__ARM__IMX_CSU_H_ */ diff --git a/repos/base-hw/src/bootstrap/spec/arm/imx_tzic.cc b/repos/base-hw/src/bootstrap/spec/arm/imx_tzic.cc deleted file mode 100644 index b9b4e78b1d..0000000000 --- a/repos/base-hw/src/bootstrap/spec/arm/imx_tzic.cc +++ /dev/null @@ -1,31 +0,0 @@ -/* - * \brief Freescale's TrustZone aware interrupt controller - * \author Stefan Kalkowski - * \date 2012-10-24 - */ - -/* - * Copyright (C) 2012-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#include - -Hw::Pic::Pic() -: - Genode::Mmio(Board::IRQ_CONTROLLER_BASE) -{ - for (unsigned i = 0; i < NR_OF_IRQ; i++) { - write(!Board::secure_irq(i), i); - if (!Board::secure_irq(i)) write(0x80, i); - write(1, i); - } - write(0xff); - Intctrl::access_t v = 0; - Intctrl::Enable::set(v, 1); - Intctrl::Nsen::set(v, 1); - Intctrl::Nsen_mask::set(v, 1); - write(v); -} diff --git a/repos/base-hw/src/bootstrap/spec/arm_64/cortex_a53_mmu.cc b/repos/base-hw/src/bootstrap/spec/arm_64/cortex_a53_mmu.cc index e0a80d13bf..5324a5a803 100644 --- a/repos/base-hw/src/bootstrap/spec/arm_64/cortex_a53_mmu.cc +++ b/repos/base-hw/src/bootstrap/spec/arm_64/cortex_a53_mmu.cc @@ -64,7 +64,7 @@ static inline void prepare_hypervisor(Cpu::Ttbr::access_t const ttbr, using namespace Hw::Mm; /* forbid trace access */ - Cpu::Cptr_el2::access_t cptr = Cpu::Cptr_el2::read(); + Cpu::Cptr_el2::access_t cptr = 0; Cpu::Cptr_el2::Tta::set(cptr, 1); Cpu::Cptr_el2::write(cptr); @@ -74,7 +74,7 @@ static inline void prepare_hypervisor(Cpu::Ttbr::access_t const ttbr, /* forbid any 32bit access to coprocessor/sysregs */ Cpu::Hstr_el2::write(0xffff); - Cpu::Hcr_el2::access_t hcr = Cpu::Hcr_el2::read(); + Cpu::Hcr_el2::access_t hcr = 0; Cpu::Hcr_el2::Rw::set(hcr, 1); /* exec in aarch64 */ Cpu::Hcr_el2::write(hcr); @@ -145,7 +145,8 @@ unsigned Bootstrap::Platform::enable_mmu() Cpu::Ttbr::Baddr::masked((Genode::addr_t)core_pd->table_base); /* primary cpu wakes up all others */ - if (primary && NR_OF_CPUS > 1) Cpu::wake_up_all_cpus(&_crt0_start_secondary); + if (primary && ::Board::NR_OF_CPUS > 1) + Cpu::wake_up_all_cpus(&_crt0_start_secondary); while (Cpu::current_privilege_level() > Cpu::Current_el::EL1) { if (Cpu::current_privilege_level() == Cpu::Current_el::EL3) { @@ -199,6 +200,7 @@ unsigned Bootstrap::Platform::enable_mmu() Cpu::Sctlr::Sa0::set(sctlr, 1); Cpu::Sctlr::Sa::set(sctlr, 0); Cpu::Sctlr::Uct::set(sctlr, 1); + Cpu::Sctlr::Uci::set(sctlr, 1); Cpu::Sctlr_el1::write(sctlr); return cpu_id; diff --git a/repos/base-hw/src/bootstrap/spec/arm_64/crt0.s b/repos/base-hw/src/bootstrap/spec/arm_64/crt0.s index 046fc94b03..22e08a95ca 100644 --- a/repos/base-hw/src/bootstrap/spec/arm_64/crt0.s +++ b/repos/base-hw/src/bootstrap/spec/arm_64/crt0.s @@ -114,19 +114,12 @@ ** Initialize stack ** **********************/ - .set STACK_SIZE, 0x2000 - _cpu_number - ldr x1, =_crt0_start_stack - ldr x2, [x1] + ldr x1, =bootstrap_stack + ldr x2, =bootstrap_stack_size + ldr x2, [x2] + add x0, x0, #1 mul x0, x0, x2 add x1, x1, x0 mov sp, x1 bl init - - .p2align 4 - .rept NR_OF_CPUS - .space STACK_SIZE - .endr - _crt0_start_stack: - .quad STACK_SIZE diff --git a/repos/base-hw/src/bootstrap/spec/x86_64/crt0.s b/repos/base-hw/src/bootstrap/spec/x86_64/crt0.s index d158d6d68a..ba927a3f76 100644 --- a/repos/base-hw/src/bootstrap/spec/x86_64/crt0.s +++ b/repos/base-hw/src/bootstrap/spec/x86_64/crt0.s @@ -143,16 +143,14 @@ __gdt: movq $1, %rcx lock xaddq %rcx, (%rax) - /* if more CPUs started than supported, then stop them */ - cmp $NR_OF_CPUS, %rcx - jge 1f - /* calculate stack depending on CPU counter */ - movq $STACK_SIZE, %rax + leaq bootstrap_stack_size@GOTPCREL(%rip),%rax + movq (%rax), %rax + movq (%rax), %rax inc %rcx mulq %rcx movq %rax, %rcx - leaq __bootstrap_stack@GOTPCREL(%rip),%rax + leaq bootstrap_stack@GOTPCREL(%rip),%rax movq (%rax), %rsp addq %rcx, %rsp @@ -182,10 +180,6 @@ __gdt: jmp 1b - .global bootstrap_stack_size - bootstrap_stack_size: - .quad STACK_SIZE - /****************************************** ** Global Descriptor Table (GDT) ** ** See Intel SDM Vol. 3A, section 3.5.1 ** @@ -236,14 +230,7 @@ __gdt: *********************************/ .bss - - /* stack of the temporary initial environment */ .p2align 12 - .globl __bootstrap_stack - __bootstrap_stack: - .rept NR_OF_CPUS - .space STACK_SIZE - .endr .globl __initial_ax __initial_ax: diff --git a/repos/base-hw/src/bootstrap/spec/x86_64/crt0_translation_table.s b/repos/base-hw/src/bootstrap/spec/x86_64/crt0_translation_table.s index 6fbde692ce..9a374a4d28 100644 --- a/repos/base-hw/src/bootstrap/spec/x86_64/crt0_translation_table.s +++ b/repos/base-hw/src/bootstrap/spec/x86_64/crt0_translation_table.s @@ -18,7 +18,7 @@ .data /******************************************** - ** Identity mapping from 4KiB to 1GiB ** + ** Identity mapping from 4KiB to 4GiB ** ** plus mappings for LAPIC, I/O APIC MMIO ** ** Page 0 containing the Bios Data Area ** ** gets mapped to 2MiB - 4KiB readonly. ** @@ -35,7 +35,7 @@ .p2align MIN_PAGE_SIZE_LOG2 _kernel_pdp: .quad _kernel_pd_0 + 0xf - .fill 1, 8, 0x0 + .quad _kernel_pd_1 + 0xf .quad _kernel_pd_2 + 0xf .quad _kernel_pd_3 + 0xf .fill 508, 8, 0x0 @@ -50,6 +50,15 @@ .set entry, entry + 0x200000 .endr + /* PD [1G-2G) */ + .p2align MIN_PAGE_SIZE_LOG2 + _kernel_pd_1: + .set entry, 0x4000018f + .rept 512 + .quad entry + .set entry, entry + 0x200000 + .endr + /* PD [2G-3G) */ .p2align MIN_PAGE_SIZE_LOG2 _kernel_pd_2: diff --git a/repos/base-hw/src/bootstrap/spec/x86_64/multiboot.h b/repos/base-hw/src/bootstrap/spec/x86_64/multiboot.h index 5c83d806dd..f130674baa 100644 --- a/repos/base-hw/src/bootstrap/spec/x86_64/multiboot.h +++ b/repos/base-hw/src/bootstrap/spec/x86_64/multiboot.h @@ -21,7 +21,7 @@ namespace Genode { class Multiboot_info; } -class Genode::Multiboot_info : Mmio +class Genode::Multiboot_info : Mmio<0x34> { private: @@ -39,17 +39,17 @@ class Genode::Multiboot_info : Mmio MAGIC = 0x2badb002, }; - Multiboot_info(addr_t mbi) : Mmio(mbi) { } + Multiboot_info(addr_t mbi) : Mmio({(char *)mbi, Mmio::SIZE}) { } Multiboot_info(addr_t mbi, bool strip); - struct Mmap : Genode::Mmio + struct Mmap : Genode::Mmio<0x1c> { struct Size : Register <0x00, 32> { }; struct Addr : Register <0x04, 64> { }; struct Length : Register <0x0c, 64> { }; struct Type : Register <0x14, 8> { enum { MEMORY = 1 }; }; - Mmap(addr_t mmap = 0) : Mmio(mmap) { } + Mmap(addr_t mmap = 0) : Mmio({(char *)mmap, Mmio::SIZE}) { } }; /** diff --git a/repos/base-hw/src/bootstrap/spec/x86_64/multiboot2.h b/repos/base-hw/src/bootstrap/spec/x86_64/multiboot2.h index af10f76946..3fb5fdf4ad 100644 --- a/repos/base-hw/src/bootstrap/spec/x86_64/multiboot2.h +++ b/repos/base-hw/src/bootstrap/spec/x86_64/multiboot2.h @@ -19,13 +19,14 @@ namespace Genode { class Multiboot2_info; } -class Genode::Multiboot2_info : Mmio +class Genode::Multiboot2_info : Mmio<0x8> { private: struct Size : Register <0x0, 32> { }; - struct Tag : Genode::Mmio + template + struct Tag_tpl : Genode::Mmio { enum { LOG2_SIZE = 3 }; @@ -42,21 +43,23 @@ class Genode::Multiboot2_info : Mmio }; struct Size : Register <0x04, 32> { }; - Tag(addr_t addr) : Mmio(addr) { } + Tag_tpl(addr_t addr) : Mmio({(char *)addr, SIZE}) { } }; - struct Efi_system_table_64 : Tag + using Tag = Tag_tpl<0x8>; + + struct Efi_system_table_64 : Tag_tpl<0x10> { struct Pointer : Register <0x08, 64> { }; - Efi_system_table_64(addr_t addr) : Tag(addr) { } + Efi_system_table_64(addr_t addr) : Tag_tpl(addr) { } }; public: enum { MAGIC = 0x36d76289UL }; - struct Memory : Genode::Mmio + struct Memory : Genode::Mmio<0x14> { enum { SIZE = 3 * 8 }; @@ -64,19 +67,15 @@ class Genode::Multiboot2_info : Mmio struct Size : Register <0x08, 64> { }; struct Type : Register <0x10, 32> { enum { MEMORY = 1 }; }; - Memory(addr_t mmap = 0) : Mmio(mmap) { } + Memory(addr_t mmap = 0) : Mmio({(char *)mmap, Mmio::SIZE}) { } }; - Multiboot2_info(addr_t mbi) : Mmio(mbi) { } + Multiboot2_info(addr_t mbi) : Mmio({(char *)mbi, Mmio::SIZE}) { } - template - void for_each_tag(FUNC_MEM mem_fn, - FUNC_ACPI acpi_fn, - FUNC_FB fb_fn, - FUNC_SYSTAB64 systab64_fn) + void for_each_tag(auto const &mem_fn, + auto const &acpi_fn, + auto const &fb_fn, + auto const &systab64_fn) { addr_t const size = read(); diff --git a/repos/base-hw/src/bootstrap/spec/x86_64/platform.cc b/repos/base-hw/src/bootstrap/spec/x86_64/platform.cc index 3dace7cf8b..ed38b1d5e5 100644 --- a/repos/base-hw/src/bootstrap/spec/x86_64/platform.cc +++ b/repos/base-hw/src/bootstrap/spec/x86_64/platform.cc @@ -7,7 +7,7 @@ */ /* - * Copyright (C) 2015-2018 Genode Labs GmbH + * Copyright (C) 2015-2022 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -19,7 +19,9 @@ #include #include +#include #include +#include using namespace Genode; @@ -31,10 +33,10 @@ extern "C" Genode::addr_t __initial_ax; extern "C" Genode::addr_t __initial_bx; /* pointer to stack base */ -extern "C" Genode::addr_t __bootstrap_stack; +extern "C" Genode::addr_t bootstrap_stack; /* number of booted CPUs */ -extern "C" Genode::addr_t __cpus_booted; +extern "C" Genode::addr_t volatile __cpus_booted; /* stack size per CPU */ extern "C" Genode::addr_t const bootstrap_stack_size; @@ -87,6 +89,31 @@ Bootstrap::Platform::Board::Board() size -= get_page_size(); } + /* exclude AP boot code page from normal RAM allocator */ + if (base <= AP_BOOT_CODE_PAGE && AP_BOOT_CODE_PAGE < base + size) { + if (AP_BOOT_CODE_PAGE - base) + early_ram_regions.add(Memory_region { base, + AP_BOOT_CODE_PAGE - base }); + + size -= AP_BOOT_CODE_PAGE - base; + size -= (get_page_size() > size) ? size : get_page_size(); + base = AP_BOOT_CODE_PAGE + get_page_size(); + } + + /* skip partial 4k pages (seen with Qemu with ahci model enabled) */ + if (!aligned(base, 12)) { + auto new_base = align_addr(base, 12); + size -= (new_base - base > size) ? size : new_base - base; + base = new_base; + } + + /* remove partial 4k pages */ + if (!aligned(size, 12)) + size -= size & 0xffful; + + if (!size) + return; + if (base >= initial_map_max) { late_ram_regions.add(Memory_region { base, size }); return; @@ -162,7 +189,8 @@ Bootstrap::Platform::Board::Board() } /* remember max supported CPUs and use ACPI to get the actual number */ - unsigned const max_cpus = cpus; + unsigned const max_cpus = + Hw::Mm::CPU_LOCAL_MEMORY_AREA_SIZE / Hw::Mm::CPU_LOCAL_MEMORY_SLOT_SIZE; cpus = 0; /* scan ACPI tables to find out number of CPUs in this machine */ @@ -170,43 +198,43 @@ Bootstrap::Platform::Board::Board() uint64_t const table_addr = acpi_rsdp.xsdt ? acpi_rsdp.xsdt : acpi_rsdp.rsdt; if (table_addr) { - Hw::Acpi_generic * table = reinterpret_cast(table_addr); + auto rsdt_xsdt_lambda = [&](auto paddr_table) { + addr_t const table_virt_addr = paddr_table; + Hw::Acpi_generic * table = reinterpret_cast(table_virt_addr); + + if (!memcmp(table->signature, "FACP", 4)) { + info.acpi_fadt = addr_t(table); + + Hw::Acpi_fadt fadt(table); + fadt.takeover_acpi(); + + Hw::Acpi_facs facs(fadt.facs()); + facs.wakeup_vector(AP_BOOT_CODE_PAGE); + + auto mem_aligned = paddr_table & _align_mask(12); + auto mem_size = align_addr(paddr_table + table->size, 12) - mem_aligned; + core_mmio.add({ mem_aligned, mem_size }); + } + + if (memcmp(table->signature, "APIC", 4)) + return; + + Hw::for_each_apic_struct(*table,[&](Hw::Apic_madt const *e){ + if (e->type == Hw::Apic_madt::LAPIC) { + Hw::Apic_madt::Lapic lapic(e); + + /* check if APIC is enabled in hardware */ + if (lapic.valid()) + cpus ++; + } + }); + }; + + auto table = reinterpret_cast(table_addr); if (!memcmp(table->signature, "RSDT", 4)) { - Hw::for_each_rsdt_entry(*table, [&](uint32_t paddr_table) { - addr_t const table_virt_addr = paddr_table; - Hw::Acpi_generic * table = reinterpret_cast(table_virt_addr); - - if (memcmp(table->signature, "APIC", 4)) - return; - - Hw::for_each_apic_struct(*table,[&](Hw::Apic_madt const *e){ - if (e->type == Hw::Apic_madt::LAPIC) { - Hw::Apic_madt::Lapic lapic(e); - - /* check if APIC is enabled in hardware */ - if (lapic.valid()) - cpus ++; - } - }); - }); + Hw::for_each_rsdt_entry(*table, rsdt_xsdt_lambda); } else if (!memcmp(table->signature, "XSDT", 4)) { - Hw::for_each_xsdt_entry(*table, [&](uint64_t paddr_table) { - addr_t const table_virt_addr = paddr_table; - Hw::Acpi_generic * table = reinterpret_cast(table_virt_addr); - - if (memcmp(table->signature, "APIC", 4)) - return; - - Hw::for_each_apic_struct(*table,[&](Hw::Apic_madt const *e){ - if (e->type == Hw::Apic_madt::LAPIC) { - Hw::Apic_madt::Lapic lapic(e); - - /* check if APIC is enabled in hardware */ - if (lapic.valid()) - cpus ++; - } - }); - }); + Hw::for_each_xsdt_entry(*table, rsdt_xsdt_lambda); } } } @@ -218,65 +246,34 @@ Bootstrap::Platform::Board::Board() cpus = !cpus ? 1 : max_cpus; } - if (cpus > 1) { - /* copy 16 bit boot code for AP CPUs */ - addr_t ap_code_size = (addr_t)&_start - (addr_t)&_ap; - memcpy((void *)AP_BOOT_CODE_PAGE, &_ap, ap_code_size); - } + /* copy 16 bit boot code for AP CPUs and for ACPI resume */ + addr_t ap_code_size = (addr_t)&_start - (addr_t)&_ap; + memcpy((void *)AP_BOOT_CODE_PAGE, &_ap, ap_code_size); } -struct Lapic : Mmio +static inline +void ipi_to_all(Hw::Local_apic &lapic, unsigned const boot_frame, + Hw::Local_apic::Icr_low::Delivery_mode::Mode const mode) { - struct Svr : Register<0x0f0, 32> - { - struct APIC_enable : Bitfield<8, 1> { }; - }; + using Icr_low = Hw::Local_apic::Icr_low; - struct Icr_low : Register<0x300, 32> - { - struct Vector : Bitfield< 0, 8> { }; - struct Delivery_mode : Bitfield< 8, 3> - { - enum Mode { INIT = 5, SIPI = 6 }; - }; - struct Delivery_status : Bitfield<12, 1> { }; - struct Level_assert : Bitfield<14, 1> { }; - struct Dest_shorthand : Bitfield<18, 2> - { - enum { ALL_OTHERS = 3 }; - }; - }; - - struct Icr_high : Register<0x310, 32> - { - struct Destination : Bitfield<24, 8> { }; - }; - - Lapic(addr_t const addr) : Mmio(addr) { } -}; - - -static inline void ipi_to_all(Lapic &lapic, unsigned const boot_frame, - Lapic::Icr_low::Delivery_mode::Mode const mode) -{ /* wait until ready */ - while (lapic.read()) + while (lapic.read()) asm volatile ("pause":::"memory"); unsigned const apic_cpu_id = 0; /* unused for IPI to all */ - Lapic::Icr_low::access_t icr_low = 0; - - Lapic::Icr_low::Vector::set(icr_low, boot_frame); - Lapic::Icr_low::Delivery_mode::set(icr_low, mode); - Lapic::Icr_low::Level_assert::set(icr_low); - Lapic::Icr_low::Level_assert::set(icr_low); - Lapic::Icr_low::Dest_shorthand::set(icr_low, Lapic::Icr_low::Dest_shorthand::ALL_OTHERS); + Icr_low::access_t icr_low = 0; + Icr_low::Vector::set(icr_low, boot_frame); + Icr_low::Delivery_mode::set(icr_low, mode); + Icr_low::Level_assert::set(icr_low); + Icr_low::Level_assert::set(icr_low); + Icr_low::Dest_shorthand::set(icr_low, Icr_low::Dest_shorthand::ALL_OTHERS); /* program */ - lapic.write(apic_cpu_id); - lapic.write(icr_low); + lapic.write(apic_cpu_id); + lapic.write(icr_low); } @@ -296,24 +293,27 @@ unsigned Bootstrap::Platform::enable_mmu() Cpu::Cr3::write(Cpu::Cr3::Pdb::masked((addr_t)core_pd->table_base)); - addr_t const stack_base = reinterpret_cast(&__bootstrap_stack); - addr_t const this_stack = reinterpret_cast(&stack_base); - addr_t const cpu_id = (this_stack - stack_base) / bootstrap_stack_size; + auto const cpu_id = + Cpu::Cpuid_1_ebx::Apic_id::get(Cpu::Cpuid_1_ebx::read()); /* we like to use local APIC */ Cpu::IA32_apic_base::access_t lapic_msr = Cpu::IA32_apic_base::read(); Cpu::IA32_apic_base::Lapic::set(lapic_msr); Cpu::IA32_apic_base::write(lapic_msr); - /* skip the SMP when ACPI parsing did not reveal the number of CPUs */ - if (board.cpus <= 1) - return (unsigned)cpu_id; - - Lapic lapic(board.core_mmio.virt_addr(Hw::Cpu_memory_map::lapic_phys_base())); + Hw::Local_apic lapic(board.core_mmio.virt_addr(Hw::Cpu_memory_map::lapic_phys_base())); /* enable local APIC if required */ - if (!lapic.read()) - lapic.write(true); + if (!lapic.read()) + lapic.write(true); + + /* reset assembly counter (crt0.s) by last booted CPU, required for resume */ + if (__cpus_booted >= board.cpus) + __cpus_booted = 0; + + /* skip wakeup IPI for non SMP setups */ + if (board.cpus <= 1) + return (unsigned)cpu_id; if (!Cpu::IA32_apic_base::Bsp::get(lapic_msr)) /* AP - done */ @@ -322,12 +322,15 @@ unsigned Bootstrap::Platform::enable_mmu() /* BSP - we're primary CPU - wake now all other CPUs */ /* see Intel Multiprocessor documentation - we need to do INIT-SIPI-SIPI */ - ipi_to_all(lapic, 0 /* unused */, Lapic::Icr_low::Delivery_mode::INIT); + ipi_to_all(lapic, 0 /* unused */, + Hw::Local_apic::Icr_low::Delivery_mode::INIT); /* wait 10 ms - debates ongoing whether this is still required */ - ipi_to_all(lapic, AP_BOOT_CODE_PAGE >> 12, Lapic::Icr_low::Delivery_mode::SIPI); + ipi_to_all(lapic, AP_BOOT_CODE_PAGE >> 12, + Hw::Local_apic::Icr_low::Delivery_mode::SIPI); /* wait 200 us - debates ongoing whether this is still required */ /* debates ongoing whether the second SIPI is still required */ - ipi_to_all(lapic, AP_BOOT_CODE_PAGE >> 12, Lapic::Icr_low::Delivery_mode::SIPI); + ipi_to_all(lapic, AP_BOOT_CODE_PAGE >> 12, + Hw::Local_apic::Icr_low::Delivery_mode::SIPI); return (unsigned)cpu_id; } @@ -340,3 +343,13 @@ Board::Serial::Serial(addr_t, size_t, unsigned baudrate) : X86_uart(Bios_data_area::singleton()->serial_port(), 0, baudrate) { } + + +unsigned Bootstrap::Platform::_prepare_cpu_memory_area() +{ + using namespace Genode; + + for (size_t id = 0; id < board.cpus; id++) + _prepare_cpu_memory_area(id); + return board.cpus; +} diff --git a/repos/base-hw/src/core/board/imx53_qsb/board.h b/repos/base-hw/src/core/board/imx53_qsb/board.h deleted file mode 100644 index 962cc85be4..0000000000 --- a/repos/base-hw/src/core/board/imx53_qsb/board.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * \brief Board driver - * \author Stefan Kalkowski - * \author Martin Stein - * \date 2012-10-24 - */ - -/* - * Copyright (C) 2012-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _CORE__SPEC__IMX53_QSB__BOARD_H_ -#define _CORE__SPEC__IMX53_QSB__BOARD_H_ - -/* base-hw internal includes */ -#include -#include - -/* base-hw Core includes */ -#include -#include -#include - -namespace Board { using namespace Hw::Imx53_qsb_board; } - -#endif /* _CORE__SPEC__IMX53_QSB__BOARD_H_ */ diff --git a/repos/base-hw/src/core/board/imx6q_sabrelite/board.h b/repos/base-hw/src/core/board/imx6q_sabrelite/board.h deleted file mode 100644 index 3e36070a8f..0000000000 --- a/repos/base-hw/src/core/board/imx6q_sabrelite/board.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * \brief Board driver - * \author Stefan Kalkowski - * \date 2019-01-05 - */ - -/* - * Copyright (C) 2019 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _CORE__SPEC__IMX6Q_SABRELITE__BOARD_H_ -#define _CORE__SPEC__IMX6Q_SABRELITE__BOARD_H_ - -/* base-hw internal includes */ -#include -#include - -/* base-hw Core includes */ -#include -#include - -namespace Board { - - using namespace Hw::Imx6q_sabrelite_board; - - class Global_interrupt_controller { }; - class Pic : public Hw::Gicv2 { public: Pic(Global_interrupt_controller &) { } }; - - using L2_cache = Hw::Pl310; - - L2_cache & l2_cache(); - - enum { - CORTEX_A9_PRIVATE_TIMER_CLK = 396000000, /* timer clk runs half the CPU freq */ - CORTEX_A9_PRIVATE_TIMER_DIV = 100, - }; -} - -#endif /* _CORE__SPEC__WAND_QUAD__BOARD_H_ */ diff --git a/repos/base-hw/src/core/board/imx7d_sabre/board.h b/repos/base-hw/src/core/board/imx7d_sabre/board.h deleted file mode 100644 index 06feed0330..0000000000 --- a/repos/base-hw/src/core/board/imx7d_sabre/board.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * \brief Board driver for core - * \author Stefan Kalkowski - * \date 2018-11-07 - */ - -/* - * Copyright (C) 2018 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _CORE__SPEC__IMX7D_SABRE__BOARD_H_ -#define _CORE__SPEC__IMX7D_SABRE__BOARD_H_ - -/* base-hw internal includes */ -#include - -/* base-hw Core includes */ -#include -#include -#include -#include -#include - -namespace Board { - - using namespace Hw::Imx7d_sabre_board; - - struct Virtual_local_pic {}; - - enum { TIMER_IRQ = 30, VCPU_MAX = 16 }; -} - -#endif /* _CORE__SPEC__IMX7_SABRELITE__BOARD_H_ */ diff --git a/repos/base-hw/src/core/board/nit6_solox/board.h b/repos/base-hw/src/core/board/nit6_solox/board.h deleted file mode 100644 index f2cff365e8..0000000000 --- a/repos/base-hw/src/core/board/nit6_solox/board.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * \brief Board driver - * \author Stefan Kalkowski - * \date 2017-10-18 - */ - -/* - * Copyright (C) 2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _CORE__SPEC__NIT6_SOLOX__BOARD_H_ -#define _CORE__SPEC__NIT6_SOLOX__BOARD_H_ - -/* base-hw internal includes */ -#include -#include - -/* base-hw Core includes */ -#include -#include - -namespace Board { - - using namespace Hw::Nit6_solox_board; - - class Global_interrupt_controller { }; - class Pic : public Hw::Gicv2 { public: Pic(Global_interrupt_controller &) { } }; - - using L2_cache = Hw::Pl310; - - L2_cache & l2_cache(); - - enum { - CORTEX_A9_PRIVATE_TIMER_CLK = 500000000, /* timer clk runs half the CPU freq */ - CORTEX_A9_PRIVATE_TIMER_DIV = 100, - }; -} - -#endif /* _CORE__SPEC__NIT6_SOLOX__BOARD_H_ */ diff --git a/repos/base-hw/src/core/board/pbxa9/board.h b/repos/base-hw/src/core/board/pbxa9/board.h index c49d19725e..af1eddb5f8 100644 --- a/repos/base-hw/src/core/board/pbxa9/board.h +++ b/repos/base-hw/src/core/board/pbxa9/board.h @@ -18,15 +18,15 @@ #include #include -/* base-hw Core includes */ -#include -#include +/* base-hw core includes */ +#include +#include namespace Board { using namespace Hw::Pbxa9_board; - class Global_interrupt_controller { }; + class Global_interrupt_controller { public: void init() {} }; class Pic : public Hw::Gicv2 { public: Pic(Global_interrupt_controller &) { } }; L2_cache & l2_cache(); diff --git a/repos/base-hw/src/core/board/pc/board.h b/repos/base-hw/src/core/board/pc/board.h index 27ef96c304..f07a971d08 100644 --- a/repos/base-hw/src/core/board/pc/board.h +++ b/repos/base-hw/src/core/board/pc/board.h @@ -16,8 +16,10 @@ /* base-hw internal includes */ #include +/* PC virtualization */ +#include -/* base-hw Core includes */ +/* base-hw core includes */ #include #include #include @@ -26,7 +28,8 @@ namespace Board { using namespace Hw::Pc_board; - class Pic : public Local_interrupt_controller { }; + class Pic : public Local_interrupt_controller + { using Local_interrupt_controller::Local_interrupt_controller; }; enum { VECTOR_REMAP_BASE = 48, diff --git a/repos/base-hw/src/core/board/usb_armory/board.h b/repos/base-hw/src/core/board/usb_armory/board.h deleted file mode 100644 index d0f5d14745..0000000000 --- a/repos/base-hw/src/core/board/usb_armory/board.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * \brief Board driver - * \author Stefan Kalkowski - * \author Martin Stein - * \date 2012-10-24 - */ - -/* - * Copyright (C) 2012-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _CORE__SPEC__USB_ARMORY__BOARD_H_ -#define _CORE__SPEC__USB_ARMORY__BOARD_H_ - -/* base-hw internal includes */ -#include -#include - -/* base-hw Core includes */ -#include -#include -#include - -namespace Board { using namespace Hw::Usb_armory_board; } - -#endif /* _CORE__SPEC__USB_ARMORY__BOARD_H_ */ diff --git a/repos/base-hw/src/core/board/virt_qemu_arm_v7a/board.h b/repos/base-hw/src/core/board/virt_qemu_arm_v7a/board.h index c12a54cc67..98c052953e 100644 --- a/repos/base-hw/src/core/board/virt_qemu_arm_v7a/board.h +++ b/repos/base-hw/src/core/board/virt_qemu_arm_v7a/board.h @@ -14,19 +14,13 @@ #ifndef _SRC__CORE__SPEC__VIRT__QEMU_H_ #define _SRC__CORE__SPEC__VIRT__QEMU_H_ -/* base-hw internal includes */ +/* base-hw core includes */ #include - -/* base-hw Core includes */ #include #include - -/* base-hw includes */ -#include - -/* base-hw Core includes */ #include -#include +#include +#include namespace Kernel { class Cpu; } @@ -40,8 +34,10 @@ namespace Board { TIMER_IRQ = 30 /* PPI IRQ 14 */, VT_TIMER_IRQ = 27, VT_MAINTAINANCE_IRQ = 25, - VCPU_MAX = 16 + VCPU_MAX = 16, }; + + static constexpr Genode::size_t NR_OF_CPUS = 2; }; #endif /* _SRC__CORE__SPEC__VIRT__QEMU_H_ */ diff --git a/repos/base-hw/src/core/board/virt_qemu_arm_v8a/board.h b/repos/base-hw/src/core/board/virt_qemu_arm_v8a/board.h index 0e72f97486..8783090205 100644 --- a/repos/base-hw/src/core/board/virt_qemu_arm_v8a/board.h +++ b/repos/base-hw/src/core/board/virt_qemu_arm_v8a/board.h @@ -16,15 +16,9 @@ /* base-hw internal includes */ #include - -/* base-hw Core includes */ #include #include - -/* base-hw includes */ -#include - -/* base-hw Core includes */ +#include #include #include #include @@ -33,6 +27,8 @@ namespace Board { using namespace Hw::Virt_qemu_board; + static constexpr Genode::size_t NR_OF_CPUS = 4; + enum { TIMER_IRQ = 30, /* PPI IRQ 14 */ VT_TIMER_IRQ = 11 + 16, @@ -46,7 +42,8 @@ namespace Board { struct Vcpu_context; - using Vm_state = Genode::Vm_state; + using Vcpu_state = Genode::Vcpu_state; + using Vcpu_data = Vcpu_state; }; diff --git a/repos/base-hw/src/core/board/wand_quad/board.h b/repos/base-hw/src/core/board/wand_quad/board.h deleted file mode 100644 index 8802e63e08..0000000000 --- a/repos/base-hw/src/core/board/wand_quad/board.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * \brief Board driver - * \author Stefan Kalkowski - * \author Martin Stein - * \date 2014-02-25 - */ - -/* - * Copyright (C) 2014-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _CORE__SPEC__WAND_QUAD__BOARD_H_ -#define _CORE__SPEC__WAND_QUAD__BOARD_H_ - -/* base-hw internal includes */ -#include -#include - -/* base-hw Core includes */ -#include -#include - -namespace Board { - - using namespace Hw::Wand_quad_board; - - using L2_cache = Hw::Pl310; - - class Global_interrupt_controller { }; - class Pic : public Hw::Gicv2 { public: Pic(Global_interrupt_controller &) { } }; - - L2_cache & l2_cache(); - - enum { - CORTEX_A9_PRIVATE_TIMER_CLK = 500000000, /* timer clk runs half the CPU freq */ - CORTEX_A9_PRIVATE_TIMER_DIV = 100, - }; -} - -#endif /* _CORE__SPEC__WAND_QUAD__BOARD_H_ */ diff --git a/repos/base-hw/src/core/core_log_out.cc b/repos/base-hw/src/core/core_log_out.cc index 2d555f12c1..4c80198c2e 100644 --- a/repos/base-hw/src/core/core_log_out.cc +++ b/repos/base-hw/src/core/core_log_out.cc @@ -12,15 +12,22 @@ * under the terms of the GNU Affero General Public License version 3. */ +/* Genode includes */ +#include + /* base-internal includes */ #include #include +/* core includes */ #include +#include #include +using namespace Core; -void Genode::Core_log::out(char const c) { Kernel::log(c); } + +void Core_log::out(char const c) { Kernel::log(c); } void Genode::raw_write_string(char const *str) @@ -28,3 +35,71 @@ void Genode::raw_write_string(char const *str) while (char c = *str++) Kernel::log(c); } + + +/************************************************************ + ** Utility to check whether kernel or core code is active ** + ************************************************************/ + +static inline bool running_in_kernel() +{ + Hw::Memory_region const cpu_region = Hw::Mm::cpu_local_memory(); + + /* check stack variable against kernel's cpu local memory area */ + return ((addr_t)&cpu_region) >= cpu_region.base && + ((addr_t)&cpu_region) < cpu_region.end(); +} + + +/******************************************* + ** Implementation of src/lib/base/log.cc ** + *******************************************/ + +void Log::_acquire(Type type) +{ + if (!running_in_kernel()) _mutex.acquire(); + + /* + * Mark warnings and errors via distinct colors. + */ + switch (type) { + case LOG: break; + case WARNING: _output.out_string("\033[34mWarning: "); break; + case ERROR: _output.out_string("\033[31mError: "); break; + }; +} + + +void Log::_release() +{ + /* + * Reset color and add newline + */ + _output.out_string("\033[0m\n"); + + if (!running_in_kernel()) _mutex.release(); +} + + +void Raw::_acquire() +{ + /* + * Mark raw output with distinct color + */ + _output().out_string("\033[32mKernel: "); +} + + +void Raw::_release() +{ + /* + * Reset color and add newline + */ + _output().out_string("\033[0m\n"); +} + + +void Trace_output::Write_trace_fn::operator () (char const *s) +{ + Thread::trace(s); +} diff --git a/repos/base-hw/src/core/core_region_map.cc b/repos/base-hw/src/core/core_region_map.cc index 0ceb40217e..8965688c8a 100644 --- a/repos/base-hw/src/core/core_region_map.cc +++ b/repos/base-hw/src/core/core_region_map.cc @@ -19,72 +19,67 @@ #include #include #include -#include -using namespace Genode; +using namespace Core; -Region_map::Local_addr -Core_region_map::attach(Dataspace_capability ds_cap, size_t size, - off_t offset, bool use_local_addr, - Region_map::Local_addr, bool, bool writeable) +Region_map::Attach_result +Core_region_map::attach(Dataspace_capability ds_cap, Attr const &attr) { - return _ep.apply(ds_cap, [&] (Dataspace_component *ds_ptr) -> Local_addr { + return _ep.apply(ds_cap, [&] (Dataspace_component *ds_ptr) -> Attach_result { if (!ds_ptr) - throw Invalid_dataspace(); + return Attach_error::INVALID_DATASPACE; Dataspace_component &ds = *ds_ptr; - if (size == 0) - size = ds.size(); + size_t const size = (attr.size == 0) ? ds.size() : attr.size; + size_t const page_rounded_size = (size + get_page_size() - 1) & get_page_mask(); - size_t page_rounded_size = (size + get_page_size() - 1) & get_page_mask(); - - if (use_local_addr) { - error("Parameter 'use_local_addr' not supported within core"); - return nullptr; - } - - if (offset) { - error("Parameter 'offset' not supported within core"); - return nullptr; - } + /* attach attributes 'use_at' and 'offset' not supported within core */ + if (attr.use_at || attr.offset) + return Attach_error::REGION_CONFLICT; unsigned const align = get_page_size_log2(); /* allocate range in core's virtual address space */ - Allocator::Alloc_result virt = + Allocator::Alloc_result const virt = platform().region_alloc().alloc_aligned(page_rounded_size, align); if (virt.failed()) { error("could not allocate virtual address range in core of size ", page_rounded_size); - return nullptr; + return Attach_error::REGION_CONFLICT; } using namespace Hw; /* map the dataspace's physical pages to corresponding virtual addresses */ - unsigned num_pages = (unsigned)(page_rounded_size >> get_page_size_log2()); - Page_flags const flags { (writeable && ds.writeable()) ? RW : RO, - NO_EXEC, KERN, GLOBAL, - ds.io_mem() ? DEVICE : RAM, - ds.cacheability() }; + unsigned const num_pages = unsigned(page_rounded_size >> get_page_size_log2()); - return virt.convert( + Page_flags const flags { + .writeable = (attr.writeable && ds.writeable()) ? RW : RO, + .executable = NO_EXEC, + .privileged = KERN, + .global = GLOBAL, + .type = ds.io_mem() ? DEVICE : RAM, + .cacheable = ds.cacheability() + }; - [&] (void *virt_addr) -> void * { + return virt.convert( + + [&] (void *virt_addr) -> Attach_result { if (map_local(ds.phys_addr(), (addr_t)virt_addr, num_pages, flags)) - return virt_addr; + return Range { .start = addr_t(virt_addr), + .num_bytes = page_rounded_size }; platform().region_alloc().free(virt_addr, page_rounded_size); - return nullptr; }, + return Attach_error::REGION_CONFLICT; }, [&] (Allocator::Alloc_error) { - return nullptr; }); + return Attach_error::REGION_CONFLICT; }); }); } -void Core_region_map::detach(Local_addr) { } +void Core_region_map::detach(addr_t) { } diff --git a/repos/base-hw/src/core/cpu_session_support.cc b/repos/base-hw/src/core/cpu_session_support.cc index caf2257c53..fbee7b6882 100644 --- a/repos/base-hw/src/core/cpu_session_support.cc +++ b/repos/base-hw/src/core/cpu_session_support.cc @@ -21,7 +21,7 @@ /* base-internal includes */ #include -using namespace Genode; +using namespace Core; Dataspace_capability Cpu_thread_component::utcb() @@ -33,7 +33,7 @@ Dataspace_capability Cpu_thread_component::utcb() Cpu_session::Quota Cpu_session_component::quota() { size_t const spu = Kernel::cpu_quota_us; - size_t const u = quota_lim_downscale(_quota, spu); + size_t const u = quota_lim_downscale(_quota, spu); return { spu, u }; } diff --git a/repos/base-hw/src/core/cpu_thread_allocator.h b/repos/base-hw/src/core/cpu_thread_allocator.h index c0e4038836..885ef1b62d 100644 --- a/repos/base-hw/src/core/cpu_thread_allocator.h +++ b/repos/base-hw/src/core/cpu_thread_allocator.h @@ -15,13 +15,12 @@ #define _CORE__CPU_THREAD_ALLOCATOR_H_ /* Genode includes */ -#include #include /* core includes */ #include -namespace Genode { class Cpu_thread_allocator; } +namespace Core { class Cpu_thread_allocator; } /** @@ -31,7 +30,7 @@ namespace Genode { class Cpu_thread_allocator; } * are tiny objects, but in 'base-hw' they contain the whole kernel * object in addition. Thus we use the given allocator directly. */ -class Genode::Cpu_thread_allocator : public Allocator +class Core::Cpu_thread_allocator : public Allocator { private: diff --git a/repos/base-hw/src/core/io_mem_session_support.cc b/repos/base-hw/src/core/io_mem_session_support.cc index 90dde90a64..a25f199fd8 100644 --- a/repos/base-hw/src/core/io_mem_session_support.cc +++ b/repos/base-hw/src/core/io_mem_session_support.cc @@ -15,10 +15,10 @@ /* core includes */ #include -using namespace Genode; +using namespace Core; -void Io_mem_session_component::_unmap_local(addr_t, size_t) { } +void Io_mem_session_component::_unmap_local(addr_t, size_t, addr_t) { } addr_t Io_mem_session_component::_map_local(addr_t base, size_t) { return base; } diff --git a/repos/base-hw/src/core/irq_session_component.cc b/repos/base-hw/src/core/irq_session_component.cc index 33d54b2f59..6c33684f91 100644 --- a/repos/base-hw/src/core/irq_session_component.cc +++ b/repos/base-hw/src/core/irq_session_component.cc @@ -23,7 +23,7 @@ /* base-internal includes */ #include -using namespace Genode; +using namespace Core; unsigned Irq_session_component::_find_irq_number(const char * const args) @@ -58,6 +58,7 @@ Irq_session_component::~Irq_session_component() using namespace Kernel; _irq_alloc.free((void *)(addr_t)_irq_number); + if (_is_msi) Platform::free_msi_vector(_address, _value); } @@ -68,14 +69,11 @@ Irq_session_component::Irq_session_component(Range_allocator &irq_alloc, _irq_number((unsigned)Platform::irq(_irq_args.irq_number())), _irq_alloc(irq_alloc), _kobj(), _is_msi(false), _address(0), _value(0) { - long const mmconf = - Arg_string::find_arg(args, "device_config_phys").long_value(0); - - if (mmconf) { - _is_msi = - Platform::get_msi_params(mmconf, _address, _value, _irq_number); + if (_irq_args.type() != Irq_session::TYPE_LEGACY) { + _is_msi = Platform::alloc_msi_vector(_address, _value); if (!_is_msi) throw Service_denied(); + _irq_number = (unsigned) _value; } /* allocate interrupt */ diff --git a/repos/base-hw/src/core/irq_session_component.h b/repos/base-hw/src/core/irq_session_component.h index 74ca09fa84..58cd896733 100644 --- a/repos/base-hw/src/core/irq_session_component.h +++ b/repos/base-hw/src/core/irq_session_component.h @@ -19,15 +19,16 @@ #include #include +/* core includes */ #include #include #include -namespace Genode { class Irq_session_component; } +namespace Core { class Irq_session_component; } -class Genode::Irq_session_component : public Rpc_object, - private List::Element +class Core::Irq_session_component : public Rpc_object, + private List::Element { private: diff --git a/repos/base-hw/src/core/kernel/configuration.h b/repos/base-hw/src/core/kernel/configuration.h index b62aaf72d9..c5ea31f871 100644 --- a/repos/base-hw/src/core/kernel/configuration.h +++ b/repos/base-hw/src/core/kernel/configuration.h @@ -20,7 +20,7 @@ namespace Kernel { enum { DEFAULT_STACK_SIZE = 16 * 1024, - DEFAULT_TRANSLATION_TABLE_MAX = 128, + DEFAULT_TRANSLATION_TABLE_MAX = 1024, }; /* amount of priority bands amongst quota owners in CPU scheduling */ diff --git a/repos/base-hw/src/core/kernel/core_interface.h b/repos/base-hw/src/core/kernel/core_interface.h index 3f59178871..4e606ee1be 100644 --- a/repos/base-hw/src/core/kernel/core_interface.h +++ b/repos/base-hw/src/core/kernel/core_interface.h @@ -14,6 +14,9 @@ #ifndef _CORE__KERNEL__CORE_INTERFACE_H_ #define _CORE__KERNEL__CORE_INTERFACE_H_ +/* base includes */ +#include + /* base-internal includes */ #include @@ -31,6 +34,7 @@ namespace Kernel { class Vm; class User_irq; using Native_utcb = Genode::Native_utcb; + using Cpu_state = Genode::Cpu_state; template class Core_object_identity; /** @@ -58,6 +62,10 @@ namespace Kernel { constexpr Call_arg call_id_new_obj() { return 121; } constexpr Call_arg call_id_delete_obj() { return 122; } constexpr Call_arg call_id_new_core_thread() { return 123; } + constexpr Call_arg call_id_get_cpu_state() { return 124; } + constexpr Call_arg call_id_set_cpu_state() { return 125; } + constexpr Call_arg call_id_exception_state() { return 126; } + constexpr Call_arg call_id_single_step() { return 127; } /** * Invalidate TLB entries for the `pd` in region `addr`, `sz` @@ -159,6 +167,42 @@ namespace Kernel { { call(call_id_ack_irq(), (Call_arg) &irq); } + + + /** + * Get CPU state + * + * \param thread pointer to thread kernel object + * \param thread_state pointer to result CPU state object + */ + inline void get_cpu_state(Thread & thread, Cpu_state & cpu_state) + { + call(call_id_get_cpu_state(), (Call_arg)&thread, (Call_arg)&cpu_state); + } + + + /** + * Set CPU state + * + * \param thread pointer to thread kernel object + * \param thread_state pointer to CPU state object + */ + inline void set_cpu_state(Thread & thread, Cpu_state & cpu_state) + { + call(call_id_set_cpu_state(), (Call_arg)&thread, (Call_arg)&cpu_state); + } + + + /** + * Enable/disable single-stepping + * + * \param thread pointer to thread kernel object + * \param on enable or disable + */ + inline void single_step(Thread & thread, bool & on) + { + call(call_id_single_step(), (Call_arg)&thread, (Call_arg)&on); + } } #endif /* _CORE__KERNEL__CORE_INTERFACE_H_ */ diff --git a/repos/base-hw/src/core/kernel/cpu.cc b/repos/base-hw/src/core/kernel/cpu.cc index cd7e57b5b9..0e0c686984 100644 --- a/repos/base-hw/src/core/kernel/cpu.cc +++ b/repos/base-hw/src/core/kernel/cpu.cc @@ -12,6 +12,8 @@ * under the terms of the GNU Affero General Public License version 3. */ +#include + /* core includes */ #include #include @@ -20,6 +22,7 @@ #include #include #include +#include using namespace Kernel; @@ -77,13 +80,13 @@ void Cpu_job::quota(unsigned const q) if (_cpu) _cpu->scheduler().quota(*this, q); else - Cpu_share::quota(q); + Context::quota(q); } -Cpu_job::Cpu_job(Cpu_priority const p, unsigned const q) +Cpu_job::Cpu_job(Priority const p, unsigned const q) : - Cpu_share(p, q), _cpu(0) + Context(p, q), _cpu(0) { } @@ -110,7 +113,7 @@ Cpu::Idle_thread::Idle_thread(Board::Address_space_id_allocator &addr_space_id_a Pd &core_pd) : Thread { addr_space_id_alloc, user_irq_pool, cpu_pool, core_pd, - Cpu_priority::min(), 0, "idle", Thread::IDLE } + Priority::min(), 0, "idle", Thread::IDLE } { regs->ip = (addr_t)&idle_thread_main; @@ -121,7 +124,7 @@ Cpu::Idle_thread::Idle_thread(Board::Address_space_id_allocator &addr_space_id_a void Cpu::schedule(Job * const job) { - _scheduler.ready(job->share()); + _scheduler.ready(job->context()); if (_id != executing_id() && _scheduler.need_to_schedule()) trigger_ip_interrupt(); } @@ -145,11 +148,14 @@ Cpu_job & Cpu::schedule() Job & old_job = scheduled_job(); old_job.exception(*this); + if (_state == SUSPEND || _state == HALT) + return _halt_job; + if (_scheduler.need_to_schedule()) { _timer.process_timeouts(); _scheduler.update(_timer.time()); - time_t t = _scheduler.head_quota(); - _timer.set_timeout(this, t); + time_t t = _scheduler.current_time_left(); + _timer.set_timeout(&_timeout, t); time_t duration = _timer.schedule_timeout(); old_job.update_execution_time(duration); } @@ -159,14 +165,10 @@ Cpu_job & Cpu::schedule() } -Genode::size_t kernel_stack_size = Cpu::KERNEL_STACK_SIZE; -Genode::uint8_t kernel_stack[NR_OF_CPUS][Cpu::KERNEL_STACK_SIZE] -__attribute__((aligned(Genode::get_page_size()))); - - addr_t Cpu::stack_start() { - return (addr_t)&kernel_stack + KERNEL_STACK_SIZE * (_id + 1); + return Abi::stack_align(Hw::Mm::cpu_local_memory().base + + (1024*1024*_id) + (64*1024)); } @@ -187,6 +189,17 @@ Cpu::Cpu(unsigned const id, _global_work_list { cpu_pool.work_list() } { _arch_init(); + + /* + * We insert the cpu objects in order into the cpu_pool's list + * to ensure that the cpu with the lowest given id is the first + * one. + */ + Cpu * cpu = cpu_pool._cpus.first(); + while (cpu && cpu->next() && (cpu->next()->id() < _id)) + cpu = cpu->next(); + cpu = (cpu && cpu->id() < _id) ? cpu : nullptr; + cpu_pool._cpus.insert(this, cpu); } @@ -194,6 +207,15 @@ Cpu::Cpu(unsigned const id, ** Cpu_pool ** **************/ +template +static inline T* cpu_object_by_id(unsigned const id) +{ + using namespace Hw::Mm; + addr_t base = CPU_LOCAL_MEMORY_AREA_START + id*CPU_LOCAL_MEMORY_SLOT_SIZE; + return (T*)(base + CPU_LOCAL_MEMORY_SLOT_OBJECT_OFFSET); +} + + void Cpu_pool:: initialize_executing_cpu(Board::Address_space_id_allocator &addr_space_id_alloc, @@ -202,22 +224,13 @@ initialize_executing_cpu(Board::Address_space_id_allocator &addr_space_id_alloc Board::Global_interrupt_controller &global_irq_ctrl) { unsigned id = Cpu::executing_id(); - _cpus[id].construct( - id, addr_space_id_alloc, user_irq_pool, *this, core_pd, global_irq_ctrl); + Genode::construct_at(cpu_object_by_id(id), id, + addr_space_id_alloc, user_irq_pool, + *this, core_pd, global_irq_ctrl); } Cpu & Cpu_pool::cpu(unsigned const id) { - assert(id < _nr_of_cpus && _cpus[id].constructed()); - return *_cpus[id]; + return *cpu_object_by_id(id); } - - -using Boot_info = Hw::Boot_info; - - -Cpu_pool::Cpu_pool(unsigned nr_of_cpus) -: - _nr_of_cpus(nr_of_cpus) -{ } diff --git a/repos/base-hw/src/core/kernel/cpu.h b/repos/base-hw/src/core/kernel/cpu.h index 30c2c1635e..83f2d5b7cc 100644 --- a/repos/base-hw/src/core/kernel/cpu.h +++ b/repos/base-hw/src/core/kernel/cpu.h @@ -15,8 +15,6 @@ #ifndef _CORE__KERNEL__CPU_H_ #define _CORE__KERNEL__CPU_H_ -#include - /* core includes */ #include #include @@ -38,39 +36,12 @@ namespace Kernel { } -/* - * The 'Cpu' class violates the "Effective C++" practices because it publicly - * inherits the 'Genode::Cpu' base class, which does not have a virtual - * destructor. Since 'Cpu' implements the 'Timeout' interface, however, it has - * a vtable. - * - * Adding a virtual destructor in the base class would be unnatural as the base - * class hierarchy does not represent an abstract interface. - * - * Inheriting the 'Genode::Cpu' class privately is not an option because the - * user of 'Cpu' class expects architecture-specific register definitions to be - * provided by 'Cpu'. Hence, all those architecture- specific definitions would - * end up as 'using' clauses in the generic class. - * - * XXX Remove the disabled warning, e.g., by one of the following approaches: - * - * * Prevent 'Cpu' to have virtual methods by making 'Timeout' a member instead - * of a base class. - * - * * Change the class hierarchy behind 'Genode::Cpu' such that - * architecture-specific bits do no longer need to implicitly become part - * of the public interface of 'Cpu'. For example, register-definition types - * could all be embedded in an 'Arch_regs' type, which the 'Cpu' class could - * publicly provide via a 'typedef Genode::Cpu::Arch_regs Arch_regs'. - * Then, the 'Genode::Cpu' could be inherited privately. - */ -#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" - -class Kernel::Cpu : public Genode::Cpu, private Irq::Pool, private Timeout +class Kernel::Cpu : public Core::Cpu, private Irq::Pool, + public Genode::List::Element { private: - typedef Cpu_job Job; + using Job = Cpu_job; /** * Inter-processor-interrupt object of the cpu @@ -88,6 +59,9 @@ class Kernel::Cpu : public Genode::Cpu, private Irq::Pool, private Timeout Ipi(Cpu & cpu); + void init(); + + /********************* ** Irq interface ** *********************/ @@ -109,11 +83,25 @@ class Kernel::Cpu : public Genode::Cpu, private Irq::Pool, private Timeout Pd &core_pd); }; + struct Halt_job : Job + { + Halt_job() : Job (0, 0) { } + void exception(Kernel::Cpu &) override { } + + void proceed(Kernel::Cpu &) override; + + Kernel::Cpu_job* helping_destination() override { return this; } + } _halt_job { }; + + enum State { RUN, HALT, SUSPEND }; + + State _state { RUN }; unsigned const _id; Board::Pic _pic; + Timeout _timeout {}; Timer _timer; - Cpu_scheduler _scheduler; + Scheduler _scheduler; Idle_thread _idle; Ipi _ipi_irq; @@ -126,7 +114,10 @@ class Kernel::Cpu : public Genode::Cpu, private Irq::Pool, private Timeout public: - enum { KERNEL_STACK_SIZE = 16 * 1024 * sizeof(Genode::addr_t) }; + void next_state_halt() { _state = HALT; }; + void next_state_suspend() { _state = SUSPEND; }; + + State state() { return _state; } /** * Construct object for CPU 'id' @@ -138,8 +129,6 @@ class Kernel::Cpu : public Genode::Cpu, private Irq::Pool, private Timeout Pd &core_pd, Board::Global_interrupt_controller &global_irq_ctrl); - static inline unsigned primary_id() { return 0; } - /** * Raise the IPI of the CPU */ @@ -171,11 +160,11 @@ class Kernel::Cpu : public Genode::Cpu, private Irq::Pool, private Timeout /** * Returns the currently active job */ - Job & scheduled_job() const { - return *static_cast(&_scheduler.head())->helping_sink(); } + Job & scheduled_job() { + return *static_cast(&_scheduler.current())->helping_destination(); } unsigned id() const { return _id; } - Cpu_scheduler &scheduler() { return _scheduler; } + Scheduler &scheduler() { return _scheduler; } Irq::Pool &irq_pool() { return *this; } @@ -186,58 +175,50 @@ class Kernel::Cpu : public Genode::Cpu, private Irq::Pool, private Timeout * Return CPU's idle thread object */ Kernel::Thread &idle_thread() { return _idle; } + + void reinit_cpu() + { + _arch_init(); + _state = RUN; + } }; -/* - * See the comment above the 'Cpu' class definition. - */ -#pragma GCC diagnostic pop - - class Kernel::Cpu_pool { private: Inter_processor_work_list _global_work_list {}; - unsigned _nr_of_cpus; - Genode::Constructible _cpus[NR_OF_CPUS]; + Genode::List _cpus {}; + + friend class Cpu; public: - Cpu_pool(unsigned nr_of_cpus); - void initialize_executing_cpu(Board::Address_space_id_allocator &addr_space_id_alloc, Irq::Pool &user_irq_pool, Pd &core_pd, Board::Global_interrupt_controller &global_irq_ctrl); - /** - * Return object of CPU 'id' - */ Cpu & cpu(unsigned const id); /** * Return object of primary CPU */ - Cpu & primary_cpu() { return cpu(Cpu::primary_id()); } + Cpu & primary_cpu() { return *_cpus.first(); } - /** - * Return object of current CPU - */ - Cpu & executing_cpu() { return cpu(Cpu::executing_id()); } - - template - void for_each_cpu(FUNC const &func) + void for_each_cpu(auto const &fn) { - for (unsigned i = 0; i < _nr_of_cpus; i++) func(cpu(i)); + Cpu * c = _cpus.first(); + while (c) { + fn(*c); + c = c->next(); + } } Inter_processor_work_list & work_list() { return _global_work_list; } - - unsigned nr_of_cpus() { return _nr_of_cpus; } }; #endif /* _CORE__KERNEL__CPU_H_ */ diff --git a/repos/base-hw/src/core/kernel/cpu_context.h b/repos/base-hw/src/core/kernel/cpu_context.h index 472dc12900..8c7444ac3d 100644 --- a/repos/base-hw/src/core/kernel/cpu_context.h +++ b/repos/base-hw/src/core/kernel/cpu_context.h @@ -16,7 +16,7 @@ #define _CORE__KERNEL__CPU_CONTEXT_H_ /* core includes */ -#include +#include #include namespace Kernel { @@ -30,11 +30,11 @@ namespace Kernel { } -class Kernel::Cpu_job : private Cpu_share +class Kernel::Cpu_job : private Scheduler::Context { private: - friend class Cpu; /* static_cast from 'Cpu_share' to 'Cpu_job' */ + friend class Cpu; /* static_cast from 'Scheduler::Context' to 'Cpu_job' */ time_t _execution_time { 0 }; @@ -75,6 +75,9 @@ class Kernel::Cpu_job : private Cpu_share public: + using Context = Scheduler::Context; + using Priority = Scheduler::Priority; + /** * Handle exception that occured during execution on CPU 'id' */ @@ -88,12 +91,12 @@ class Kernel::Cpu_job : private Cpu_share /** * Return which job currently uses our CPU-share */ - virtual Cpu_job * helping_sink() = 0; + virtual Cpu_job * helping_destination() = 0; /** * Construct a job with scheduling priority 'p' and time quota 'q' */ - Cpu_job(Cpu_priority const p, unsigned const q); + Cpu_job(Priority const p, unsigned const q); /** * Destructor @@ -113,7 +116,7 @@ class Kernel::Cpu_job : private Cpu_share /** * Return wether our CPU-share is currently active */ - bool own_share_active() { return Cpu_share::ready(); } + bool own_share_active() { return Context::ready(); } /** * Update total execution time @@ -132,7 +135,7 @@ class Kernel::Cpu_job : private Cpu_share void cpu(Cpu &cpu) { _cpu = &cpu; } - Cpu_share &share() { return *this; } + Context &context() { return *this; } }; #endif /* _CORE__KERNEL__CPU_CONTEXT_H_ */ diff --git a/repos/base-hw/src/core/kernel/cpu_mp.cc b/repos/base-hw/src/core/kernel/cpu_mp.cc index 514a2a05c0..8b2eca8fef 100644 --- a/repos/base-hw/src/core/kernel/cpu_mp.cc +++ b/repos/base-hw/src/core/kernel/cpu_mp.cc @@ -19,12 +19,12 @@ using namespace Kernel; void Cpu::Ipi::occurred() { /* lambda to iterate over a work-list and execute all work items */ - auto iterate = [] (Genode::List> & li) { + auto iterate = [&] (Genode::List> & li) { Genode::List_element const *e = li.first(); Genode::List_element const *next = nullptr; for ( ; e; e = next) { next = e->next(); - e->object()->execute(); + e->object()->execute(cpu); } }; @@ -52,5 +52,12 @@ Cpu::Ipi::Ipi(Cpu & cpu) : Irq(Board::Pic::IPI, cpu, cpu.pic()), cpu(cpu) { + init(); +} + + +void Cpu::Ipi::init() +{ + pending = false; cpu.pic().unmask(Board::Pic::IPI, cpu.id()); } diff --git a/repos/base-hw/src/core/kernel/cpu_scheduler.cc b/repos/base-hw/src/core/kernel/cpu_scheduler.cc deleted file mode 100644 index b56d771656..0000000000 --- a/repos/base-hw/src/core/kernel/cpu_scheduler.cc +++ /dev/null @@ -1,317 +0,0 @@ -/* - * \brief Schedules CPU shares for the execution time of a CPU - * \author Martin Stein - * \date 2014-10-09 - */ - -/* - * Copyright (C) 2014-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#include -#include -#include - -using namespace Kernel; - - -void Cpu_scheduler::_reset(Cpu_share &share) -{ - share._claim = share._quota; -} - - -void Cpu_scheduler::_reset_claims(unsigned const p) -{ - _rcl[p].for_each([&] (Cpu_share &share) { _reset(share); }); - _ucl[p].for_each([&] (Cpu_share &share) { _reset(share); }); -} - - -void Cpu_scheduler::_next_round() -{ - _residual = _quota; - _for_each_prio([&] (Cpu_priority const p, bool &) { _reset_claims(p); }); -} - - -void Cpu_scheduler::_consumed(unsigned const q) -{ - if (_residual > q) - _residual -= q; - else - _next_round(); -} - - -void Cpu_scheduler::_set_head(Share &s, unsigned const q, bool const c) -{ - _head_quota = q; - _head_claims = c; - _head = &s; -} - - -void Cpu_scheduler::_next_fill() -{ - _head->_fill = _fill; - _fills.head_to_tail(); -} - - -void Cpu_scheduler::_head_claimed(unsigned const r) -{ - if (!_head->_quota) - return; - - _head->_claim = r > _head->_quota ? _head->_quota : r; - - if (_head->_claim || !_head->_ready) - return; - - _rcl[_head->_prio].to_tail(&_head->_claim_item); -} - - -void Cpu_scheduler::_head_filled(unsigned const r) -{ - if (_fills.head() != &_head->_fill_item) - return; - - if (r) - _head->_fill = r; - else - _next_fill(); -} - - -bool Cpu_scheduler::_claim_for_head() -{ - bool result { false }; - _for_each_prio([&] (Cpu_priority const p, bool &cancel_for_each_prio) { - Double_list_item *const item { _rcl[p].head() }; - - if (!item) - return; - - Cpu_share &share { item->payload() }; - - if (!share._claim) - return; - - _set_head(share, share._claim, 1); - result = true; - cancel_for_each_prio = true; - }); - return result; -} - - -bool Cpu_scheduler::_fill_for_head() -{ - Double_list_item *const item { _fills.head() }; - if (!item) - return 0; - - Share &share = item->payload(); - _set_head(share, share._fill, 0); - return 1; -} - - -unsigned Cpu_scheduler::_trim_consumption(unsigned &q) -{ - q = Genode::min(Genode::min(q, _head_quota), _residual); - if (!_head_yields) - return _head_quota - q; - - _head_yields = false; - return 0; -} - - -void Cpu_scheduler::_quota_introduction(Share &s) -{ - if (s._ready) - _rcl[s._prio].insert_tail(&s._claim_item); - else - _ucl[s._prio].insert_tail(&s._claim_item); -} - - -void Cpu_scheduler::_quota_revokation(Share &s) -{ - if (s._ready) - _rcl[s._prio].remove(&s._claim_item); - else - _ucl[s._prio].remove(&s._claim_item); -} - - -void Cpu_scheduler::_quota_adaption(Share &s, unsigned const q) -{ - if (q) { - if (s._claim > q) - s._claim = q; - } else { - _quota_revokation(s); - } - -} - - -void Cpu_scheduler::update(time_t time) -{ - unsigned duration = (unsigned) (time - _last_time); - _last_time = time; - _need_to_schedule = false; - - /* do not detract the quota if the head context was removed even now */ - if (_head) { - unsigned const r = _trim_consumption(duration); - - if (_head_claims) - _head_claimed(r); - else - _head_filled(r); - - _consumed(duration); - } - - if (_claim_for_head()) - return; - - if (_fill_for_head()) - return; - - _set_head(_idle, _fill, 0); -} - - -void Cpu_scheduler::ready(Share &s) -{ - assert(!s._ready && &s != &_idle); - - s._ready = 1; - s._fill = _fill; - _fills.insert_tail(&s._fill_item); - - if (_head == &_idle) - _need_to_schedule = true; - - if (!s._quota) - return; - - _ucl[s._prio].remove(&s._claim_item); - - if (s._claim) - _rcl[s._prio].insert_head(&s._claim_item); - else - _rcl[s._prio].insert_tail(&s._claim_item); - - /* - * Check whether we need to re-schedule - */ - if (_need_to_schedule) - return; - - /* current head has no quota left */ - if (!_head_claims) { - _need_to_schedule = true; - return; - } - - /* if current head has different priority */ - if (s._prio != _head->_prio) { - _need_to_schedule = s._prio > _head->_prio; - return; - } - - /* if current head has same priority, the ready share gets active */ - if (s._claim) - _need_to_schedule = true; -} - - -void Cpu_scheduler::unready(Share &s) -{ - assert(s._ready && &s != &_idle); - - if (&s == _head) - _need_to_schedule = true; - - s._ready = 0; - _fills.remove(&s._fill_item); - - if (!s._quota) - return; - - _rcl[s._prio].remove(&s._claim_item); - _ucl[s._prio].insert_tail(&s._claim_item); -} - - -void Cpu_scheduler::yield() -{ - _head_yields = true; - _need_to_schedule = true; -} - - -void Cpu_scheduler::remove(Share &s) -{ - assert(&s != &_idle); - - if (s._ready) unready(s); - - if (&s == _head) - _head = nullptr; - - if (!s._quota) - return; - - _ucl[s._prio].remove(&s._claim_item); -} - - -void Cpu_scheduler::insert(Share &s) -{ - assert(!s._ready); - - if (!s._quota) - return; - - s._claim = s._quota; - _ucl[s._prio].insert_head(&s._claim_item); -} - - -void Cpu_scheduler::quota(Share &s, unsigned const q) -{ - assert(&s != &_idle); - - if (s._quota) - _quota_adaption(s, q); - else if (q) - _quota_introduction(s); - - s._quota = q; -} - - -Cpu_share &Cpu_scheduler::head() const -{ - assert(_head); - return *_head; -} - - -Cpu_scheduler::Cpu_scheduler(Share &i, unsigned const q, unsigned const f) -: - _idle(i), _quota(q), _residual(q), _fill(f) -{ - _set_head(i, f, 0); -} diff --git a/repos/base-hw/src/core/kernel/cpu_scheduler.h b/repos/base-hw/src/core/kernel/cpu_scheduler.h deleted file mode 100644 index 70e921f44c..0000000000 --- a/repos/base-hw/src/core/kernel/cpu_scheduler.h +++ /dev/null @@ -1,228 +0,0 @@ -/* - * \brief Schedules CPU shares for the execution time of a CPU - * \author Martin Stein - * \date 2014-10-09 - */ - -/* - * Copyright (C) 2014-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _CORE__KERNEL__CPU_SCHEDULER_H_ -#define _CORE__KERNEL__CPU_SCHEDULER_H_ - -/* core includes */ -#include -#include -#include -#include - -namespace Kernel { - - /** - * Priority of an unconsumed CPU claim versus other unconsumed CPU claims - */ - class Cpu_priority; - - /** - * Scheduling context that is both claim and fill - */ - class Cpu_share; - - /** - * Schedules CPU shares for the execution time of a CPU - */ - class Cpu_scheduler; -} - - -class Kernel::Cpu_priority -{ - private: - - unsigned _value; - - public: - - static constexpr unsigned min() { return 0; } - static constexpr unsigned max() { return cpu_priorities - 1; } - - /** - * Construct priority with value 'v' - */ - Cpu_priority(unsigned const v) - : - _value { Genode::min(v, max()) } - { } - - /* - * Standard operators - */ - - Cpu_priority &operator =(unsigned const v) - { - _value = Genode::min(v, max()); - return *this; - } - - operator unsigned() const { return _value; } -}; - - -class Kernel::Cpu_share -{ - friend class Cpu_scheduler; - - private: - - Double_list_item _fill_item { *this }; - Double_list_item _claim_item { *this }; - Cpu_priority const _prio; - unsigned _quota; - unsigned _claim; - unsigned _fill { 0 }; - bool _ready { false }; - - public: - - /** - * Constructor - * - * \param p claimed priority - * \param q claimed quota - */ - Cpu_share(Cpu_priority const p, unsigned const q) - : _prio(p), _quota(q), _claim(q) { } - - /* - * Accessors - */ - - bool ready() const { return _ready; } - void quota(unsigned const q) { _quota = q; } -}; - -class Kernel::Cpu_scheduler -{ - private: - - typedef Cpu_share Share; - typedef Cpu_priority Prio; - - Double_list _rcl[Prio::max() + 1]; /* ready claims */ - Double_list _ucl[Prio::max() + 1]; /* unready claims */ - Double_list _fills { }; /* ready fills */ - Share &_idle; - Share *_head = nullptr; - unsigned _head_quota = 0; - bool _head_claims = false; - bool _head_yields = false; - unsigned const _quota; - unsigned _residual; - unsigned const _fill; - bool _need_to_schedule { true }; - time_t _last_time { 0 }; - - template void _for_each_prio(F f) - { - bool cancel_for_each_prio { false }; - for (unsigned p = Prio::max(); p != Prio::min() - 1; p--) { - f(p, cancel_for_each_prio); - if (cancel_for_each_prio) - return; - } - } - - static void _reset(Cpu_share &share); - - void _reset_claims(unsigned const p); - void _next_round(); - void _consumed(unsigned const q); - void _set_head(Share &s, unsigned const q, bool const c); - void _next_fill(); - void _head_claimed(unsigned const r); - void _head_filled(unsigned const r); - bool _claim_for_head(); - bool _fill_for_head(); - unsigned _trim_consumption(unsigned &q); - - /** - * Fill 's' becomes a claim due to a quota donation - */ - void _quota_introduction(Share &s); - - /** - * Claim 's' looses its state as claim due to quota revokation - */ - void _quota_revokation(Share &s); - - /** - * The quota of claim 's' changes to 'q' - */ - void _quota_adaption(Share &s, unsigned const q); - - public: - - /** - * Constructor - * - * \param i Gets scheduled with static quota when no other share - * is schedulable. Unremovable. All values get ignored. - * \param q total amount of time quota that can be claimed by shares - * \param f time-slice length of the fill round-robin - */ - Cpu_scheduler(Share &i, unsigned const q, unsigned const f); - - bool need_to_schedule() { return _need_to_schedule; } - void timeout() { _need_to_schedule = true; } - - /** - * Update head according to the current (absolute) time - */ - void update(time_t time); - - /** - * Set share 's' ready - */ - void ready(Share &s); - - /** - * Set share 's' unready - */ - void unready(Share &s); - - /** - * Current head looses its current claim/fill for this round - */ - void yield(); - - /** - * Remove share 's' from scheduler - */ - void remove(Share &s); - - /** - * Insert share 's' into scheduler - */ - void insert(Share &s); - - /** - * Set quota of share 's' to 'q' - */ - void quota(Share &s, unsigned const q); - - /* - * Accessors - */ - - Share &head() const; - unsigned head_quota() const { - return Genode::min(_head_quota, _residual); } - unsigned quota() const { return _quota; } - unsigned residual() const { return _residual; } -}; - -#endif /* _CORE__KERNEL__CPU_SCHEDULER_H_ */ diff --git a/repos/base-hw/src/core/kernel/double_list.h b/repos/base-hw/src/core/kernel/double_list.h deleted file mode 100644 index 14b71f2eb8..0000000000 --- a/repos/base-hw/src/core/kernel/double_list.h +++ /dev/null @@ -1,159 +0,0 @@ -/* - * \brief List of double connected items - * \author Martin Stein - * \date 2012-11-30 - */ - -/* - * Copyright (C) 2012-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _CORE__KERNEL__DOUBLE_LIST_H_ -#define _CORE__KERNEL__DOUBLE_LIST_H_ - -namespace Kernel { - - /** - * Ability to be an item in a double connected list - */ - template - class Double_list_item; - - /** - * List of double connected items - */ - template - class Double_list; -} - - -template -class Kernel::Double_list_item -{ - friend class Double_list; - - private: - - Double_list_item * _next = nullptr; - Double_list_item * _prev = nullptr; - T & _payload; - - public: - - Double_list_item(T &payload) : _payload(payload) { } - - T &payload() { return _payload; } -}; - - -template -class Kernel::Double_list -{ - private: - - typedef Double_list_item Item; - - Item * _head; - Item * _tail; - - void _connect_neighbors(Item * const i) - { - i->_prev->_next = i->_next; - i->_next->_prev = i->_prev; - } - - void _to_tail(Item * const i) - { - if (i == _tail) { return; } - _connect_neighbors(i); - i->_prev = _tail; - i->_next = 0; - _tail->_next = i; - _tail = i; - } - - public: - - /** - * Construct empty list - */ - Double_list() : _head(0), _tail(0) { } - - /** - * Move item 'i' from its current list position to the tail - */ - void to_tail(Item * const i) - { - if (i == _head) { head_to_tail(); } - else { _to_tail(i); } - } - - /** - * Insert item 'i' as new tail into list - */ - void insert_tail(Item * const i) - { - if (_tail) { _tail->_next = i; } - else { _head = i; } - i->_prev = _tail; - i->_next = 0; - _tail = i; - } - - /** - * Insert item 'i' as new head into list - */ - void insert_head(Item * const i) - { - if (_head) { _head->_prev = i; } - else { _tail = i; } - i->_next = _head; - i->_prev = 0; - _head = i; - } - - /** - * Remove item 'i' from list - */ - void remove(Item * const i) - { - if (i == _tail) { _tail = i->_prev; } - else { i->_next->_prev = i->_prev; } - if (i == _head) { _head = i->_next; } - else { i->_prev->_next = i->_next; } - } - - /** - * Move head item of list to tail position - */ - void head_to_tail() - { - if (!_head || _head == _tail) - return; - - _head->_prev = _tail; - _tail->_next = _head; - _head = _head->_next; - _head->_prev = 0; - _tail = _tail->_next; - _tail->_next = 0; - } - - /** - * Call function 'f' of type 'void (Item *)' for each item in the list - */ - template void for_each(F f) { - for (Item * i = _head; i; i = i->_next) { f(i->payload()); } } - - /* - * Accessors - */ - - Item * head() const { return _head; } - static Item * next(Item * const i) { return i->_next; } -}; - -#endif /* _CORE__KERNEL__DOUBLE_LIST_H_ */ diff --git a/repos/base-hw/src/core/kernel/inter_processor_work.h b/repos/base-hw/src/core/kernel/inter_processor_work.h index b6a4f2fdc6..f2791ccac7 100644 --- a/repos/base-hw/src/core/kernel/inter_processor_work.h +++ b/repos/base-hw/src/core/kernel/inter_processor_work.h @@ -32,7 +32,7 @@ class Kernel::Inter_processor_work : Genode::Interface { public: - virtual void execute() = 0; + virtual void execute(Cpu &) = 0; protected: diff --git a/repos/base-hw/src/core/kernel/ipc_node.cc b/repos/base-hw/src/core/kernel/ipc_node.cc index ffa2e3abdf..f06b557c36 100644 --- a/repos/base-hw/src/core/kernel/ipc_node.cc +++ b/repos/base-hw/src/core/kernel/ipc_node.cc @@ -25,153 +25,107 @@ using namespace Kernel; -void Ipc_node::_receive_request(Ipc_node &caller) +void Ipc_node::_receive_from(Ipc_node &node) { - _thread.ipc_copy_msg(caller._thread); - _caller = &caller; - _state = INACTIVE; + _thread.ipc_copy_msg(node._thread); + _in.state = In::REPLY; } -void Ipc_node::_receive_reply(Ipc_node &callee) +void Ipc_node::_cancel_send() { - _thread.ipc_copy_msg(callee._thread); - _state = INACTIVE; - _thread.ipc_send_request_succeeded(); -} + if (_out.node) { + /* + * If the receiver is already processing our message, + * we have to ensure that he skips sending a reply by + * letting his node state indicate our withdrawal. + */ + if (_out.node->_in.state == In::REPLY) + _out.node->_in.queue.head([&] (Queue_item &item) { + if (&item == &_queue_item) + _out.node->_in.state = In::REPLY_NO_SENDER; + }); -void Ipc_node::_announce_request(Ipc_node &node) -{ - /* directly receive request if we've awaited it */ - if (_state == AWAIT_REQUEST) { - _receive_request(node); - _thread.ipc_await_request_succeeded(); - return; + _out.node->_in.queue.remove(_queue_item); + _out.node = nullptr; + } + if (_out.sending()) { + _thread.ipc_send_request_failed(); + _out.state = Out::READY; } - - /* cannot receive yet, so queue request */ - _request_queue.enqueue(node._request_queue_item); } -void Ipc_node::_cancel_request_queue() +bool Ipc_node::_helping() const { - _request_queue.dequeue_all([] (Queue_item &item) { - Ipc_node &node { item.object() }; - node._outbuf_request_cancelled(); + return _out.state == Out::SEND_HELPING && _out.node; +} + + +bool Ipc_node::ready_to_send() const +{ + return _out.state == Out::READY && !_in.waiting(); +} + + +void Ipc_node::send(Ipc_node &node, bool help) +{ + node._in.queue.enqueue(_queue_item); + + if (node._in.waiting()) { + node._receive_from(*this); + node._thread.ipc_await_request_succeeded(); + } + _out.node = &node; + _out.state = help ? Out::SEND_HELPING : Out::SEND; +} + + +Thread &Ipc_node::helping_destination() +{ + return _helping() ? _out.node->helping_destination() : _thread; +} + + +bool Ipc_node::ready_to_wait() const +{ + return _in.state == In::READY; +} + + +void Ipc_node::wait() +{ + _in.state = In::WAIT; + _in.queue.head([&] (Queue_item &item) { + _receive_from(item.object()); }); } -void Ipc_node::_cancel_outbuf_request() +void Ipc_node::reply() { - if (_callee) { - _callee->_announced_request_cancelled(*this); - _callee = nullptr; - } -} + if (_in.state == In::REPLY) + _in.queue.dequeue([&] (Queue_item &item) { + Ipc_node &node { item.object() }; + node._thread.ipc_copy_msg(_thread); + node._out.node = nullptr; + node._out.state = Out::READY; + node._thread.ipc_send_request_succeeded(); + }); - -void Ipc_node::_cancel_inbuf_request() -{ - if (_caller) { - _caller->_outbuf_request_cancelled(); - _caller = nullptr; - } -} - - -void Ipc_node::_announced_request_cancelled(Ipc_node &node) -{ - if (_caller == &node) - _caller = nullptr; - else - _request_queue.remove(node._request_queue_item); -} - - -void Ipc_node::_outbuf_request_cancelled() -{ - if (_callee == nullptr) - return; - - _callee = nullptr; - _state = INACTIVE; - _thread.ipc_send_request_failed(); -} - - -bool Ipc_node::_helps_outbuf_dst() -{ - return (_state == AWAIT_REPLY) && _help; -} - - -bool Ipc_node::can_send_request() -{ - return _state == INACTIVE; -} - - -void Ipc_node::send_request(Ipc_node &callee, bool help) -{ - _state = AWAIT_REPLY; - _callee = &callee; - _help = false; - - /* announce request */ - _callee->_announce_request(*this); - - _help = help; -} - - -Thread &Ipc_node::helping_sink() -{ - return _helps_outbuf_dst() ? _callee->helping_sink() : _thread; -} - - -bool Ipc_node::can_await_request() -{ - return _state == INACTIVE; -} - - -void Ipc_node::await_request() -{ - _state = AWAIT_REQUEST; - _request_queue.dequeue([&] (Queue_item &item) { - _receive_request(item.object()); - }); -} - - -void Ipc_node::send_reply() -{ - /* reply to the last request if we have to */ - if (_state == INACTIVE && _caller) { - _caller->_receive_reply(*this); - _caller = nullptr; - } + _in.state = In::READY; } void Ipc_node::cancel_waiting() { - switch (_state) { - case AWAIT_REPLY: - _cancel_outbuf_request(); - _state = INACTIVE; - _thread.ipc_send_request_failed(); - break; - case AWAIT_REQUEST: - _state = INACTIVE; + if (_out.sending()) + _cancel_send(); + + if (_in.waiting()) { + _in.state = In::READY; _thread.ipc_await_request_failed(); - break; - return; - default: return; } } @@ -184,8 +138,12 @@ Ipc_node::Ipc_node(Thread &thread) Ipc_node::~Ipc_node() { - _cancel_request_queue(); - _cancel_inbuf_request(); - _cancel_outbuf_request(); -} + _in.state = In::DESTRUCT; + _out.state = Out::DESTRUCT; + _cancel_send(); + + _in.queue.for_each([&] (Queue_item &item) { + item.object()._cancel_send(); + }); +} diff --git a/repos/base-hw/src/core/kernel/ipc_node.h b/repos/base-hw/src/core/kernel/ipc_node.h index b8e25ea4b7..df9f3d7d19 100644 --- a/repos/base-hw/src/core/kernel/ipc_node.h +++ b/repos/base-hw/src/core/kernel/ipc_node.h @@ -35,140 +35,122 @@ class Kernel::Ipc_node using Queue_item = Genode::Fifo_element; using Queue = Genode::Fifo; - enum State + struct In { - INACTIVE = 1, - AWAIT_REPLY = 2, - AWAIT_REQUEST = 3, + enum State { READY, WAIT, REPLY, REPLY_NO_SENDER, DESTRUCT }; + + State state { READY }; + Queue queue { }; + + bool waiting() const + { + return state == WAIT; + } + }; + + struct Out + { + enum State { READY, SEND, SEND_HELPING, DESTRUCT }; + + State state { READY }; + Ipc_node *node { nullptr }; + + bool sending() const + { + return state == SEND_HELPING || state == SEND; + } }; Thread &_thread; - Queue_item _request_queue_item { *this }; - State _state { INACTIVE }; - Ipc_node *_caller { nullptr }; - Ipc_node *_callee { nullptr }; - bool _help { false }; - Queue _request_queue { }; + Queue_item _queue_item { *this }; + Out _out { }; + In _in { }; /** - * Buffer next request from request queue in 'r' to handle it + * Receive a message from another IPC node */ - void _receive_request(Ipc_node &caller); + void _receive_from(Ipc_node &node); /** - * Receive a given reply if one is expected + * Cancel an ongoing send operation */ - void _receive_reply(Ipc_node &callee); + void _cancel_send(); /** - * Insert 'r' into request queue, buffer it if we were waiting for it + * Return wether this IPC node is helping another one */ - void _announce_request(Ipc_node &node); + bool _helping() const; /** - * Cancel all requests in request queue - */ - void _cancel_request_queue(); - - /** - * Cancel request in outgoing buffer - */ - void _cancel_outbuf_request(); - - /** - * Cancel request in incoming buffer - */ - void _cancel_inbuf_request(); - - /** - * A request 'r' in inbuf or request queue was cancelled by sender - */ - void _announced_request_cancelled(Ipc_node &node); - - /** - * The request in the outbuf was cancelled by receiver - */ - void _outbuf_request_cancelled(); - - /** - * Return wether we are the source of a helping relationship - */ - bool _helps_outbuf_dst(); - - /** - * Make the class noncopyable because it has pointer members + * Noncopyable */ Ipc_node(const Ipc_node&) = delete; - - /** - * Make the class noncopyable because it has pointer members - */ const Ipc_node& operator=(const Ipc_node&) = delete; public: - /** - * Destructor - */ + Ipc_node(Thread &thread); + ~Ipc_node(); /** - * Constructor + * Return whether this IPC node is ready to send a message */ - Ipc_node(Thread &thread); + bool ready_to_send() const; /** - * Send a request and wait for the according reply + * Send a message and wait for the according reply * - * \param callee targeted IPC node - * \param help wether the request implies a helping relationship + * \param node targeted IPC node + * \param help wether the request implies a helping relationship */ - bool can_send_request(); - void send_request(Ipc_node &callee, - bool help); + void send(Ipc_node &node, bool help); /** - * Return root destination of the helping-relation tree we are in + * Return final destination of the helping-chain + * this IPC node is part of, or its own thread otherwise */ - Thread &helping_sink(); + Thread &helping_destination(); /** - * Call function 'f' of type 'void (Ipc_node *)' for each helper + * Call 'fn' of type 'void (Ipc_node *)' for each helper */ - template void for_each_helper(F f) + void for_each_helper(auto const &fn) { - /* if we have a helper in the receive buffer, call 'f' for it */ - if (_caller && _caller->_help) - f(_caller->_thread); - - /* call 'f' for each helper in our request queue */ - _request_queue.for_each([f] (Queue_item &item) { + _in.queue.for_each([fn] (Queue_item &item) { Ipc_node &node { item.object() }; - if (node._help) - f(node._thread); + if (node._helping()) + fn(node._thread); }); } /** - * Wait until a request has arrived and load it for handling + * Return whether this IPC node is ready to wait for messages + */ + bool ready_to_wait() const; + + /** + * Wait until a message has arrived, or handle it if one is available * - * \return wether a request could be received already + * \return wether a message could be received already */ - bool can_await_request(); - void await_request(); + void wait(); /** - * Reply to last request if there's any + * Reply to last message if there's any */ - void send_reply(); + void reply(); /** - * If IPC node waits, cancel '_outbuf' to stop waiting + * If IPC node waits, cancel it */ void cancel_waiting(); - bool awaits_request() const { return _state == AWAIT_REQUEST; } + /** + * Return whether this IPC node is waiting for messages + */ + bool waiting() const { return _in.waiting(); } }; #endif /* _CORE__KERNEL__IPC_NODE_H_ */ diff --git a/repos/base-hw/src/core/kernel/irq.h b/repos/base-hw/src/core/kernel/irq.h index 4472cb8cb8..9b8be0bf65 100644 --- a/repos/base-hw/src/core/kernel/irq.h +++ b/repos/base-hw/src/core/kernel/irq.h @@ -42,7 +42,7 @@ namespace Kernel { } -namespace Genode { +namespace Core { /** * Core front-end of a user interrupt @@ -182,11 +182,11 @@ class Kernel::User_irq : public Kernel::Irq * \param polarity low or high * \param sig capability of signal context */ - static capid_t syscall_create(Genode::Kernel_object & irq, - unsigned nr, - Genode::Irq_session::Trigger trigger, - Genode::Irq_session::Polarity polarity, - capid_t sig) + static capid_t syscall_create(Core::Kernel_object &irq, + unsigned nr, + Genode::Irq_session::Trigger trigger, + Genode::Irq_session::Polarity polarity, + capid_t sig) { return (capid_t)call(call_id_new_irq(), (Call_arg)&irq, nr, (trigger << 2) | polarity, sig); @@ -197,7 +197,7 @@ class Kernel::User_irq : public Kernel::Irq * * \param irq reference to constructible object */ - static void syscall_destroy(Genode::Kernel_object &irq) { + static void syscall_destroy(Core::Kernel_object &irq) { call(call_id_delete_irq(), (Call_arg) &irq); } Object &kernel_object() { return _kernel_object; } diff --git a/repos/base-hw/src/core/kernel/lock.cc b/repos/base-hw/src/core/kernel/lock.cc index 21ed98b44d..e5b199dec6 100644 --- a/repos/base-hw/src/core/kernel/lock.cc +++ b/repos/base-hw/src/core/kernel/lock.cc @@ -15,7 +15,7 @@ #include #include -/* base-hw Core includes */ +/* base-hw core includes */ #include #include diff --git a/repos/base-hw/src/core/kernel/lock.h b/repos/base-hw/src/core/kernel/lock.h index 1befd37bac..60b542166b 100644 --- a/repos/base-hw/src/core/kernel/lock.h +++ b/repos/base-hw/src/core/kernel/lock.h @@ -15,9 +15,6 @@ #ifndef _CORE__SPEC__SMP__KERNEL__LOCK_H_ #define _CORE__SPEC__SMP__KERNEL__LOCK_H_ -/* Genode includes */ -#include - namespace Kernel { class Lock; } @@ -37,7 +34,14 @@ class Kernel::Lock void lock(); void unlock(); - using Guard = Genode::Lock_guard; + struct Guard + { + Lock &_lock; + + explicit Guard(Lock &lock) : _lock(lock) { _lock.lock(); } + + ~Guard() { _lock.unlock(); } + }; }; #endif /* _CORE__SPEC__SMP__KERNEL__LOCK_H_ */ diff --git a/repos/base-hw/src/core/kernel/main.cc b/repos/base-hw/src/core/kernel/main.cc index 855d6dbb7c..e14b17f1c5 100644 --- a/repos/base-hw/src/core/kernel/main.cc +++ b/repos/base-hw/src/core/kernel/main.cc @@ -12,13 +12,8 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* base includes */ -#include - -/* base Core includes */ +/* core includes */ #include - -/* base-hw Core includes */ #include #include #include @@ -28,11 +23,7 @@ /* base-hw-internal includes */ #include - -namespace Kernel { - - class Main; -} +namespace Kernel { class Main; } class Kernel::Main @@ -49,35 +40,27 @@ class Kernel::Main static Main *_instance; Lock _data_lock { }; - Cpu_pool _cpu_pool; + Cpu_pool _cpu_pool { }; Irq::Pool _user_irq_pool { }; Board::Address_space_id_allocator _addr_space_id_alloc { }; - Genode::Core_platform_pd _core_platform_pd { _addr_space_id_alloc }; + Core::Core_platform_pd _core_platform_pd { _addr_space_id_alloc }; Genode::Constructible _core_main_thread { }; Board::Global_interrupt_controller _global_irq_ctrl { }; - Board::Serial _serial { Genode::Platform::mmio_to_virt(Board::UART_BASE), + Board::Serial _serial { Core::Platform::mmio_to_virt(Board::UART_BASE), Board::UART_CLOCK, SERIAL_BAUD_RATE }; void _handle_kernel_entry(); - Main(unsigned nr_of_cpus); - public: - static Genode::Platform_pd &core_platform_pd(); + static Core::Platform_pd &core_platform_pd(); }; Kernel::Main *Kernel::Main::_instance; -Kernel::Main::Main(unsigned nr_of_cpus) -: - _cpu_pool { nr_of_cpus } -{ } - - void Kernel::Main::_handle_kernel_entry() { Cpu &cpu = _cpu_pool.cpu(Cpu::executing_id()); @@ -101,12 +84,9 @@ void Kernel::main_handle_kernel_entry() void Kernel::main_initialize_and_handle_kernel_entry() { - static_assert(sizeof(Genode::sizet_arithm_t) >= 2 * sizeof(size_t), - "Bad result type for size_t arithmetics."); - using Boot_info = Hw::Boot_info; - static volatile bool instance_initialized { false }; + static Lock init_lock; static volatile unsigned nr_of_initialized_cpus { 0 }; static volatile bool kernel_initialized { false }; @@ -114,24 +94,46 @@ void Kernel::main_initialize_and_handle_kernel_entry() *reinterpret_cast(Hw::Mm::boot_info().base) }; unsigned const nr_of_cpus { boot_info.cpus }; - bool const primary_cpu { Cpu::executing_id() == Cpu::primary_id() }; - if (primary_cpu) { + /** + * Let the first CPU create a Main object and initialize the static + * reference to it. + */ + { + Lock::Guard guard(init_lock); - /** - * Let the primary CPU create a Main object and initialize the static - * reference to it. - */ - static Main instance { nr_of_cpus }; + static Main instance; Main::_instance = &instance; - } else { + } - /** - * Let secondary CPUs block until the primary CPU has managed to set - * up the Main instance. - */ - while (!instance_initialized) { } + /* the CPU resumed if the kernel is already initialized */ + if (kernel_initialized) { + + { + Lock::Guard guard(Main::_instance->_data_lock); + + if (nr_of_initialized_cpus == nr_of_cpus) { + nr_of_initialized_cpus = 0; + + Main::_instance->_serial.init(); + Main::_instance->_global_irq_ctrl.init(); + } + + nr_of_initialized_cpus = nr_of_initialized_cpus + 1; + + Main::_instance->_cpu_pool.cpu(Cpu::executing_id()).reinit_cpu(); + + if (nr_of_initialized_cpus == nr_of_cpus) { + Genode::raw("kernel resumed"); + } + } + + while (nr_of_initialized_cpus < nr_of_cpus) { } + + Main::_instance->_handle_kernel_entry(); + /* never reached */ + return; } { @@ -140,14 +142,13 @@ void Kernel::main_initialize_and_handle_kernel_entry() * CPU pool. */ Lock::Guard guard(Main::_instance->_data_lock); - instance_initialized = true; Main::_instance->_cpu_pool.initialize_executing_cpu( Main::_instance->_addr_space_id_alloc, Main::_instance->_user_irq_pool, Main::_instance->_core_platform_pd.kernel_pd(), Main::_instance->_global_irq_ctrl); - nr_of_initialized_cpus++; + nr_of_initialized_cpus = nr_of_initialized_cpus + 1; }; /** @@ -156,47 +157,45 @@ void Kernel::main_initialize_and_handle_kernel_entry() */ while (nr_of_initialized_cpus < nr_of_cpus) { } - if (primary_cpu) { - - /** - * Let the primary CPU initialize the core main thread and finish - * initialization of the boot info. - */ - + /** + * Let the primary CPU initialize the core main thread and finish + * initialization of the boot info. + */ + { Lock::Guard guard(Main::_instance->_data_lock); - Main::_instance->_cpu_pool.for_each_cpu([&] (Kernel::Cpu &cpu) { - boot_info.kernel_irqs.add(cpu.timer().interrupt_id()); - }); - boot_info.kernel_irqs.add((unsigned)Board::Pic::IPI); + if (Cpu::executing_id() == Main::_instance->_cpu_pool.primary_cpu().id()) { + Main::_instance->_cpu_pool.for_each_cpu([&] (Kernel::Cpu &cpu) { + boot_info.kernel_irqs.add(cpu.timer().interrupt_id()); + }); + boot_info.kernel_irqs.add((unsigned)Board::Pic::IPI); - Main::_instance->_core_main_thread.construct( - Main::_instance->_addr_space_id_alloc, - Main::_instance->_user_irq_pool, - Main::_instance->_cpu_pool, - Main::_instance->_core_platform_pd.kernel_pd()); + Main::_instance->_core_main_thread.construct( + Main::_instance->_addr_space_id_alloc, + Main::_instance->_user_irq_pool, + Main::_instance->_cpu_pool, + Main::_instance->_core_platform_pd.kernel_pd()); - boot_info.core_main_thread_utcb = - (addr_t)Main::_instance->_core_main_thread->utcb(); + boot_info.core_main_thread_utcb = + (addr_t)Main::_instance->_core_main_thread->utcb(); - Genode::log(""); - Genode::log("kernel initialized"); - kernel_initialized = true; - - } else { - - /** - * Let secondary CPUs block until the primary CPU has initialized the - * core main thread and finished initialization of the boot info. - */ - while (!kernel_initialized) {;} + Genode::log(""); + Genode::log("kernel initialized"); + kernel_initialized = true; + } } + /** + * Let secondary CPUs block until the primary CPU has initialized the + * core main thread and finished initialization of the boot info. + */ + while (!kernel_initialized) {;} + Main::_instance->_handle_kernel_entry(); } -Genode::Platform_pd &Kernel::Main::core_platform_pd() +Core::Platform_pd &Kernel::Main::core_platform_pd() { return _instance->_core_platform_pd; } @@ -214,15 +213,14 @@ Kernel::time_t Kernel::main_read_idle_thread_execution_time(unsigned cpu_idx) } -Genode::Platform_pd & -Genode::Platform_thread::_kernel_main_get_core_platform_pd() +Core::Platform_pd &Core::Platform_thread::_kernel_main_get_core_platform_pd() { return Kernel::Main::core_platform_pd(); } -bool Genode::map_local(addr_t from_phys, addr_t to_virt, size_t num_pages, - Page_flags flags) +bool Core::map_local(addr_t from_phys, addr_t to_virt, size_t num_pages, + Page_flags flags) { return Kernel::Main::core_platform_pd().insert_translation( @@ -230,7 +228,7 @@ bool Genode::map_local(addr_t from_phys, addr_t to_virt, size_t num_pages, } -bool Genode::unmap_local(addr_t virt_addr, size_t num_pages) +bool Core::unmap_local(addr_t virt_addr, size_t num_pages) { Kernel::Main::core_platform_pd().flush( virt_addr, num_pages * get_page_size()); diff --git a/repos/base-hw/src/core/kernel/main.h b/repos/base-hw/src/core/kernel/main.h index fe5a8d3367..dd728ad2f6 100644 --- a/repos/base-hw/src/core/kernel/main.h +++ b/repos/base-hw/src/core/kernel/main.h @@ -14,7 +14,7 @@ #ifndef _KERNEL__MAIN_H_ #define _KERNEL__MAIN_H_ -/* base-hw Core includes */ +/* base-hw core includes */ #include namespace Kernel { diff --git a/repos/base-hw/src/core/kernel/object.h b/repos/base-hw/src/core/kernel/object.h index d54ece909d..0c242bad55 100644 --- a/repos/base-hw/src/core/kernel/object.h +++ b/repos/base-hw/src/core/kernel/object.h @@ -18,9 +18,9 @@ #include #include #include -#include /* core includes */ +#include #include #include @@ -265,9 +265,7 @@ class Kernel::Core_object : public T, Kernel::Core_object_identity /** * Constructor used for objects other than the Core PD */ - template - Core_object(Pd &core_pd, - ARGS &&... args) + Core_object(Pd &core_pd, auto &&... args) : T(args...), Core_object_identity(core_pd, *static_cast(this)) @@ -276,8 +274,7 @@ class Kernel::Core_object : public T, Kernel::Core_object_identity /** * Constructor used for Core PD object */ - template - Core_object(ARGS &&... args) + Core_object(auto &&... args) : T(args...), Core_object_identity(*static_cast(this)) diff --git a/repos/base-hw/src/core/kernel/pd.h b/repos/base-hw/src/core/kernel/pd.h index 4a82c0b71f..e2658b4b73 100644 --- a/repos/base-hw/src/core/kernel/pd.h +++ b/repos/base-hw/src/core/kernel/pd.h @@ -15,16 +15,13 @@ #ifndef _CORE__KERNEL__PD_H_ #define _CORE__KERNEL__PD_H_ -/* base-hw Core includes */ +/* base-hw core includes */ #include #include #include #include -/* base includes */ -#include - -namespace Genode { class Platform_pd; } +namespace Core { class Platform_pd; } namespace Kernel { @@ -50,13 +47,13 @@ class Kernel::Pd Kernel::Object _kernel_object { *this }; Hw::Page_table &_table; - Genode::Platform_pd &_platform_pd; + Core::Platform_pd &_platform_pd; Capid_allocator _capid_alloc { }; Object_identity_reference_tree _cap_tree { }; public: - Genode::Cpu::Mmu_context mmu_regs; + Core::Cpu::Mmu_context mmu_regs; /** * Constructor @@ -65,7 +62,7 @@ class Kernel::Pd * \param platform_pd core object of the PD */ Pd(Hw::Page_table &table, - Genode::Platform_pd &platform_pd, + Core::Platform_pd &platform_pd, Board::Address_space_id_allocator &addr_space_id_alloc) : _table(table), @@ -82,15 +79,15 @@ class Kernel::Pd oir->~Object_identity_reference(); } - static capid_t syscall_create(Genode::Kernel_object &p, - Hw::Page_table &tt, - Genode::Platform_pd &pd) + static capid_t syscall_create(Core::Kernel_object &p, + Hw::Page_table &tt, + Core::Platform_pd &pd) { return (capid_t)call(call_id_new_pd(), (Call_arg)&p, (Call_arg)&tt, (Call_arg)&pd); } - static void syscall_destroy(Genode::Kernel_object & p) { + static void syscall_destroy(Core::Kernel_object & p) { call(call_id_delete_pd(), (Call_arg)&p); } /** @@ -105,7 +102,7 @@ class Kernel::Pd ***************/ Object &kernel_object() { return _kernel_object; } - Genode::Platform_pd &platform_pd() { return _platform_pd; } + Core::Platform_pd &platform_pd() { return _platform_pd; } Hw::Page_table &translation_table() { return _table; } Capid_allocator &capid_alloc() { return _capid_alloc; } Object_identity_reference_tree &cap_tree() { return _cap_tree; } diff --git a/repos/base-hw/src/core/kernel/scheduler.cc b/repos/base-hw/src/core/kernel/scheduler.cc new file mode 100644 index 0000000000..5dbd7f2c18 --- /dev/null +++ b/repos/base-hw/src/core/kernel/scheduler.cc @@ -0,0 +1,271 @@ +/* + * \brief Schedules CPU contexts for the execution time of a CPU + * \author Martin Stein + * \author Stefan Kalkowski + * \date 2014-10-09 + */ + +/* + * Copyright (C) 2014-2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#include +#include +#include + +using namespace Kernel; + + +void Scheduler::_consumed(unsigned const time) +{ + if (_super_period_left > time) { + _super_period_left -= time; + return; + } + + /** + * Start of a new super period + */ + _super_period_left = _super_period_length; + + /* reset all priotized contexts */ + _each_prio_until([&] (Priority const priority) { + unsigned const p = priority.value; + _rpl[p].for_each([&] (Context &c) { c._reset(); }); + _upl[p].for_each([&] (Context &c) { c._reset(); }); + return false; + }); +} + + +void Scheduler::_set_current(Context &context, unsigned const q) +{ + _current_quantum = q; + _current = &context; +} + + +void Scheduler::_account_priotized(Context &c, unsigned const r) +{ + if (!c._quota) + return; + + c._priotized_time_left = (r > c._quota) ? c._quota : r; + + if (c._priotized_time_left || !c.ready()) + return; + + _rpl[c._priority].to_tail(&c._priotized_le); + + /* + * This is an optimization for the case that a prioritized scheduling + * context needs sligtly more time during a round than granted via quota. + * If this is the case, we move the scheduling context to the front of + * the unprioritized schedule once its quota gets depleted and thereby + * at least ensure that it does not have to wait for all unprioritized + * scheduling contexts as well before being scheduled again. + */ + if (_state != YIELD) + _slack_list.to_head(&c._slack_le); +} + + +void Scheduler::_account_slack(Context &c, unsigned const r) +{ + if (r) { + c._slack_time_left = r; + return; + } + + c._slack_time_left = _slack_quota; + if (c.ready()) _slack_list.to_tail(&c._slack_le); +} + + +bool Scheduler::_schedule_priotized() +{ + bool result { false }; + + _each_prio_until([&] (Priority const p) { + Context* const context = _rpl[p.value].head(); + + if (!context) + return false; + + if (!context->_priotized_time_left) + return false; + + _set_current(*context, context->_priotized_time_left); + result = true; + return true; + }); + return result; +} + + +bool Scheduler::_schedule_slack() +{ + Context *const context = _slack_list.head(); + if (!context) + return false; + + _set_current(*context, context->_slack_time_left); + return true; +} + + +void Scheduler::update(time_t time) +{ + using namespace Genode; + + unsigned const duration = + min(min((unsigned)(time-_last_time), _current_quantum), + _super_period_left); + _last_time = time; + + /* do not detract the quota of idle or removed context */ + if (_current && _current != &_idle) { + unsigned const r = (_state != YIELD) ? _current_quantum - duration : 0; + if (_current->_priotized_time_left) _account_priotized(*_current, r); + else _account_slack(*_current, r); + } + + _consumed(duration); + + _state = UP_TO_DATE; + + if (_schedule_priotized()) + return; + + if (_schedule_slack()) + return; + + _set_current(_idle, _slack_quota); +} + + +void Scheduler::ready(Context &c) +{ + assert(!c.ready() && &c != &_idle); + + c._ready = true; + + bool keep_current = + (_current->_priotized_time_left && + !c._priotized_time_left) || + (_current->_priotized_time_left && + (_current->_priority > c._priority)); + + if (c._quota) { + _upl[c._priority].remove(&c._priotized_le); + if (c._priotized_time_left) + _rpl[c._priority].insert_head(&c._priotized_le); + else + _rpl[c._priority].insert_tail(&c._priotized_le); + } + + _slack_list.insert_head(&c._slack_le); + + if (!keep_current && _state == UP_TO_DATE) _state = OUT_OF_DATE; +} + + +void Scheduler::unready(Context &c) +{ + assert(c.ready() && &c != &_idle); + + if (&c == _current && _state == UP_TO_DATE) _state = OUT_OF_DATE; + + c._ready = false; + _slack_list.remove(&c._slack_le); + + if (!c._quota) + return; + + _rpl[c._priority].remove(&c._priotized_le); + _upl[c._priority].insert_tail(&c._priotized_le); +} + + +void Scheduler::yield() +{ + _state = YIELD; +} + + +void Scheduler::remove(Context &c) +{ + assert(&c != &_idle); + + if (c._ready) unready(c); + + if (&c == _current) + _current = nullptr; + + if (!c._quota) + return; + + _upl[c._priority].remove(&c._priotized_le); +} + + +void Scheduler::insert(Context &c) +{ + assert(!c.ready()); + + c._slack_time_left = _slack_quota; + + if (!c._quota) + return; + + c._reset(); + _upl[c._priority].insert_head(&c._priotized_le); +} + + +void Scheduler::quota(Context &c, unsigned const q) +{ + assert(&c != &_idle); + + if (c._quota) { + if (c._priotized_time_left > q) c._priotized_time_left = q; + + /* does the quota gets revoked completely? */ + if (!q) { + if (c.ready()) _rpl[c._priority].remove(&c._priotized_le); + else _upl[c._priority].remove(&c._priotized_le); + } + } else if (q) { + + /* initial quota introduction */ + if (c.ready()) _rpl[c._priority].insert_tail(&c._priotized_le); + else _upl[c._priority].insert_tail(&c._priotized_le); + } + + c.quota(q); +} + + +Scheduler::Context& Scheduler::current() +{ + if (!_current) { + Genode::error("attempt to access invalid scheduler's current context"); + update(_last_time); + } + return *_current; +} + + +Scheduler::Scheduler(Context &idle, + unsigned const super_period_length, + unsigned const slack_quota) +: + _slack_quota(slack_quota), + _super_period_length(super_period_length), + _idle(idle) +{ + _set_current(idle, slack_quota); +} diff --git a/repos/base-hw/src/core/kernel/scheduler.h b/repos/base-hw/src/core/kernel/scheduler.h new file mode 100644 index 0000000000..7727b24995 --- /dev/null +++ b/repos/base-hw/src/core/kernel/scheduler.h @@ -0,0 +1,245 @@ +/* + * \brief Schedules CPU shares for the execution time of a CPU + * \author Martin Stein + * \author Stefan Kalkowski + * \date 2014-10-09 + */ + +/* + * Copyright (C) 2014-2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CORE__KERNEL__SCHEDULER_H_ +#define _CORE__KERNEL__SCHEDULER_H_ + +/* core includes */ +#include +#include +#include +#include + +namespace Kernel { class Scheduler; } + + +/** + * Forward declaration of corresponding unit-test classes for friendship + */ +namespace Scheduler_test { + class Scheduler; + class Context; + class Main; +} + + +class Kernel::Scheduler +{ + public: + + struct Priority + { + unsigned value; + + static constexpr unsigned min() { return 0; } + static constexpr unsigned max() { return cpu_priorities - 1; } + + Priority(unsigned const value) + : value(Genode::min(value, max())) { } + + Priority &operator =(unsigned const v) + { + value = Genode::min(v, max()); + return *this; + } + }; + + + class Context + { + private: + + friend class Scheduler; + friend class Scheduler_test::Scheduler; + friend class Scheduler_test::Context; + + using List_element = Genode::List_element; + + unsigned _priority; + unsigned _quota; + List_element _priotized_le { this }; + unsigned _priotized_time_left { 0 }; + + List_element _slack_le { this }; + unsigned _slack_time_left { 0 }; + + bool _ready { false }; + + void _reset() { _priotized_time_left = _quota; } + + public: + + Context(Priority const priority, + unsigned const quota) + : + _priority(priority.value), + _quota(quota) { } + + bool ready() const { return _ready; } + void quota(unsigned const q) { _quota = q; } + }; + + private: + + friend class Scheduler_test::Scheduler; + friend class Scheduler_test::Main; + + class Context_list + { + private: + + using List_element = Genode::List_element; + + Genode::List _list {}; + List_element *_last { nullptr }; + + public: + + void for_each(auto const &fn) + { + for (List_element * le = _list.first(); le; le = le->next()) + fn(*le->object()); + } + + void for_each(auto const &fn) const + { + for (List_element const * le = _list.first(); le; + le = le->next()) fn(*le->object()); + } + + Context* head() const { + return _list.first() ? _list.first()->object() : nullptr; } + + void insert_head(List_element * const le) + { + _list.insert(le); + if (!_last) _last = le; + } + + void insert_tail(List_element * const le) + { + _list.insert(le, _last); + _last = le; + } + + void remove(List_element * const le) + { + _list.remove(le); + + if (_last != le) + return; + + _last = nullptr; + for (List_element * le = _list.first(); le; le = le->next()) + _last = le; + } + + void to_tail(List_element * const le) + { + remove(le); + insert_tail(le); + } + + void to_head(List_element * const le) + { + remove(le); + insert_head(le); + } + }; + + enum State { UP_TO_DATE, OUT_OF_DATE, YIELD }; + + unsigned const _slack_quota; + unsigned const _super_period_length; + + unsigned _super_period_left { _super_period_length }; + unsigned _current_quantum { 0 }; + + time_t _last_time { 0 }; + State _state { UP_TO_DATE }; + + Context_list _rpl[cpu_priorities]; /* ready lists by priority */ + Context_list _upl[cpu_priorities]; /* unready lists by priority */ + Context_list _slack_list { }; + + Context &_idle; + Context *_current { nullptr }; + + void _each_prio_until(auto const &fn) + { + for (unsigned p = Priority::max(); p != Priority::min()-1; p--) + if (fn(p)) + return; + } + + void _consumed(unsigned const q); + void _set_current(Context &context, unsigned const q); + void _account_priotized(Context &, unsigned const r); + void _account_slack(Context &c, unsigned const r); + bool _schedule_priotized(); + bool _schedule_slack(); + + public: + + Scheduler(Context &idle, + unsigned const super_period_length, + unsigned const slack_quota); + + bool need_to_schedule() const { return _state != UP_TO_DATE; } + + void timeout() { + if (_state == UP_TO_DATE) _state = OUT_OF_DATE; } + + /** + * Update state according to the current (absolute) time + */ + void update(time_t time); + + /** + * Set 'context' ready + */ + void ready(Context &context); + + /** + * Set 'context' unready + */ + void unready(Context &context); + + /** + * Current context likes another context to be scheduled now + */ + void yield(); + + /** + * Remove 'context' from scheduler + */ + void remove(Context &context); + + /** + * Insert 'context' into scheduler + */ + void insert(Context &context); + + /** + * Set prioritized quota of 'context' to 'quota' + */ + void quota(Context &context, unsigned const quota); + + Context& current(); + + unsigned current_time_left() const { + return Genode::min(_current_quantum, _super_period_left); } +}; + +#endif /* _CORE__KERNEL__SCHEDULER_H_ */ diff --git a/repos/base-hw/src/core/kernel/signal_receiver.cc b/repos/base-hw/src/core/kernel/signal_receiver.cc index 2e192d3ffe..5c99894103 100644 --- a/repos/base-hw/src/core/kernel/signal_receiver.cc +++ b/repos/base-hw/src/core/kernel/signal_receiver.cc @@ -191,7 +191,7 @@ void Signal_receiver::_listen() return; /* create a signal data-object */ - typedef Genode::Signal_context * Signal_imprint; + using Signal_imprint = Genode::Signal_context *; _deliver.dequeue([&] (Signal_context::Fifo_element &elem) { auto const context = &elem.object(); diff --git a/repos/base-hw/src/core/kernel/signal_receiver.h b/repos/base-hw/src/core/kernel/signal_receiver.h index 2aabe24ef5..f5b2df09f8 100644 --- a/repos/base-hw/src/core/kernel/signal_receiver.h +++ b/repos/base-hw/src/core/kernel/signal_receiver.h @@ -16,8 +16,8 @@ /* Genode includes */ #include -#include +/* core includes */ #include #include @@ -59,7 +59,7 @@ class Kernel::Signal_handler Signal_handler(Signal_handler const &); Signal_handler &operator = (Signal_handler const &); - typedef Genode::Fifo_element Fifo_element; + using Fifo_element = Genode::Fifo_element; Thread &_thread; Fifo_element _handlers_fe { *this }; @@ -119,7 +119,7 @@ class Kernel::Signal_context Signal_context(Signal_context const &); Signal_context &operator = (Signal_context const &); - typedef Genode::Fifo_element Fifo_element; + using Fifo_element = Genode::Fifo_element; Kernel::Object _kernel_object { *this }; Fifo_element _deliver_fe { *this }; @@ -199,7 +199,7 @@ class Kernel::Signal_context * * \retval capability id of the new kernel object */ - static capid_t syscall_create(Genode::Kernel_object &c, + static capid_t syscall_create(Core::Kernel_object &c, Signal_receiver & receiver, addr_t const imprint) { @@ -212,7 +212,7 @@ class Kernel::Signal_context * * \param context pointer to signal context kernel object */ - static void syscall_destroy(Genode::Kernel_object &c) { + static void syscall_destroy(Core::Kernel_object &c) { call(call_id_delete_signal_context(), (Call_arg)&c); } Object &kernel_object() { return _kernel_object; } @@ -226,7 +226,7 @@ class Kernel::Signal_receiver private: - typedef Genode::Signal Signal; + using Signal = Genode::Signal; template class Fifo : public Genode::Fifo { }; @@ -282,7 +282,7 @@ class Kernel::Signal_receiver * * \retval capability id of the new kernel object */ - static capid_t syscall_create(Genode::Kernel_object &r) { + static capid_t syscall_create(Core::Kernel_object &r) { return (capid_t)call(call_id_new_signal_receiver(), (Call_arg)&r); } /** @@ -290,7 +290,7 @@ class Kernel::Signal_receiver * * \param receiver pointer to signal receiver kernel object */ - static void syscall_destroy(Genode::Kernel_object &r) { + static void syscall_destroy(Core::Kernel_object &r) { call(call_id_delete_signal_receiver(), (Call_arg)&r); } Object &kernel_object() { return _kernel_object; } diff --git a/repos/base-hw/src/core/kernel/thread.cc b/repos/base-hw/src/core/kernel/thread.cc index a5f3b37593..b4febf8070 100644 --- a/repos/base-hw/src/core/kernel/thread.cc +++ b/repos/base-hw/src/core/kernel/thread.cc @@ -159,7 +159,7 @@ Tlb_invalidation::Tlb_invalidation(Inter_processor_work_list &global_work_list, } -Thread::Destroy::Destroy(Thread & caller, Genode::Kernel_object & to_delete) +Thread::Destroy::Destroy(Thread & caller, Core::Kernel_object & to_delete) : caller(caller), thread_to_destroy(to_delete) { @@ -169,7 +169,7 @@ Thread::Destroy::Destroy(Thread & caller, Genode::Kernel_object & to_del void -Thread::Destroy::execute() +Thread::Destroy::execute(Cpu &) { thread_to_destroy->_cpu->work_list().remove(&_le); thread_to_destroy.destruct(); @@ -295,16 +295,18 @@ void Thread::_become_inactive(State const s) void Thread::_die() { _become_inactive(DEAD); } -Cpu_job * Thread::helping_sink() { - return &_ipc_node.helping_sink(); } +Cpu_job * Thread::helping_destination() { + return &_ipc_node.helping_destination(); } size_t Thread::_core_to_kernel_quota(size_t const quota) const { using Genode::Cpu_session; - using Genode::sizet_arithm_t; - size_t const ticks = _cpu->timer().us_to_ticks(Kernel::cpu_quota_us); - return Cpu_session::quota_lim_downscale(quota, ticks); + + /* we assert at timer construction that cpu_quota_us in ticks fits size_t */ + size_t const ticks = (size_t) + _cpu->timer().us_to_ticks(Kernel::cpu_quota_us); + return Cpu_session::quota_lim_downscale(quota, ticks); } @@ -400,6 +402,7 @@ bool Thread::_restart() { assert(_state == ACTIVE || _state == AWAITS_RESTART); if (_state != AWAITS_RESTART) { return false; } + _exception_state = NO_EXCEPTION; _become_active(); return true; } @@ -442,8 +445,8 @@ void Thread::_call_yield_thread() void Thread::_call_delete_thread() { - Genode::Kernel_object & to_delete = - *(Genode::Kernel_object*)user_arg_1(); + Core::Kernel_object & to_delete = + *(Core::Kernel_object*)user_arg_1(); /** * Delete a thread immediately if it has no cpu assigned yet, @@ -466,8 +469,8 @@ void Thread::_call_delete_thread() void Thread::_call_delete_pd() { - Genode::Kernel_object & pd = - *(Genode::Kernel_object*)user_arg_1(); + Core::Kernel_object & pd = + *(Core::Kernel_object*)user_arg_1(); if (_cpu->active(pd->mmu_regs)) _cpu->switch_to(_core_pd.mmu_regs); @@ -478,17 +481,17 @@ void Thread::_call_delete_pd() void Thread::_call_await_request_msg() { - if (_ipc_node.can_await_request()) { + if (_ipc_node.ready_to_wait()) { _ipc_alloc_recv_caps((unsigned)user_arg_1()); - _ipc_node.await_request(); - if (_ipc_node.awaits_request()) { + _ipc_node.wait(); + if (_ipc_node.waiting()) { _become_inactive(AWAITS_IPC); } else { user_arg_0(0); } } else { - Genode::raw("IPC await request: bad state"); - user_arg_0(0); + Genode::raw("IPC await request: bad state, will block"); + _become_inactive(DEAD); } } @@ -533,18 +536,18 @@ void Thread::_call_send_request_msg() if (!dst) { Genode::raw(*this, ": cannot send to unknown recipient ", (unsigned)user_arg_1()); - _become_inactive(AWAITS_IPC); + _become_inactive(DEAD); return; } bool const help = Cpu_job::_helping_possible(*dst); oir = oir->find(dst->pd()); - if (!_ipc_node.can_send_request()) { + if (!_ipc_node.ready_to_send()) { Genode::raw("IPC send request: bad state"); } else { _ipc_alloc_recv_caps((unsigned)user_arg_2()); _ipc_capid = oir ? oir->capid() : cap_id_invalid(); - _ipc_node.send_request(dst->_ipc_node, help); + _ipc_node.send(dst->_ipc_node, help); } _state = AWAITS_IPC; @@ -554,7 +557,7 @@ void Thread::_call_send_request_msg() void Thread::_call_send_reply_msg() { - _ipc_node.send_reply(); + _ipc_node.reply(); bool const await_request_msg = user_arg_2(); if (await_request_msg) { _call_await_request_msg(); } else { user_arg_0(0); } @@ -715,9 +718,8 @@ void Thread::_call_new_irq() Genode::Irq_session::Polarity polarity = (Genode::Irq_session::Polarity) (user_arg_3() & 0b11); - _call_new( - (unsigned)user_arg_2(), trigger, polarity, *c, - _cpu_pool.executing_cpu().pic(), _user_irq_pool); + _call_new((unsigned)user_arg_2(), trigger, polarity, *c, + _cpu->pic(), _user_irq_pool); } @@ -790,6 +792,34 @@ void Kernel::Thread::_call_invalidate_tlb() } +void Thread::_call_get_cpu_state() { + Thread &thread = *(Thread*)user_arg_1(); + Cpu_state &cpu_state = *(Cpu_state*)user_arg_2(); + cpu_state = *thread.regs; +} + + +void Thread::_call_set_cpu_state() { + Thread &thread = *(Thread*)user_arg_1(); + Cpu_state &cpu_state = *(Cpu_state*)user_arg_2(); + static_cast(*thread.regs) = cpu_state; +} + + +void Thread::_call_exception_state() { + Thread &thread = *(Thread*)user_arg_1(); + Exception_state &exception_state = *(Exception_state*)user_arg_2(); + exception_state = thread.exception_state(); +} + + +void Thread::_call_single_step() { + Thread &thread = *(Thread*)user_arg_1(); + bool on = *(bool*)user_arg_2(); + Cpu::single_step(*thread.regs, on); +} + + void Thread::_call() { try { @@ -800,6 +830,7 @@ void Thread::_call() case call_id_cache_coherent_region(): _call_cache_coherent_region(); return; case call_id_cache_clean_inv_region(): _call_cache_clean_invalidate_data_region(); return; case call_id_cache_inv_region(): _call_cache_invalidate_data_region(); return; + case call_id_cache_line_size(): _call_cache_line_size(); return; case call_id_stop_thread(): _call_stop_thread(); return; case call_id_restart_thread(): _call_restart_thread(); return; case call_id_yield_thread(): _call_yield_thread(); return; @@ -847,8 +878,8 @@ void Thread::_call() case call_id_thread_pager(): _call_pager(); return; case call_id_invalidate_tlb(): _call_invalidate_tlb(); return; case call_id_new_pd(): - _call_new(*(Hw::Page_table *) user_arg_2(), - *(Genode::Platform_pd *) user_arg_3(), + _call_new(*(Hw::Page_table *) user_arg_2(), + *(Core::Platform_pd *) user_arg_3(), _addr_space_id_alloc); return; case call_id_delete_pd(): _call_delete_pd(); return; @@ -866,6 +897,11 @@ void Thread::_call() case call_id_ack_irq(): _call_ack_irq(); return; case call_id_new_obj(): _call_new_obj(); return; case call_id_delete_obj(): _call_delete_obj(); return; + case call_id_suspend(): _call_suspend(); return; + case call_id_get_cpu_state(): _call_get_cpu_state(); return; + case call_id_set_cpu_state(): _call_set_cpu_state(); return; + case call_id_exception_state(): _call_exception_state(); return; + case call_id_single_step(): _call_single_step(); return; default: Genode::raw(*this, ": unknown kernel call"); _die(); @@ -878,6 +914,7 @@ void Thread::_call() void Thread::_mmu_exception() { _become_inactive(AWAITS_RESTART); + _exception_state = MMU_FAULT; Cpu::mmu_fault(*regs, _fault); _fault.ip = regs->ip; @@ -896,6 +933,25 @@ void Thread::_mmu_exception() } +void Thread::_exception() +{ + _become_inactive(AWAITS_RESTART); + _exception_state = EXCEPTION; + + if (_type != USER) { + Genode::raw(*this, " raised an exception, which should never happen"); + _die(); + } + + if (_pager && _pager->can_submit(1)) { + _pager->submit(1); + } else { + Genode::raw(*this, " could not send signal to pager on exception"); + _die(); + } +} + + Thread::Thread(Board::Address_space_id_allocator &addr_space_id_alloc, Irq::Pool &user_irq_pool, Cpu_pool &cpu_pool, @@ -946,11 +1002,11 @@ Core_main_thread(Board::Address_space_id_allocator &addr_space_id_alloc, Core_object( core_pd, addr_space_id_alloc, user_irq_pool, cpu_pool, core_pd, "core") { - using namespace Genode; + using namespace Core; - Genode::map_local(Platform::core_phys_addr((addr_t)&_utcb_instance), - (addr_t)utcb_main_thread(), - sizeof(Native_utcb) / get_page_size()); + map_local(Platform::core_phys_addr((addr_t)&_utcb_instance), + (addr_t)utcb_main_thread(), + sizeof(Native_utcb) / get_page_size()); _utcb_instance.cap_add(core_capid()); _utcb_instance.cap_add(cap_id_invalid()); diff --git a/repos/base-hw/src/core/kernel/thread.h b/repos/base-hw/src/core/kernel/thread.h index 93e45c3303..5feedebdf8 100644 --- a/repos/base-hw/src/core/kernel/thread.h +++ b/repos/base-hw/src/core/kernel/thread.h @@ -14,12 +14,10 @@ #ifndef _CORE__KERNEL__THREAD_H_ #define _CORE__KERNEL__THREAD_H_ - /* Genode includes */ #include -#include -/* base-hw Core includes */ +/* base-hw core includes */ #include #include #include @@ -61,6 +59,8 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout enum Type { USER, CORE, IDLE }; + enum Exception_state { NO_EXCEPTION, MMU_FAULT, EXCEPTION }; + private: /* @@ -92,7 +92,7 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout ** Inter_processor_work interface ** ************************************/ - void execute() override; + void execute(Cpu &) override; }; /** @@ -101,7 +101,7 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout */ struct Destroy : Inter_processor_work { - using Kthread = Genode::Kernel_object; + using Kthread = Core::Kernel_object; Thread & caller; /* the caller gets blocked till the end */ Kthread & thread_to_destroy; /* thread to be destroyed */ @@ -112,11 +112,40 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout ** Inter_processor_work interface ** ************************************/ - void execute() override; + void execute(Cpu &) override; }; - friend void Tlb_invalidation::execute(); - friend void Destroy::execute(); + /** + * Flush and stop CPU, e.g. before suspending or powering off the CPU + */ + struct Flush_and_stop_cpu : Inter_processor_work + { + Inter_processor_work_list &global_work_list; + unsigned cpus_left; + Hw::Suspend_type suspend; + + Flush_and_stop_cpu(Inter_processor_work_list &global_work_list, + unsigned cpus, Hw::Suspend_type suspend) + : + global_work_list(global_work_list), + cpus_left(cpus), + suspend(suspend) + { + global_work_list.insert(&_le); + } + + ~Flush_and_stop_cpu() { global_work_list.remove(&_le); } + + /************************************ + ** Inter_processor_work interface ** + ************************************/ + + void execute(Cpu &) override; + }; + + friend void Tlb_invalidation::execute(Cpu &); + friend void Destroy::execute(Cpu &); + friend void Flush_and_stop_cpu::execute(Cpu &); protected: @@ -154,9 +183,11 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout bool _paused { false }; bool _cancel_next_await_signal { false }; Type const _type; + Exception_state _exception_state { NO_EXCEPTION }; - Genode::Constructible _tlb_invalidation {}; - Genode::Constructible _destroy {}; + Genode::Constructible _tlb_invalidation {}; + Genode::Constructible _destroy {}; + Genode::Constructible _stop_cpu {}; /** * Notice that another thread yielded the CPU to this thread @@ -205,6 +236,11 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout */ void _mmu_exception(); + /** + * Handle a non-mmu exception + */ + void _exception(); + /** * Handle kernel-call request of the thread */ @@ -242,6 +278,7 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout void _call_cache_coherent_region(); void _call_cache_clean_invalidate_data_region(); void _call_cache_invalidate_data_region(); + void _call_cache_line_size(); void _call_print_char(); void _call_await_signal(); void _call_pending_signal(); @@ -264,22 +301,24 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout void _call_timeout(); void _call_timeout_max_us(); void _call_time(); + void _call_suspend(); + void _call_get_cpu_state(); + void _call_set_cpu_state(); + void _call_exception_state(); + void _call_single_step(); - template - void _call_new(ARGS &&... args) + template + void _call_new(auto &&... args) { - Genode::Kernel_object & kobj = - *(Genode::Kernel_object*)user_arg_1(); + Core::Kernel_object & kobj = *(Core::Kernel_object*)user_arg_1(); kobj.construct(_core_pd, args...); user_arg_0(kobj->core_capid()); } - template void _call_delete() { - Genode::Kernel_object & kobj = - *(Genode::Kernel_object*)user_arg_1(); + Core::Kernel_object & kobj = *(Core::Kernel_object*)user_arg_1(); kobj.destruct(); } @@ -289,7 +328,7 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout public: - Genode::Align_at regs; + Genode::Align_at regs; /** * Constructor @@ -320,7 +359,7 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout char const *const label) : Thread(addr_space_id_alloc, user_irq_pool, cpu_pool, core_pd, - Cpu_priority::min(), 0, label, CORE) + Scheduler::Priority::min(), 0, label, CORE) { } ~Thread(); @@ -356,10 +395,10 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout * * \retval capability id of the new kernel object */ - static capid_t syscall_create(Genode::Kernel_object & t, - unsigned const priority, - size_t const quota, - char const * const label) + static capid_t syscall_create(Core::Kernel_object &t, + unsigned const priority, + size_t const quota, + char const * const label) { return (capid_t)call(call_id_new_thread(), (Call_arg)&t, (Call_arg)priority, (Call_arg)quota, @@ -374,8 +413,8 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout * * \retval capability id of the new kernel object */ - static capid_t syscall_create(Genode::Kernel_object & t, - char const * const label) + static capid_t syscall_create(Core::Kernel_object &t, + char const * const label) { return (capid_t)call(call_id_new_core_thread(), (Call_arg)&t, (Call_arg)label); @@ -386,11 +425,13 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout * * \param thread pointer to thread kernel object */ - static void syscall_destroy(Genode::Kernel_object & t) { + static void syscall_destroy(Core::Kernel_object &t) { call(call_id_delete_thread(), (Call_arg)&t); } + void print(Genode::Output &out) const; + /************** ** Ipc_node ** **************/ @@ -417,9 +458,9 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout ** Cpu_job ** *************/ - void exception(Cpu & cpu) override; - void proceed(Cpu & cpu) override; - Cpu_job * helping_sink() override; + void exception(Cpu & cpu) override; + void proceed(Cpu & cpu) override; + Cpu_job * helping_destination() override; /************* @@ -438,6 +479,7 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout Thread_fault fault() const { return _fault; } Genode::Native_utcb *utcb() { return _utcb; } Type type() const { return _type; } + Exception_state exception_state() const { return _exception_state; } Pd &pd() const { diff --git a/repos/base-hw/src/core/kernel/timer.cc b/repos/base-hw/src/core/kernel/timer.cc index 910e6fafd4..3e3bff6113 100644 --- a/repos/base-hw/src/core/kernel/timer.cc +++ b/repos/base-hw/src/core/kernel/timer.cc @@ -11,7 +11,7 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* Core includes */ +/* core includes */ #include #include #include @@ -122,4 +122,10 @@ Timer::Timer(Cpu & cpu) * period). */ assert(ticks_to_us(_max_value()) > 2 * cpu_quota_us); + + /* + * Kernel::cpu_quota_us is used in ticks for quota calculations + * and must fit into its datatype, which is size_t not time_t + */ + assert(us_to_ticks(cpu_quota_us) < ~0UL); } diff --git a/repos/base-hw/src/core/kernel/timer.h b/repos/base-hw/src/core/kernel/timer.h index 50ed898b11..920847803c 100644 --- a/repos/base-hw/src/core/kernel/timer.h +++ b/repos/base-hw/src/core/kernel/timer.h @@ -110,6 +110,9 @@ class Kernel::Timer unsigned interrupt_id() const; time_t time() const { return _time + _duration(); } + + void init() { _device.init(); } + }; #endif /* _CORE__KERNEL__TIMER_H_ */ diff --git a/repos/base-hw/src/core/kernel/vm.h b/repos/base-hw/src/core/kernel/vm.h index 06a069a743..b742822f7e 100644 --- a/repos/base-hw/src/core/kernel/vm.h +++ b/repos/base-hw/src/core/kernel/vm.h @@ -1,11 +1,12 @@ /* * \brief Kernel backend for virtual machines * \author Martin Stein + * \author Benjamin Lamowski * \date 2013-10-30 */ /* - * Copyright (C) 2013-2017 Genode Labs GmbH + * Copyright (C) 2013-2023 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -14,8 +15,6 @@ #ifndef _CORE__KERNEL__VM_H_ #define _CORE__KERNEL__VM_H_ -namespace Genode { class Vm_state; } - /* core includes */ #include #include @@ -44,7 +43,7 @@ class Kernel::Vm : private Kernel::Object, public Cpu_job private: - using State = Board::Vm_state; + using Vcpu_state = Genode::Vcpu_state; /* * Noncopyable @@ -56,12 +55,22 @@ class Kernel::Vm : private Kernel::Object, public Cpu_job Irq::Pool & _user_irq_pool; Object _kernel_object { *this }; - State & _state; + Vcpu_state & _state; Signal_context & _context; Identity const _id; Scheduler_state _scheduled = INACTIVE; Board::Vcpu_context _vcpu_context; + void _sync_to_vmm(); + void _sync_from_vmm(); + void _pause_vcpu() + { + if (_scheduled != INACTIVE) + Cpu_job::_deactivate_own_share(); + + _scheduled = INACTIVE; + } + public: /** @@ -73,7 +82,7 @@ class Kernel::Vm : private Kernel::Object, public Cpu_job */ Vm(Irq::Pool & user_irq_pool, Cpu & cpu, - Genode::Vm_state & state, + Genode::Vcpu_data & data, Kernel::Signal_context & context, Identity & id); @@ -91,20 +100,20 @@ class Kernel::Vm : private Kernel::Object, public Cpu_job * Create a virtual machine that is stopped initially * * \param dst memory donation for the VM object - * \param state location of the CPU state of the VM + * \param data location of the CPU data of the VM * \param signal_context_id kernel name of the signal context for VM events * \param id VM identity * * \retval cap id when successful, otherwise invalid cap id */ - static capid_t syscall_create(Genode::Kernel_object & vm, - unsigned cpu, - void * const state, - capid_t const signal_context_id, - Identity & id) + static capid_t syscall_create(Core::Kernel_object &vm, + unsigned cpu, + void * const data, + capid_t const signal_context_id, + Identity &id) { return (capid_t)call(call_id_new_vm(), (Call_arg)&vm, (Call_arg)cpu, - (Call_arg)state, (Call_arg)&id, signal_context_id); + (Call_arg)data, (Call_arg)&id, signal_context_id); } /** @@ -114,7 +123,7 @@ class Kernel::Vm : private Kernel::Object, public Cpu_job * * \retval 0 when successful, otherwise !=0 */ - static void syscall_destroy(Genode::Kernel_object & vm) { + static void syscall_destroy(Core::Kernel_object & vm) { call(call_id_delete_vm(), (Call_arg) &vm); } Object &kernel_object() { return _kernel_object; } @@ -125,16 +134,15 @@ class Kernel::Vm : private Kernel::Object, public Cpu_job void run() { + _sync_from_vmm(); if (_scheduled != ACTIVE) Cpu_job::_activate_own_share(); _scheduled = ACTIVE; } void pause() { - if (_scheduled != INACTIVE) - Cpu_job::_deactivate_own_share(); - - _scheduled = INACTIVE; + _pause_vcpu(); + _sync_to_vmm(); } @@ -142,9 +150,9 @@ class Kernel::Vm : private Kernel::Object, public Cpu_job ** Cpu_job ** *************/ - void exception(Cpu & cpu) override; - void proceed(Cpu & cpu) override; - Cpu_job * helping_sink() override { return this; } + void exception(Cpu & cpu) override; + void proceed(Cpu & cpu) override; + Cpu_job * helping_destination() override { return this; } }; #endif /* _CORE__KERNEL__VM_H_ */ diff --git a/repos/base-hw/src/core/kernel/vm_thread_on.cc b/repos/base-hw/src/core/kernel/vm_thread_on.cc index 4bfa7703f9..d2023d83b9 100644 --- a/repos/base-hw/src/core/kernel/vm_thread_on.cc +++ b/repos/base-hw/src/core/kernel/vm_thread_on.cc @@ -26,7 +26,7 @@ void Kernel::Thread::_call_new_vm() } _call_new(_user_irq_pool, _cpu_pool.cpu((unsigned)user_arg_2()), - *(Board::Vm_state*)user_arg_3(), + *(Board::Vcpu_data*)user_arg_3(), *context, *(Vm::Identity*)user_arg_4()); } diff --git a/repos/base-hw/src/core/kernel_log.cc b/repos/base-hw/src/core/kernel_log.cc index ba8a59c91e..51c1ca28df 100644 --- a/repos/base-hw/src/core/kernel_log.cc +++ b/repos/base-hw/src/core/kernel_log.cc @@ -12,7 +12,7 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* base-hw Core includes */ +/* core includes */ #include #include diff --git a/repos/base-hw/src/core/map_local.h b/repos/base-hw/src/core/map_local.h index bfd701c8cd..c48f879d1d 100644 --- a/repos/base-hw/src/core/map_local.h +++ b/repos/base-hw/src/core/map_local.h @@ -14,11 +14,13 @@ #ifndef _CORE__MAP_LOCAL_H_ #define _CORE__MAP_LOCAL_H_ -#include +/* core includes */ +#include +#include -namespace Genode { +namespace Core { - using Hw::Page_flags; + using Genode::Page_flags; /** * Map physical pages to core-local virtual address range @@ -31,7 +33,7 @@ namespace Genode { * \return true on success */ bool map_local(addr_t from_phys, addr_t to_virt, size_t num_pages, - Page_flags flags = Hw::PAGE_FLAGS_KERN_DATA); + Page_flags flags = Genode::PAGE_FLAGS_KERN_DATA); /** * Unmap pages from core's address space diff --git a/repos/base-hw/src/core/native_pd_component.cc b/repos/base-hw/src/core/native_pd_component.cc index 710c28d792..658209e340 100644 --- a/repos/base-hw/src/core/native_pd_component.cc +++ b/repos/base-hw/src/core/native_pd_component.cc @@ -14,7 +14,7 @@ #include #include -using namespace Genode; +using namespace Core; void Native_pd_component::upgrade_cap_slab() @@ -23,6 +23,12 @@ void Native_pd_component::upgrade_cap_slab() } +size_t Native_pd_component::avail_cap_slab() +{ + return _pd_session._pd->avail_slab(); +} + + Native_pd_component::Native_pd_component(Pd_session_component &pd, char const *) : _pd_session(pd) diff --git a/repos/base-hw/src/core/native_pd_component.h b/repos/base-hw/src/core/native_pd_component.h index 36589cd75a..b5cca69601 100644 --- a/repos/base-hw/src/core/native_pd_component.h +++ b/repos/base-hw/src/core/native_pd_component.h @@ -18,17 +18,17 @@ /* Genode includes */ #include -/* core-local includes */ +/* core includes */ #include -namespace Genode { +namespace Core { class Pd_session_component; class Native_pd_component; } -class Genode::Native_pd_component : public Rpc_object +class Core::Native_pd_component : public Rpc_object { private: @@ -41,6 +41,7 @@ class Genode::Native_pd_component : public Rpc_object ~Native_pd_component(); void upgrade_cap_slab() override; + size_t avail_cap_slab() override; }; #endif /* _CORE__INCLUDE__NATIVE_PD_COMPONENT_H_ */ diff --git a/repos/base-hw/src/core/object.h b/repos/base-hw/src/core/object.h index 4267b4b7a0..c972e265c5 100644 --- a/repos/base-hw/src/core/object.h +++ b/repos/base-hw/src/core/object.h @@ -14,29 +14,26 @@ #ifndef _CORE__OBJECT_H_ #define _CORE__OBJECT_H_ -/* Genode includes */ -#include - /* base-internal includes */ #include +/* core includes */ +#include + /* base-hw includes */ #include #include -namespace Genode { - - /** - * Represents a kernel object in core - * - * \param T type of the kernel object - */ - template class Kernel_object; -} +namespace Core { template class Kernel_object; } +/** + * Represents a kernel object in core + * + * \param T type of the kernel object + */ template -class Genode::Kernel_object : public Genode::Constructible> +class Core::Kernel_object : public Constructible> { protected: @@ -52,8 +49,7 @@ class Genode::Kernel_object : public Genode::Constructible - Kernel_object(Called_from_core, ARGS &&... args) + Kernel_object(Called_from_core, auto &&... args) : _cap(Capability_space::import(T::syscall_create(*this, args...))) { } @@ -61,17 +57,16 @@ class Genode::Kernel_object : public Genode::Constructible - Kernel_object(Called_from_kernel, ARGS &&... args) + Kernel_object(Called_from_kernel, auto &&... args) : _cap(Capability_space::import(Kernel::cap_id_invalid())) { - Genode::Constructible>::construct(args...); + Constructible>::construct(args...); } ~Kernel_object() { - if (Genode::Constructible>::constructed()) + if (Constructible>::constructed()) T::syscall_destroy(*this); } @@ -80,10 +75,9 @@ class Genode::Kernel_object : public Genode::Constructible - bool create(ARGS &&... args) + bool create(auto &&... args) { - if (Genode::Constructible>::constructed()) + if (Constructible>::constructed()) return false; _cap = Capability_space::import(T::syscall_create(*this, args...)); diff --git a/repos/base-hw/src/core/pager.cc b/repos/base-hw/src/core/pager.cc index e5cc671c91..4fcd3d651e 100644 --- a/repos/base-hw/src/core/pager.cc +++ b/repos/base-hw/src/core/pager.cc @@ -11,9 +11,6 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* Genode includes */ -#include - /* core includes*/ #include #include @@ -23,7 +20,7 @@ /* base-internal includes */ #include -using namespace Genode; +using namespace Core; /*************** @@ -64,23 +61,14 @@ void Pager_object::start_paging(Kernel_object & receive } -void Pager_object::exception_handler(Signal_context_capability) { } - - -void Pager_object::unresolved_page_fault_occurred() -{ - Platform_thread * const pt = (Platform_thread *)badge(); - if (pt && pt->pd()) - warning("page fault, pager_object: pd='", pt->pd()->label(), - "' thread='", pt->label(), "' ", pt->fault_info()); -} +void Pager_object::unresolved_page_fault_occurred() { } void Pager_object::print(Output &out) const { Platform_thread * const pt = (Platform_thread *)badge(); - if (pt && pt->pd()) - Genode::print(out, "pager_object: pd='", pt->pd()->label(), + if (pt) + Genode::print(out, "pager_object: pd='", pt->pd().label(), "' thread='", pt->label(), "'"); } diff --git a/repos/base-hw/src/core/pager.h b/repos/base-hw/src/core/pager.h index 3387ae1f07..29f650e187 100644 --- a/repos/base-hw/src/core/pager.h +++ b/repos/base-hw/src/core/pager.h @@ -21,14 +21,14 @@ #include #include -/* core-local includes */ +/* core includes */ #include #include #include #include #include -namespace Genode { +namespace Core { /** * Interface used by generic region_map code @@ -50,11 +50,13 @@ namespace Genode { */ class Pager_entrypoint; + using Pager_capability = Capability; + enum { PAGER_EP_STACK_SIZE = sizeof(addr_t) * 2048 }; } -class Genode::Ipc_pager +class Core::Ipc_pager { protected: @@ -91,8 +93,8 @@ class Genode::Ipc_pager }; -class Genode::Pager_object : private Object_pool::Entry, - private Genode::Kernel_object +class Core::Pager_object : private Object_pool::Entry, + private Kernel_object { friend class Pager_entrypoint; friend class Object_pool; @@ -103,6 +105,12 @@ class Genode::Pager_object : private Object_pool::Entry, Cpu_session_capability _cpu_session_cap; Thread_capability _thread_cap; + /** + * User-level signal handler registered for this pager object via + * 'Cpu_session::exception_handler()'. + */ + Signal_context_capability _exception_sigh { }; + public: /** @@ -126,9 +134,24 @@ class Genode::Pager_object : private Object_pool::Entry, void wake_up(); /** - * Unnecessary as base-hw doesn't use exception handlers + * Assign user-level exception handler for the pager object */ - void exception_handler(Signal_context_capability); + void exception_handler(Signal_context_capability sigh) + { + _exception_sigh = sigh; + } + + /** + * Notify exception handler about the occurrence of an exception + */ + bool submit_exception_signal() + { + if (!_exception_sigh.valid()) return false; + + Signal_transmitter transmitter(_exception_sigh); + transmitter.submit(); + return true; + } /** * Install information that is necessary to handle page faults @@ -149,6 +172,8 @@ class Genode::Pager_object : private Object_pool::Entry, ** Pure virtual ** ******************/ + enum class Pager_result { STOP, CONTINUE }; + /** * Request a mapping that resolves a fault directly * @@ -157,7 +182,7 @@ class Genode::Pager_object : private Object_pool::Entry, * \retval 0 succeeded * \retval !=0 fault can't be received directly */ - virtual int pager(Ipc_pager & p) = 0; + virtual Pager_result pager(Ipc_pager & p) = 0; /*************** @@ -171,9 +196,9 @@ class Genode::Pager_object : private Object_pool::Entry, }; -class Genode::Pager_entrypoint : public Object_pool, - public Thread, - private Ipc_pager +class Core::Pager_entrypoint : public Object_pool, + public Thread, + private Ipc_pager { private: diff --git a/repos/base-hw/src/core/platform.cc b/repos/base-hw/src/core/platform.cc index 66d1146a89..4df49e25f3 100644 --- a/repos/base-hw/src/core/platform.cc +++ b/repos/base-hw/src/core/platform.cc @@ -13,18 +13,18 @@ */ -/* base Core includes */ +/* core includes */ #include #include -/* base-hw Core includes */ +/* base-hw core includes */ #include #include #include #include /* base-hw internal includes */ -#include +#include #include #include @@ -34,10 +34,9 @@ #include /* base includes */ -#include #include -using namespace Genode; +using namespace Core; /************** @@ -155,15 +154,15 @@ void Platform::_init_platform_info() return; } - Genode::Xml_generator xml(reinterpret_cast(virt_addr), - rom_size, rom_name, [&] () + Xml_generator xml(reinterpret_cast(virt_addr), rom_size, rom_name, [&] { - xml.node("kernel", [&] () { + xml.node("kernel", [&] { xml.attribute("name", "hw"); xml.attribute("acpi", true); + xml.attribute("msi", true); }); _init_additional_platform_info(xml); - xml.node("affinity-space", [&] () { + xml.node("affinity-space", [&] { xml.attribute("width", affinity_space().width()); xml.attribute("height", affinity_space().height()); }); @@ -174,8 +173,7 @@ void Platform::_init_platform_info() return; } - _rom_fs.insert( - new (core_mem_alloc()) Rom_module(phys_addr, rom_size, rom_name)); + new (core_mem_alloc()) Rom_module(_rom_fs, rom_name, phys_addr, rom_size); /* keep phys allocation but let guard revert virt allocation */ guard.phys_ptr = nullptr; @@ -238,8 +236,8 @@ Platform::Platform() map_local(phys_addr, (addr_t)ptr, pages); memset(ptr, 0, log_size); - _rom_fs.insert(new (core_mem_alloc()) - Rom_module(phys_addr, log_size, "core_log")); + new (core_mem_alloc()) + Rom_module(_rom_fs, "core_log", phys_addr, log_size); init_core_log(Core_log_range { (addr_t)ptr, log_size } ); }, @@ -291,8 +289,6 @@ Platform::Platform() Idle_thread_trace_source( Trace::sources(), Affinity::Location(cpu_idx, 0)); } - - log(_rom_fs); } diff --git a/repos/base-hw/src/core/platform.h b/repos/base-hw/src/core/platform.h index 44f72754f9..de24fa5150 100644 --- a/repos/base-hw/src/core/platform.h +++ b/repos/base-hw/src/core/platform.h @@ -30,20 +30,20 @@ #include #include -/* base-hw Core includes */ +/* base-hw core includes */ #include #include #include #include #include -namespace Genode { +namespace Core { class Address_space; class Platform; }; -class Genode::Platform : public Genode::Platform_generic +class Core::Platform : public Platform_generic { private: @@ -79,7 +79,7 @@ class Genode::Platform : public Genode::Platform_generic /** * Add additional platform-specific information. */ - void _init_additional_platform_info(Genode::Xml_generator &); + void _init_additional_platform_info(Xml_generator &); void _init_rom_modules(); @@ -97,18 +97,22 @@ class Genode::Platform : public Genode::Platform_generic static long irq(long const user_irq); /** - * Get MSI-related parameters from device PCI config space + * Allocate MSI exception vector entry * - * \param mmconf PCI config space address of device - * \param address MSI address register value to use - * \param data MSI data register value to use - * \param irq_number IRQ to use + * \param address MSI address register value to use + * \param data MSI data register value to use * - * \return true if the device is MSI-capable, false if not + * \return true if the platform is MSI-capable, false if not */ - static bool get_msi_params(const addr_t mmconf, - addr_t &address, addr_t &data, - unsigned &irq_number); + static bool alloc_msi_vector(addr_t &address, addr_t &data); + + /** + * Allocate MSI exception vector entry + * + * \param address MSI address register value to free + * \param data MSI data register value to free + */ + static void free_msi_vector(addr_t address, addr_t data); static addr_t core_phys_addr(addr_t virt); @@ -146,6 +150,11 @@ class Genode::Platform : public Genode::Platform_generic size_t max_caps() const override { return Kernel::Pd::max_cap_ids; } static addr_t core_main_thread_phys_utcb(); + + static void apply_with_boot_info(auto const &fn) + { + fn(_boot_info()); + } }; #endif /* _CORE__PLATFORM_H_ */ diff --git a/repos/base-hw/src/core/platform_pd.cc b/repos/base-hw/src/core/platform_pd.cc index 3d258c1d3d..b96e1ee8b2 100644 --- a/repos/base-hw/src/core/platform_pd.cc +++ b/repos/base-hw/src/core/platform_pd.cc @@ -21,7 +21,7 @@ #include #include -using namespace Genode; +using namespace Core; using Hw::Page_table; @@ -144,9 +144,8 @@ void Cap_space::upgrade_slab(Allocator &alloc) [&] (void *ptr) { _slab.insert_sb(ptr); }, - [&] (Allocator::Alloc_error) { - /* XXX distinguish error conditions */ - throw Out_of_ram(); + [&] (Allocator::Alloc_error error) { + Allocator::throw_alloc_error(error); }); } @@ -155,16 +154,6 @@ void Cap_space::upgrade_slab(Allocator &alloc) ** Platform_pd implementation ** ********************************/ -bool Platform_pd::bind_thread(Platform_thread &t) -{ - /* is this the first and therefore main thread in this PD? */ - bool main_thread = !_thread_associated; - _thread_associated = true; - t.join_pd(this, main_thread, Address_space::weak_ptr()); - return true; -} - - void Platform_pd::assign_parent(Native_capability parent) { if (!_parent.valid() && parent.valid()) diff --git a/repos/base-hw/src/core/platform_pd.h b/repos/base-hw/src/core/platform_pd.h index db3383713e..c40187a4bc 100644 --- a/repos/base-hw/src/core/platform_pd.h +++ b/repos/base-hw/src/core/platform_pd.h @@ -15,7 +15,7 @@ #ifndef _CORE__PLATFORM_PD_H_ #define _CORE__PLATFORM_PD_H_ -/* base-hw Core includes */ +/* core includes */ #include #include #include @@ -29,7 +29,7 @@ namespace Hw { using namespace Kernel; - using namespace Genode; + using namespace Core; /** * Memory virtualization interface of a protection domain @@ -38,19 +38,19 @@ namespace Hw { } -namespace Genode { +namespace Core { class Platform_thread; /* forward declaration */ class Cap_space; /** - * Platform specific part of a Genode protection domain + * Platform specific part of a protection domain */ class Platform_pd; /** - * Platform specific part of Core's protection domain + * Platform specific part of core's protection domain */ class Core_platform_pd; @@ -58,7 +58,7 @@ namespace Genode { } -class Hw::Address_space : public Genode::Address_space +class Hw::Address_space : public Core::Address_space { private: @@ -68,19 +68,19 @@ class Hw::Address_space : public Genode::Address_space Address_space(Address_space const &); Address_space &operator = (Address_space const &); - friend class Genode::Platform; - friend class Genode::Mapped_mem_allocator; + friend class Core::Platform; + friend class Core::Mapped_mem_allocator; using Table = Hw::Page_table; using Array = Table::Allocator::Array; - Genode::Mutex _mutex { }; /* table lock */ + Mutex _mutex { }; /* table lock */ Table &_tt; /* table virt addr */ - Genode::addr_t _tt_phys; /* table phys addr */ + addr_t _tt_phys; /* table phys addr */ Array *_tt_array = nullptr; Table::Allocator &_tt_alloc; /* table allocator */ - static inline Genode::Core_mem_allocator &_cma(); + static inline Core_mem_allocator &_cma(); static inline void *_table_alloc(); @@ -119,11 +119,11 @@ class Hw::Address_space : public Genode::Address_space * \param size size of memory region * \param flags translation table flags (e.g. caching attributes) */ - bool insert_translation(Genode::addr_t virt, Genode::addr_t phys, - Genode::size_t size, Genode::Page_flags flags); + bool insert_translation(addr_t virt, addr_t phys, + size_t size, Page_flags flags); + + bool lookup_rw_translation(addr_t const virt, addr_t & phys); - bool lookup_rw_translation(Genode::addr_t const virt, - Genode::addr_t & phys); /***************************** ** Address-space interface ** @@ -138,13 +138,13 @@ class Hw::Address_space : public Genode::Address_space ** Accessors ** ***************/ - Kernel::Pd & kernel_pd() { return *_kobj; } - Hw::Page_table & translation_table() { return _tt; } - Genode::addr_t translation_table_phys() { return _tt_phys; } + Kernel::Pd &kernel_pd() { return *_kobj; } + Hw::Page_table &translation_table() { return _tt; } + addr_t translation_table_phys() { return _tt_phys; } }; -class Genode::Cap_space +class Core::Cap_space { private: @@ -163,11 +163,11 @@ class Genode::Cap_space Cap_slab & capability_slab() { return _slab; } void upgrade_slab(Allocator &alloc); + size_t avail_slab() { return _slab.avail_entries(); } }; -class Genode::Platform_pd : public Hw::Address_space, - private Cap_space +class Core::Platform_pd : public Hw::Address_space, private Cap_space { private: @@ -195,6 +195,8 @@ class Genode::Platform_pd : public Hw::Address_space, public: + bool has_any_thread = false; + /** * Constructor used for objects other than the Core PD * @@ -209,6 +211,7 @@ class Genode::Platform_pd : public Hw::Address_space, using Cap_space::capability_slab; using Cap_space::upgrade_slab; + using Cap_space::avail_slab; /** * Bind thread to protection domain @@ -230,7 +233,7 @@ class Genode::Platform_pd : public Hw::Address_space, }; -struct Genode::Core_platform_pd : Genode::Platform_pd +struct Core::Core_platform_pd : Platform_pd { Core_platform_pd(Board::Address_space_id_allocator &addr_space_id_alloc); }; diff --git a/repos/base-hw/src/core/platform_thread.cc b/repos/base-hw/src/core/platform_thread.cc index fac3d8551c..7ae23acd04 100644 --- a/repos/base-hw/src/core/platform_thread.cc +++ b/repos/base-hw/src/core/platform_thread.cc @@ -27,7 +27,7 @@ #include #include -using namespace Genode; +using namespace Core; void Platform_thread::_init() { } @@ -62,7 +62,7 @@ void Platform_thread::quota(size_t const quota) Platform_thread::Platform_thread(Label const &label, Native_utcb &utcb) : _label(label), - _pd(&_kernel_main_get_core_platform_pd()), + _pd(_kernel_main_get_core_platform_pd()), _pager(nullptr), _utcb_core_addr(&utcb), _utcb_pd_addr(&utcb), @@ -86,19 +86,20 @@ Platform_thread::Platform_thread(Label const &label, Native_utcb &utcb) } -Platform_thread::Platform_thread(size_t const quota, +Platform_thread::Platform_thread(Platform_pd &pd, + size_t const quota, Label const &label, unsigned const virt_prio, Affinity::Location const location, addr_t const utcb) : _label(label), - _pd(nullptr), + _pd(pd), _pager(nullptr), _utcb_pd_addr((Native_utcb *)utcb), _priority(_scale_priority(virt_prio)), _quota((unsigned)quota), - _main_thread(false), + _main_thread(!pd.has_any_thread), _location(location), _kobj(_kobj.CALLED_FROM_CORE, _priority, _quota, _label.string()) { @@ -108,23 +109,17 @@ Platform_thread::Platform_thread(size_t const quota, error("failed to allocate UTCB"); throw Out_of_ram(); } - _utcb_core_addr = (Native_utcb *)core_env().rm_session()->attach(_utcb); -} + Region_map::Attr attr { }; + attr.writeable = true; + core_env().rm_session()->attach(_utcb, attr).with_result( + [&] (Region_map::Range range) { + _utcb_core_addr = (Native_utcb *)range.start; }, + [&] (Region_map::Attach_error) { + error("failed to attach UTCB of new thread within core"); }); -void Platform_thread::join_pd(Platform_pd * pd, bool const main_thread, - Weak_ptr address_space) -{ - /* check if thread is already in another protection domain */ - if (_pd && _pd != pd) { - error("thread already in another protection domain"); - return; - } - - /* join protection domain */ - _pd = pd; - _main_thread = main_thread; - _address_space = address_space; + _address_space = pd.weak_ptr(); + pd.has_any_thread = true; } @@ -137,7 +132,7 @@ void Platform_thread::affinity(Affinity::Location const &) Affinity::Location Platform_thread::affinity() const { return _location; } -int Platform_thread::start(void * const ip, void * const sp) +void Platform_thread::start(void * const ip, void * const sp) { /* attach UTCB in case of a main thread */ if (_main_thread) { @@ -161,7 +156,8 @@ int Platform_thread::start(void * const ip, void * const sp) } return 0; }; - if (core_env().entrypoint().apply(_utcb, lambda)) return -1; + if (core_env().entrypoint().apply(_utcb, lambda)) + return; } /* initialize thread registers */ @@ -169,11 +165,6 @@ int Platform_thread::start(void * const ip, void * const sp) _kobj->regs->sp = reinterpret_cast(sp); /* start executing new thread */ - if (!_pd) { - error("no protection domain associated!"); - return -1; - } - unsigned const cpu = _location.xpos(); Native_utcb &utcb = *Thread::myself()->utcb(); @@ -182,11 +173,10 @@ int Platform_thread::start(void * const ip, void * const sp) utcb.cap_cnt(0); utcb.cap_add(Capability_space::capid(_kobj.cap())); if (_main_thread) { - utcb.cap_add(Capability_space::capid(_pd->parent())); + utcb.cap_add(Capability_space::capid(_pd.parent())); utcb.cap_add(Capability_space::capid(_utcb)); } - Kernel::start_thread(*_kobj, cpu, _pd->kernel_pd(), *_utcb_core_addr); - return 0; + Kernel::start_thread(*_kobj, cpu, _pd.kernel_pd(), *_utcb_core_addr); } @@ -199,7 +189,7 @@ void Platform_thread::pager(Pager_object &pager) } -Genode::Pager_object &Platform_thread::pager() +Core::Pager_object &Platform_thread::pager() { if (_pager) return *_pager; @@ -210,15 +200,30 @@ Genode::Pager_object &Platform_thread::pager() Thread_state Platform_thread::state() { - Thread_state bstate(*_kobj->regs); - return Thread_state(bstate); + Cpu_state cpu { }; + Kernel::get_cpu_state(*_kobj, cpu); + + auto state = [&] () -> Thread_state::State + { + using Exception_state = Kernel::Thread::Exception_state; + switch (exception_state()) { + case Exception_state::NO_EXCEPTION: return Thread_state::State::VALID; + case Exception_state::MMU_FAULT: return Thread_state::State::PAGE_FAULT; + case Exception_state::EXCEPTION: return Thread_state::State::EXCEPTION; + } + return Thread_state::State::UNAVAILABLE; + }; + + return { + .state = state(), + .cpu = cpu + }; } void Platform_thread::state(Thread_state thread_state) { - Cpu_state * cstate = static_cast(&*_kobj->regs); - *cstate = static_cast(thread_state); + Kernel::set_cpu_state(*_kobj, thread_state.cpu); } diff --git a/repos/base-hw/src/core/platform_thread.h b/repos/base-hw/src/core/platform_thread.h index e7e5b5e259..4c386eb1ef 100644 --- a/repos/base-hw/src/core/platform_thread.h +++ b/repos/base-hw/src/core/platform_thread.h @@ -31,17 +31,19 @@ #include #include -namespace Genode { +namespace Core { class Pager_object; - class Thread_state; class Rm_client; class Platform_thread; class Platform_pd; } -class Genode::Platform_thread : Noncopyable +namespace Genode { class Thread_state; } + + +class Core::Platform_thread : Noncopyable { private: @@ -51,10 +53,10 @@ class Genode::Platform_thread : Noncopyable Platform_thread(Platform_thread const &); Platform_thread &operator = (Platform_thread const &); - typedef String<32> Label; + using Label = String<32>; Label const _label; - Platform_pd * _pd; + Platform_pd &_pd; Weak_ptr _address_space { }; Pager_object * _pager; Native_utcb * _utcb_core_addr { }; /* UTCB addr in core */ @@ -89,8 +91,8 @@ class Genode::Platform_thread : Noncopyable unsigned _scale_priority(unsigned virt_prio) { - return Cpu_session::scale_priority(Kernel::Cpu_priority::max(), - virt_prio); + static constexpr unsigned p = Kernel::Scheduler::Priority::max(); + return Cpu_session::scale_priority(p, virt_prio); } Platform_pd &_kernel_main_get_core_platform_pd(); @@ -113,7 +115,7 @@ class Genode::Platform_thread : Noncopyable * \param virt_prio unscaled processor-scheduling priority * \param utcb core local pointer to userland stack */ - Platform_thread(size_t const quota, Label const &label, + Platform_thread(Platform_pd &, size_t const quota, Label const &label, unsigned const virt_prio, Affinity::Location, addr_t const utcb); @@ -122,31 +124,39 @@ class Genode::Platform_thread : Noncopyable */ ~Platform_thread(); + /** + * Return true if thread creation succeeded + */ + bool valid() const { return true; } + + /** + * Return information about current exception state + * + * This syscall wrapper is located here and not in + * 'core_interface.h' because the 'Thread::Exception_state' + * type is not known there. + */ + Kernel::Thread::Exception_state exception_state() + { + Kernel::Thread::Exception_state exception_state; + using namespace Kernel; + call(call_id_exception_state(), (Call_arg)&*_kobj, + (Call_arg)&exception_state); + return exception_state; + } + /** * Return information about current fault */ Kernel::Thread_fault fault_info() { return _kobj->fault(); } - /** - * Join a protection domain - * - * \param pd platform pd object pointer - * \param main_thread wether thread is the first in protection domain - * \param address_space corresponding Genode address space - * - * This function has no effect when called more twice for a - * given thread. - */ - void join_pd(Platform_pd *const pd, bool const main_thread, - Weak_ptr address_space); - /** * Run this thread * * \param ip initial instruction pointer * \param sp initial stack pointer */ - int start(void * const ip, void * const sp); + void start(void *ip, void *sp); void restart(); @@ -158,12 +168,19 @@ class Genode::Platform_thread : Noncopyable /** * Enable/disable single stepping */ - void single_step(bool) { } + void single_step(bool on) { Kernel::single_step(*_kobj, on); } /** * Resume this thread */ - void resume() { Kernel::resume_thread(*_kobj); } + void resume() + { + if (exception_state() != + Kernel::Thread::Exception_state::NO_EXCEPTION) + restart(); + + Kernel::resume_thread(*_kobj); + } /** * Set CPU quota of the thread to 'quota' @@ -207,7 +224,7 @@ class Genode::Platform_thread : Noncopyable */ Trace::Execution_time execution_time() const { - Genode::uint64_t execution_time = + uint64_t execution_time = const_cast(this)->_kobj->execution_time(); return { execution_time, 0, _quota, _priority }; } @@ -222,7 +239,7 @@ class Genode::Platform_thread : Noncopyable Pager_object &pager(); - Platform_pd * pd() const { return _pd; } + Platform_pd &pd() const { return _pd; } Ram_dataspace_capability utcb() const { return _utcb; } }; diff --git a/repos/base-hw/src/core/ram_dataspace_support.cc b/repos/base-hw/src/core/ram_dataspace_support.cc index 74e86ca880..9b245a43a2 100644 --- a/repos/base-hw/src/core/ram_dataspace_support.cc +++ b/repos/base-hw/src/core/ram_dataspace_support.cc @@ -12,15 +12,13 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* Genode includes */ -#include - /* core includes */ #include #include #include +#include -using namespace Genode; +using namespace Core; void Ram_dataspace_factory::_export_ram_ds(Dataspace_component &) { } @@ -54,19 +52,35 @@ void Ram_dataspace_factory::_clear_ds (Dataspace_component &ds) if (!guard.virt_ptr) return; - /* map the dataspace's physical pages to corresponding virtual addresses */ - size_t num_pages = page_rounded_size >> get_page_size_log2(); - if (!map_local(ds.phys_addr(), (addr_t)guard.virt_ptr, num_pages)) { - error("core-local memory mapping failed"); - return; + /* + * Map and clear dataspaces in chucks of 128MiB max to prevent large + * mappings from filling up core's page table. + */ + static size_t constexpr max_chunk_size = 128 * 1024 * 1024; + + size_t size_remaining = page_rounded_size; + addr_t chunk_phys_addr = ds.phys_addr(); + + while (size_remaining) { + size_t chunk_size = min(size_remaining, max_chunk_size); + size_t num_pages = chunk_size >> get_page_size_log2(); + + /* map the dataspace's physical pages to corresponding virtual addresses */ + if (!map_local(chunk_phys_addr, (addr_t)guard.virt_ptr, num_pages)) { + error("core-local memory mapping failed"); + return; + } + + /* dependent on the architecture, cache maintainance might be necessary */ + Cpu::clear_memory_region((addr_t)guard.virt_ptr, chunk_size, + ds.cacheability() != CACHED); + + /* unmap dataspace from core */ + if (!unmap_local((addr_t)guard.virt_ptr, num_pages)) + error("could not unmap core-local address range at ", guard.virt_ptr); + + size_remaining -= chunk_size; + chunk_phys_addr += chunk_size; } - - /* dependent on the architecture, cache maintainance might be necessary */ - Cpu::clear_memory_region((addr_t)guard.virt_ptr, page_rounded_size, - ds.cacheability() != CACHED); - - /* unmap dataspace from core */ - if (!unmap_local((addr_t)guard.virt_ptr, num_pages)) - error("could not unmap core-local address range at ", guard.virt_ptr); } diff --git a/repos/base-hw/src/core/region_map_support.cc b/repos/base-hw/src/core/region_map_support.cc index a90926a355..4f7f4df79d 100644 --- a/repos/base-hw/src/core/region_map_support.cc +++ b/repos/base-hw/src/core/region_map_support.cc @@ -12,18 +12,14 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* base-hw Core includes */ +/* base-hw core includes */ #include #include #include -using namespace Genode; +using namespace Core; -/********************** - ** Pager_entrypoint ** - **********************/ - void Pager_entrypoint::entry() { Untyped_capability cap; @@ -43,14 +39,25 @@ void Pager_entrypoint::entry() /* fetch fault data */ Platform_thread * const pt = (Platform_thread *)po->badge(); if (!pt) { - Genode::warning("failed to get platform thread of faulter"); + warning("failed to get platform thread of faulter"); + continue; + } + + if (pt->exception_state() == + Kernel::Thread::Exception_state::EXCEPTION) { + if (!po->submit_exception_signal()) + warning("unresolvable exception: " + "pd='", pt->pd().label(), "', " + "thread='", pt->label(), "', " + "ip=", Hex(pt->state().cpu.ip)); continue; } _fault = pt->fault_info(); /* try to resolve fault directly via local region managers */ - if (po->pager(*this)) continue; + if (po->pager(*this) == Pager_object::Pager_result::STOP) + continue; /* apply mapping that was determined by the local region managers */ { @@ -59,13 +66,19 @@ void Pager_entrypoint::entry() Hw::Address_space * as = static_cast(&*locked_ptr); + Cache cacheable = Genode::CACHED; + if (!_mapping.cached) + cacheable = Genode::UNCACHED; + if (_mapping.write_combined) + cacheable = Genode::WRITE_COMBINED; + Hw::Page_flags const flags { .writeable = _mapping.writeable ? Hw::RW : Hw::RO, .executable = _mapping.executable ? Hw::EXEC : Hw::NO_EXEC, .privileged = Hw::USER, .global = Hw::NO_GLOBAL, .type = _mapping.io_mem ? Hw::DEVICE : Hw::RAM, - .cacheable = _mapping.cached ? Genode::CACHED : Genode::UNCACHED + .cacheable = cacheable }; as->insert_translation(_mapping.dst_addr, _mapping.src_addr, diff --git a/repos/base-hw/src/core/rpc_cap_factory.h b/repos/base-hw/src/core/rpc_cap_factory.h index d8cfb3839c..078ecfc6a1 100644 --- a/repos/base-hw/src/core/rpc_cap_factory.h +++ b/repos/base-hw/src/core/rpc_cap_factory.h @@ -20,27 +20,25 @@ #include #include #include -#include -/* core-local includes */ +/* core includes */ #include #include /* base-internal includes */ #include -namespace Genode { class Rpc_cap_factory; } +namespace Core { class Rpc_cap_factory; } -class Genode::Rpc_cap_factory +class Core::Rpc_cap_factory { private: /** * Kernel object placeholder held in a list */ - struct Kobject - : List::Element + struct Kobject : List::Element { using O = Kernel::Core_object_identity; diff --git a/repos/base-hw/src/core/signal_broker.h b/repos/base-hw/src/core/signal_broker.h index 29460fc762..673a1ada01 100644 --- a/repos/base-hw/src/core/signal_broker.h +++ b/repos/base-hw/src/core/signal_broker.h @@ -17,13 +17,13 @@ /* Genode includes */ #include -/* core-local includes */ +/* core includes */ #include -namespace Genode { class Signal_broker; } +namespace Core { class Signal_broker; } -class Genode::Signal_broker +class Core::Signal_broker { private: diff --git a/repos/base-hw/src/core/signal_source_component.h b/repos/base-hw/src/core/signal_source_component.h index c5d49a9e2a..82186608f3 100644 --- a/repos/base-hw/src/core/signal_source_component.h +++ b/repos/base-hw/src/core/signal_source_component.h @@ -17,23 +17,23 @@ /* Genode includes */ #include -/* core-local includes */ +/* core includes */ #include #include #include -namespace Genode { +namespace Core { class Signal_context_component; class Signal_source_component; - typedef Object_pool Signal_context_pool; - typedef Object_pool Signal_source_pool; + using Signal_context_pool = Object_pool; + using Signal_source_pool = Object_pool; } -struct Genode::Signal_context_component : private Kernel_object, - public Signal_context_pool::Entry +struct Core::Signal_context_component : private Kernel_object, + public Signal_context_pool::Entry { friend class Object_pool; @@ -46,8 +46,8 @@ struct Genode::Signal_context_component : private Kernel_object, - public Signal_source_pool::Entry +struct Core::Signal_source_component : private Kernel_object, + public Signal_source_pool::Entry { friend class Object_pool; friend class Signal_context_component; @@ -67,8 +67,8 @@ struct Genode::Signal_source_component : private Kernel_object(CALLED_FROM_CORE, s.signal_receiver(), diff --git a/repos/base-hw/src/core/spec/arm/cortex_a15_cpu.cc b/repos/base-hw/src/core/spec/arm/cortex_a15_cpu.cc new file mode 100644 index 0000000000..0a6a47f710 --- /dev/null +++ b/repos/base-hw/src/core/spec/arm/cortex_a15_cpu.cc @@ -0,0 +1,54 @@ +/* + * \brief Cortex A15 specific MMU context initialization + * \author Stefan Kalkowski + * \date 2017-10-17 + */ + +/* + * Copyright (C) 2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* base-hw core includes */ +#include +#include + +using namespace Core; + + +Cpu::Mmu_context::Mmu_context(addr_t table, + Board::Address_space_id_allocator &id_alloc) +: + _addr_space_id_alloc(id_alloc), + ttbr0(Ttbr_64bit::Ba::masked((Ttbr_64bit::access_t)table)) +{ + Ttbr_64bit::Asid::set(ttbr0, (uint8_t)_addr_space_id_alloc.alloc()); +} + + +Cpu::Mmu_context::~Mmu_context() +{ + /* flush TLB by ASID */ + Cpu::Tlbiasid::write(id()); + _addr_space_id_alloc.free(id()); +} + + +void Cpu::mmu_fault_status(Cpu::Fsr::access_t fsr, Kernel::Thread_fault &fault) +{ + enum { + FAULT_MASK = 0b111100, + TRANSLATION = 0b000100, + PERMISSION = 0b001100, + }; + + using Fault = Kernel::Thread_fault; + + switch(fsr & FAULT_MASK) { + case TRANSLATION: fault.type = Fault::PAGE_MISSING; return; + case PERMISSION: fault.type = Fault::EXEC; return; + default: fault.type = Fault::UNKNOWN; + }; +}; diff --git a/repos/base-hw/src/core/spec/arm/cortex_a15_cpu.h b/repos/base-hw/src/core/spec/arm/cortex_a15_cpu.h new file mode 100644 index 0000000000..fe9824167b --- /dev/null +++ b/repos/base-hw/src/core/spec/arm/cortex_a15_cpu.h @@ -0,0 +1,129 @@ +/* + * \brief CPU driver for core + * \author Martin stein + * \author Stefan Kalkowski + * \date 2011-11-03 + */ + +/* + * Copyright (C) 2011-2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CORE__SPEC__CORTEX_A15__CPU_H_ +#define _CORE__SPEC__CORTEX_A15__CPU_H_ + +/* base-hw core includes */ +#include +#include + +namespace Core { class Cpu; } + + +class Core::Cpu : public Arm_v7_cpu +{ + public: + + /********************************* + ** Virtualization extensions ** + *********************************/ + + /** + * Hypervisor system trap register + */ + struct Hstr : Register<32> + { + /* System coprocessor primary register access trap */ + template + struct T : Bitfield {}; + + static access_t init() + { + /* + * allow everything except c0, c11, c12, and c15 accesses. + */ + access_t v = 0; + T<0>::set(v, 1); + T<11>::set(v, 1); + T<12>::set(v, 1); + T<15>::set(v, 1); + return v; + }; + }; + + /** + * Hypervisor control register + */ + struct Hcr : Register<32> + { + struct Vm : Bitfield<0, 1> {}; /* VT MMU enabled */ + struct Fmo : Bitfield<3, 1> {}; /* FIQ cannot been masked */ + struct Imo : Bitfield<4, 1> {}; /* IRQ cannot been masked */ + struct Amo : Bitfield<5, 1> {}; /* A bit cannot been masked */ + struct Twi : Bitfield<13, 1> {}; /* trap on WFI instruction */ + struct Twe : Bitfield<14, 1> {}; /* trap on WFE instruction */ + struct Tidcp : Bitfield<20, 1> {}; /* trap lockdown */ + struct Tac : Bitfield<21, 1> {}; /* trap ACTLR accesses */ + + static access_t init() + { + access_t v = 0; + Vm::set(v, 1); + Fmo::set(v, 1); + Imo::set(v, 1); + Amo::set(v, 1); + Twi::set(v, 1); + Twe::set(v, 1); + Tidcp::set(v, 1); + Tac::set(v, 1); + return v; + }; + }; + + + /** + * An usermode execution state + */ + class Mmu_context + { + private: + + Board::Address_space_id_allocator &_addr_space_id_alloc; + + public: + + Ttbr_64bit::access_t ttbr0; + + Mmu_context(addr_t table, + Board::Address_space_id_allocator &addr_space_id_alloc); + + ~Mmu_context(); + + uint8_t id() const + { + return (uint8_t)Ttbr_64bit::Asid::get(ttbr0); + } + }; + + static void mmu_fault_status(Fsr::access_t fsr, + Kernel::Thread_fault & fault); + + /** + * Return kernel name of the executing CPU + */ + static unsigned executing_id() { return Mpidr::Aff_0::get(Mpidr::read()); } + + bool active(Mmu_context & mmu_context) + { + return (Ttbr0_64bit::read() == mmu_context.ttbr0); + } + + void switch_to(Mmu_context & mmu_context) + { + Ttbr0_64bit::write(mmu_context.ttbr0); + } +}; + +#endif /* _CORE__SPEC__CORTEX_A15__CPU_H_ */ diff --git a/repos/base-hw/src/core/spec/arm/cortex_a8_page_table.h b/repos/base-hw/src/core/spec/arm/cortex_a8_page_table.h new file mode 100644 index 0000000000..a28a33858f --- /dev/null +++ b/repos/base-hw/src/core/spec/arm/cortex_a8_page_table.h @@ -0,0 +1,44 @@ +/* + * \brief Translation table definitions for core + * \author Martin Stein + * \author Stefan Kalkowski + * \date 2012-02-22 + */ + +/* + * Copyright (C) 2012-2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CORE__SPEC__CORTEX_A8__PAGE_TABLE_H_ +#define _CORE__SPEC__CORTEX_A8__PAGE_TABLE_H_ + +/* base-hw internal includes */ +#include + +/* base-hw core includes */ +#include + + +constexpr unsigned Hw::Page_table::Descriptor_base::_device_tex() { + return 2; } + + +constexpr bool Hw::Page_table::Descriptor_base::_smp() { return false; } + + +void Hw::Page_table::_table_changed(unsigned long addr, unsigned long size) +{ + /* + * The Cortex-A8 CPU can't use the L1 cache on page-table + * walks. Therefore, as the page-tables lie in write-back cacheable + * memory we've to clean the corresponding cache-lines even when a + * page table entry is added. We only do this as core as the kernel + * adds translations solely before MMU and caches are enabled. + */ + Core::Arm_cpu::cache_clean_data_region(addr, size); +} + +#endif /* _CORE__SPEC__CORTEX_A8__PAGE_TABLE_H_ */ diff --git a/repos/base-hw/src/core/spec/arm/cortex_a9_board.cc b/repos/base-hw/src/core/spec/arm/cortex_a9_board.cc new file mode 100644 index 0000000000..d603998330 --- /dev/null +++ b/repos/base-hw/src/core/spec/arm/cortex_a9_board.cc @@ -0,0 +1,25 @@ +/* + * \brief Board implementation specific to Cortex A9 + * \author Stefan Kalkowski + * \date 2016-01-07 + */ + +/* + * Copyright (C) 2016-2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* core includes */ +#include +#include + + +Board::L2_cache & Board::l2_cache() +{ + using namespace Core; + + static L2_cache cache(Platform::mmio_to_virt(Board::PL310_MMIO_BASE)); + return cache; +} diff --git a/repos/base-hw/src/core/spec/arm/cortex_a9_cpu.cc b/repos/base-hw/src/core/spec/arm/cortex_a9_cpu.cc new file mode 100644 index 0000000000..2598895d52 --- /dev/null +++ b/repos/base-hw/src/core/spec/arm/cortex_a9_cpu.cc @@ -0,0 +1,25 @@ +/* + * \brief CPU driver for core + * \author Martin stein + * \author Stefan Kalkowski + * \date 2011-11-03 + */ + +/* + * Copyright (C) 2011-2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* base-hw core includes */ +#include +#include + + +void Core::Cpu::cache_clean_invalidate_data_region(addr_t const base, + size_t const size) +{ + Arm_cpu::cache_clean_invalidate_data_region(base, size); + Board::l2_cache().clean_invalidate(); +} diff --git a/repos/base-hw/src/core/spec/arm/cortex_a9_cpu.h b/repos/base-hw/src/core/spec/arm/cortex_a9_cpu.h new file mode 100644 index 0000000000..11c01ffd60 --- /dev/null +++ b/repos/base-hw/src/core/spec/arm/cortex_a9_cpu.h @@ -0,0 +1,37 @@ +/* + * \brief CPU driver for core + * \author Martin stein + * \author Stefan Kalkowski + * \date 2011-11-03 + */ + +/* + * Copyright (C) 2011-2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CORE__SPEC__CORTEX_A9__CPU_H_ +#define _CORE__SPEC__CORTEX_A9__CPU_H_ + +/* base-hw core includes */ +#include +#include + +namespace Core { struct Cpu; } + + +struct Core::Cpu : Arm_v7_cpu +{ + /** + * Clean and invalidate data-cache for virtual region + * 'base' - 'base + size' + */ + static void cache_clean_invalidate_data_region(addr_t const base, + size_t const size); + + static unsigned executing_id() { return Mpidr::Aff_0::get(Mpidr::read()); } +}; + +#endif /* _CORE__SPEC__CORTEX_A9__CPU_H_ */ diff --git a/repos/base-hw/src/core/spec/arm/cortex_a9_global_timer.cc b/repos/base-hw/src/core/spec/arm/cortex_a9_global_timer.cc new file mode 100644 index 0000000000..242b0fe235 --- /dev/null +++ b/repos/base-hw/src/core/spec/arm/cortex_a9_global_timer.cc @@ -0,0 +1,113 @@ +/* + * \brief Global timer implementation specific to Cortex A9 + * \author Johannes Schlatow + * \date 2023-01-11 + */ + +/* + * Copyright (C) 2023 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* Genode includes */ +#include + +/* core includes */ +#include +#include +#include + +using namespace Core; +using namespace Kernel; + +using Device = Board::Timer; +using counter_t = Board::Timer::Counter::access_t; + + +enum { + TICS_PER_MS = + Board::CORTEX_A9_GLOBAL_TIMER_CLK / + Board::CORTEX_A9_GLOBAL_TIMER_DIV / 1000, +}; + + +Board::Timer::Timer(unsigned cpu_id) +: + Mmio({(char *)Platform::mmio_to_virt(Board::Cpu_mmio::GLOBAL_TIMER_MMIO_BASE), Mmio::SIZE}) +{ + enum { PRESCALER = Board::CORTEX_A9_GLOBAL_TIMER_DIV - 1 }; + + static_assert((TICS_PER_MS >= 1000), + "Bad TICS_PER_US value"); + + /* primary CPU sets initial timer value */ + if (cpu_id == 0) { + write(0); + write(0, 0); + write(0, 1); + } + + Control::access_t control = 0; + Control::Irq_enable::set(control, 1); + Control::Prescaler::set(control, PRESCALER); + Control::Timer_enable::set(control, 1); + write(control); +} + + +time_t Board::Timer::current_ticks() const +{ + uint32_t upper = read(1); + uint32_t lower = read(0); + uint32_t upper_new = read(1); + + while (upper != upper_new) { + upper = upper_new; + lower = read(0); + upper_new = read(1); + } + + return (time_t)upper << 32 | (time_t)lower; +} + + +void Timer::_start_one_shot(time_t const ticks) +{ + /* + * First unset the interrupt flag, + * otherwise if the tick is small enough, we loose an interrupt + */ + _device.write(1); + + /* Disable comparator before setting a new value */ + _device.write(0); + + time_t end_ticks = _device.current_ticks() + ticks; + _device.write((uint32_t)end_ticks, 0); + _device.write((uint32_t)(end_ticks >> 32) , 1); + + /* Enable comparator before setting a new value */ + _device.write(1); +} + + +time_t Timer::ticks_to_us(time_t const ticks) const { + return timer_ticks_to_us(ticks, TICS_PER_MS); } + + +unsigned Timer::interrupt_id() const { + return Board::Cpu_mmio::GLOBAL_TIMER_IRQ; } + + +time_t Timer::us_to_ticks(time_t const us) const { + return (us * TICS_PER_MS) / 1000; } + + +time_t Timer::_duration() const { + return _device.current_ticks() - _time; } + + +time_t Timer::_max_value() const { + return TICS_PER_MS * 5000; } diff --git a/repos/base-hw/src/core/spec/arm/cortex_a9_global_timer.h b/repos/base-hw/src/core/spec/arm/cortex_a9_global_timer.h new file mode 100644 index 0000000000..3a02b7191b --- /dev/null +++ b/repos/base-hw/src/core/spec/arm/cortex_a9_global_timer.h @@ -0,0 +1,68 @@ +/* + * \brief Global timer implementation specific to Cortex A9 + * \author Johannes Schlatow + * \date 2023-01-11 + */ + +/* + * Copyright (C) 2023 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _SRC__CORE__SPEC__ARM__CORTEX_A9_GLOBAL_TIMER_H_ +#define _SRC__CORE__SPEC__ARM__CORTEX_A9_GLOBAL_TIMER_H_ + +/* Genode includes */ +#include + +/* base-hw includes */ +#include + +namespace Board { class Timer; } + + +/** + * Timer driver for core + */ +struct Board::Timer : Genode::Mmio<0x18> +{ + /** + * Counter value registers + */ + struct Counter : Register_array<0x0, 32, 2, 32> { }; + + /** + * Timer control register + */ + struct Control : Register<0x8, 32> + { + struct Timer_enable : Bitfield<0,1> { }; /* enable counting */ + struct Comp_enable : Bitfield<1,1> { }; + struct Irq_enable : Bitfield<2,1> { }; /* unmask interrupt */ + struct Auto_increment : Bitfield<3,1> { }; + struct Prescaler : Bitfield<8,8> { }; + }; + + /** + * Timer interrupt status register + */ + struct Interrupt_status : Register<0xc, 32> + { + struct Event : Bitfield<0,1> { }; /* if counter hit zero */ + }; + + /** + * Comparator registers + */ + struct Comparator : Register_array<0x10, 32, 2, 32> { }; + + Kernel::time_t current_ticks() const; + + Timer(unsigned); + + void init(); +}; + +#endif /* _SRC__CORE__SPEC__ARM__CORTEX_A9_GLOBAL_TIMER_H_ */ diff --git a/repos/base-hw/src/core/spec/arm/cortex_a9_page_table.h b/repos/base-hw/src/core/spec/arm/cortex_a9_page_table.h new file mode 100644 index 0000000000..1152024489 --- /dev/null +++ b/repos/base-hw/src/core/spec/arm/cortex_a9_page_table.h @@ -0,0 +1,30 @@ +/* + * \brief Translation table definitions for core + * \author Martin Stein + * \author Stefan Kalkowski + * \date 2012-02-22 + */ + +/* + * Copyright (C) 2012-2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CORE__SPEC__ARM__CORTEX_A9_PAGE_TABLE_H_ +#define _CORE__SPEC__ARM__CORTEX_A9_PAGE_TABLE_H_ + +#include + + +constexpr unsigned Hw::Page_table::Descriptor_base::_device_tex() { + return 2; } + + +constexpr bool Hw::Page_table::Descriptor_base::_smp() { return true; } + + +void Hw::Page_table::_table_changed(unsigned long, unsigned long) { } + +#endif /* _CORE__SPEC__ARM__CORTEX_A9_PAGE_TABLE_H_ */ diff --git a/repos/base-hw/src/core/spec/arm/cortex_a9_private_timer.cc b/repos/base-hw/src/core/spec/arm/cortex_a9_private_timer.cc deleted file mode 100644 index d2bf7dc4b4..0000000000 --- a/repos/base-hw/src/core/spec/arm/cortex_a9_private_timer.cc +++ /dev/null @@ -1,115 +0,0 @@ -/* - * \brief Timer implementation specific to Cortex A9 - * \author Stefan Kalkowski - * \author Martin Stein - * \date 2016-01-07 - */ - -/* - * Copyright (C) 2016-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -/* Genode includes */ -#include - -/* core includes */ -#include -#include -#include - -using namespace Genode; -using namespace Kernel; - -using Device = Board::Timer; -using counter_t = Board::Timer::Counter::access_t; - - -enum { - TICS_PER_MS = - Board::CORTEX_A9_PRIVATE_TIMER_CLK / - Board::CORTEX_A9_PRIVATE_TIMER_DIV / 1000, - - MAX_COUNTER_VAL = ~(counter_t)0 -}; - - -Board::Timer::Timer(unsigned) -: - Mmio(Platform::mmio_to_virt(Board::Cpu_mmio::PRIVATE_TIMER_MMIO_BASE)) -{ - enum { PRESCALER = Board::CORTEX_A9_PRIVATE_TIMER_DIV - 1 }; - - static_assert((TICS_PER_MS >= 1000) /*&& - (TICS_PER_US * 1000000 * - Board::CORTEX_A9_PRIVATE_TIMER_DIV) == - Board::CORTEX_A9_PRIVATE_TIMER_CLK*/, - "Bad TICS_PER_US value"); - - write(0xffffffff); - Control::access_t control = 0; - Control::Irq_enable::set(control, 1); - Control::Prescaler::set(control, PRESCALER); - Control::Auto_reload::set(control, 1); - Control::Timer_enable::set(control, 1); - write(control); -} - - -void Timer::_start_one_shot(time_t const ticks) -{ - /* - * First unset the interrupt flag, - * otherwise if the tick is small enough, we loose an interrupt - */ - _device.write(1); - _device.write(ticks); -} - - -time_t Timer::ticks_to_us(time_t const ticks) const { - return timer_ticks_to_us(ticks, TICS_PER_MS); } - - -unsigned Timer::interrupt_id() const { - return Board::Cpu_mmio::PRIVATE_TIMER_IRQ; } - - -time_t Timer::us_to_ticks(time_t const us) const { - return (us / 1000) * TICS_PER_MS; } - - -time_t Timer::_duration() const -{ - counter_t const start_counter_val { (counter_t)_last_timeout_duration }; - counter_t const curr_counter_val { _device.read() }; - - /* - * Calculate result depending on whether the counter already wrapped or - * not. See the comment in the implementation of '_max_value' for an - * explanation why this comparison is done instead of checking the IRQ - * status and why it is sufficient. - */ - if (curr_counter_val > start_counter_val) - return start_counter_val + (MAX_COUNTER_VAL - curr_counter_val); - - return start_counter_val - curr_counter_val; -} - - -time_t Timer::_max_value() const -{ - /* - * We propagate a max timeout value far lower than the one required - * by the hardware. This is because on some platforms (Qemu 4.2.1 PBXA9), - * the IRQ status register is not reliable. Sometimes, it indicates an IRQ - * too early, i.e., shortly before the counter wraps. Therefore we have to - * accomplish wrap detection via counter comparison only. Therefore, we - * have to make sure that we always read out the counter before it hits - * the max timout value again. And, therefore, the max timeout value has - * to be far away from the first value the counter has after wrapping. - */ - return MAX_COUNTER_VAL >> 1; -} diff --git a/repos/base-hw/src/core/spec/arm/cortex_a9_private_timer.h b/repos/base-hw/src/core/spec/arm/cortex_a9_private_timer.h deleted file mode 100644 index 45ca3d4768..0000000000 --- a/repos/base-hw/src/core/spec/arm/cortex_a9_private_timer.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * \brief Private Timer implementation specific to Cortex A9 - * \author Martin stein - * \date 2011-12-13 - */ - -/* - * Copyright (C) 2011-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _SRC__CORE__SPEC__ARM__CORTEX_A9_PRIVATE_TIMER_H_ -#define _SRC__CORE__SPEC__ARM__CORTEX_A9_PRIVATE_TIMER_H_ - -/* Genode includes */ -#include - -namespace Board { class Timer; } - - -/** - * Timer driver for core - */ -struct Board::Timer : Genode::Mmio -{ - /** - * Load value register - */ - struct Load : Register<0x0, 32> { }; - - /** - * Counter value register - */ - struct Counter : Register<0x4, 32> { }; - - /** - * Timer control register - */ - struct Control : Register<0x8, 32> - { - struct Timer_enable : Bitfield<0,1> { }; /* enable counting */ - struct Auto_reload : Bitfield<1,1> { }; - struct Irq_enable : Bitfield<2,1> { }; /* unmask interrupt */ - struct Prescaler : Bitfield<8,8> { }; - }; - - /** - * Timer interrupt status register - */ - struct Interrupt_status : Register<0xc, 32> - { - struct Event : Bitfield<0,1> { }; /* if counter hit zero */ - }; - - Timer(unsigned); -}; - -#endif /* _SRC__CORE__SPEC__ARM__CORTEX_A9_PRIVATE_TIMER_H_ */ diff --git a/repos/base-hw/src/core/spec/arm/cpu.cc b/repos/base-hw/src/core/spec/arm/cpu.cc index 7c8c722e31..06e6f1baf5 100644 --- a/repos/base-hw/src/core/spec/arm/cpu.cc +++ b/repos/base-hw/src/core/spec/arm/cpu.cc @@ -14,12 +14,12 @@ /* base includes */ #include -/* base-hw Core includes */ +/* base-hw core includes */ #include #include #include -using namespace Genode; +using namespace Core; Arm_cpu::Context::Context(bool privileged) @@ -46,7 +46,7 @@ Mmu_context(addr_t table, { } -Genode::Arm_cpu::Mmu_context::~Mmu_context() +Core::Arm_cpu::Mmu_context::~Mmu_context() { /* flush TLB by ASID */ Cpu::Tlbiasid::write(id()); @@ -109,23 +109,17 @@ void Arm_cpu::switch_to(Arm_cpu::Mmu_context & ctx) } -template -static inline void cache_maintainance(addr_t const base, - size_t const size, - size_t const cache_line_size, - FUNC & func) +static inline void cache_maintainance(addr_t const base, + size_t const size, + size_t const cache_line_size, + auto const &fn) { - /** - * Although, the ARMv7 reference manual states that addresses does not - * need to be cacheline aligned, we observed problems when not doing so - * on i.MX6 Quad Sabrelite (maybe Cortex A9 generic issue?). - * Therefore, we align it here. - */ + /* align the start address to catch all related cache lines */ addr_t start = base & ~(cache_line_size-1); addr_t const end = base + size; /* iterate over all cachelines of the given region and apply the functor */ - for (; start < end; start += cache_line_size) func(start); + for (; start < end; start += cache_line_size) fn(start); } @@ -147,8 +141,8 @@ void Arm_cpu::cache_coherent_region(addr_t const base, }; /* take the smallest cacheline, either from I-, or D-cache */ - size_t const cache_line_size = Genode::min(Cpu::instruction_cache_line_size(), - Cpu::data_cache_line_size()); + size_t const cache_line_size = min(Cpu::instruction_cache_line_size(), + Cpu::data_cache_line_size()); cache_maintainance(base, size, cache_line_size, lambda); } diff --git a/repos/base-hw/src/core/spec/arm/cpu_support.h b/repos/base-hw/src/core/spec/arm/cpu_support.h index 33d63848be..ef7fabdaf5 100644 --- a/repos/base-hw/src/core/spec/arm/cpu_support.h +++ b/repos/base-hw/src/core/spec/arm/cpu_support.h @@ -32,13 +32,13 @@ namespace Kernel { struct Thread_fault; } -namespace Genode { - using sizet_arithm_t = Genode::uint64_t; +namespace Core { + using sizet_arithm_t = uint64_t; struct Arm_cpu; } -struct Genode::Arm_cpu : public Hw::Arm_cpu +struct Core::Arm_cpu : public Hw::Arm_cpu { struct Fpu_context { @@ -120,6 +120,8 @@ struct Genode::Arm_cpu : public Hw::Arm_cpu * Return kernel name of the executing CPU */ static unsigned executing_id() { return 0; } + + static void single_step(Context &, bool) { }; }; #endif /* _CORE__SPEC__ARM__CPU_SUPPORT_H_ */ diff --git a/repos/base-hw/src/core/spec/arm/crt0.s b/repos/base-hw/src/core/spec/arm/crt0.s index b11c3ae502..b179135c95 100644 --- a/repos/base-hw/src/core/spec/arm/crt0.s +++ b/repos/base-hw/src/core/spec/arm/crt0.s @@ -11,6 +11,8 @@ * under the terms of the GNU Affero General Public License version 3. */ +.include "memory_consts.s" + .section ".text" /*********************** @@ -21,20 +23,22 @@ _start: /* switch to cpu-specific kernel stack */ - adr r1, _kernel_stack - adr r2, _kernel_stack_size + adr r1, _cpu_mem_area_base + adr r2, _cpu_mem_slot_size + adr r3, _kernel_stack_size ldr r1, [r1] ldr r2, [r2] - ldr r2, [r2] - add r0, #1 + ldr r3, [r3] mul r0, r0, r2 - add sp, r1, r0 + add r0, r0, r1 + add sp, r0, r3 /* jump into init C code */ b _ZN6Kernel39main_initialize_and_handle_kernel_entryEv - _kernel_stack: .long kernel_stack - _kernel_stack_size: .long kernel_stack_size + _cpu_mem_area_base: .long HW_MM_CPU_LOCAL_MEMORY_AREA_START + _cpu_mem_slot_size: .long HW_MM_CPU_LOCAL_MEMORY_SLOT_SIZE + _kernel_stack_size: .long HW_MM_KERNEL_STACK_SIZE /********************************* diff --git a/repos/base-hw/src/core/spec/arm/generic_timer.cc b/repos/base-hw/src/core/spec/arm/generic_timer.cc index 5bf6195059..0d702cecd3 100644 --- a/repos/base-hw/src/core/spec/arm/generic_timer.cc +++ b/repos/base-hw/src/core/spec/arm/generic_timer.cc @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2019 Genode Labs GmbH + * Copyright (C) 2019-2022 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -21,10 +21,16 @@ using namespace Kernel; unsigned Timer::interrupt_id() const { return Board::TIMER_IRQ; } -unsigned long Board::Timer::_freq() { return Genode::Cpu::Cntfrq::read(); } +unsigned long Board::Timer::_freq() { return Core::Cpu::Cntfrq::read(); } Board::Timer::Timer(unsigned) : ticks_per_ms((unsigned)(_freq() / 1000)) +{ + init(); +} + + +void Board::Timer::init() { Cpu::Cntp_ctl::access_t ctl = 0; Cpu::Cntp_ctl::Enable::set(ctl, 1); @@ -34,7 +40,6 @@ Board::Timer::Timer(unsigned) : ticks_per_ms((unsigned)(_freq() / 1000)) void Timer::_start_one_shot(time_t const ticks) { - _device.last_time = Cpu::Cntpct::read(); Cpu::Cntp_tval::write((Cpu::Cntp_tval::access_t)ticks); Cpu::Cntp_ctl::access_t ctl = Cpu::Cntp_ctl::read(); Cpu::Cntp_ctl::Istatus::set(ctl, 0); @@ -44,7 +49,7 @@ void Timer::_start_one_shot(time_t const ticks) time_t Timer::_duration() const { - return Cpu::Cntpct::read() - _device.last_time; + return Cpu::Cntpct::read() - _time; } @@ -53,7 +58,7 @@ time_t Timer::ticks_to_us(time_t const ticks) const { time_t Timer::us_to_ticks(time_t const us) const { - return (us / 1000) * _device.ticks_per_ms; } + return (us * _device.ticks_per_ms) / 1000; } time_t Timer::_max_value() const { diff --git a/repos/base-hw/src/core/spec/arm/generic_timer.h b/repos/base-hw/src/core/spec/arm/generic_timer.h index c06f18ee9c..8ec27c1dc3 100644 --- a/repos/base-hw/src/core/spec/arm/generic_timer.h +++ b/repos/base-hw/src/core/spec/arm/generic_timer.h @@ -26,9 +26,9 @@ struct Board::Timer unsigned const ticks_per_ms; - Kernel::time_t last_time { 0 }; - Timer(unsigned); + + void init(); }; #endif /* _SRC__CORE__SPEC__ARM__GENERIC_TIMER_H_ */ diff --git a/repos/base-hw/src/core/spec/arm/gicv2.cc b/repos/base-hw/src/core/spec/arm/gicv2.cc index ff6ab9ff7b..8dd4c05ac0 100644 --- a/repos/base-hw/src/core/spec/arm/gicv2.cc +++ b/repos/base-hw/src/core/spec/arm/gicv2.cc @@ -15,7 +15,7 @@ #include #include -using namespace Genode; +using namespace Core; Hw::Gicv2::Gicv2() diff --git a/repos/base-hw/src/core/spec/arm/gicv3.cc b/repos/base-hw/src/core/spec/arm/gicv3.cc index 6ca86a3842..9bd1a14803 100644 --- a/repos/base-hw/src/core/spec/arm/gicv3.cc +++ b/repos/base-hw/src/core/spec/arm/gicv3.cc @@ -15,10 +15,10 @@ #include #include -using namespace Genode; +using namespace Core; -static inline Genode::addr_t redistributor_addr() +static inline addr_t redistributor_addr() { return Platform::mmio_to_virt(Board::Cpu_mmio::IRQ_CONTROLLER_REDIST_BASE + (Cpu::executing_id() * 0x20000)); @@ -27,9 +27,9 @@ static inline Genode::addr_t redistributor_addr() Hw::Pic::Pic() : - _distr(Platform::mmio_to_virt(Board::Cpu_mmio::IRQ_CONTROLLER_DISTR_BASE)), - _redistr(redistributor_addr()), - _redistr_sgi(redistributor_addr() + 0x10000), + _distr({(char *)Platform::mmio_to_virt(Board::Cpu_mmio::IRQ_CONTROLLER_DISTR_BASE), Board::Cpu_mmio::IRQ_CONTROLLER_DISTR_SIZE}), + _redistr({(char *)redistributor_addr(), Board::Cpu_mmio::IRQ_CONTROLLER_REDIST_SIZE}), + _redistr_sgi({(char *)redistributor_addr() + 0x10000, Board::Cpu_mmio::IRQ_CONTROLLER_REDIST_SIZE - 0x10000}), _max_irq(_distr.max_irq()) { _redistributor_init(); diff --git a/repos/base-hw/src/core/spec/arm/imx_epit.cc b/repos/base-hw/src/core/spec/arm/imx_epit.cc deleted file mode 100644 index e226969be8..0000000000 --- a/repos/base-hw/src/core/spec/arm/imx_epit.cc +++ /dev/null @@ -1,81 +0,0 @@ -/* - * \brief Timer driver for core - * \author Stefan Kalkowski - * \author Martin Stein - * \date 2012-04-23 - */ - -/* - * Copyright (C) 2012-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -/* core includes */ -#include -#include -#include - -#include - -using namespace Genode; -using namespace Kernel; - - -unsigned Timer::interrupt_id() const { return Board::EPIT_1_IRQ; } - - -Board::Timer::Timer(unsigned) -: - Mmio(Platform::mmio_to_virt(Board::EPIT_1_MMIO_BASE)) -{ - reset(); - - Cr::access_t cr = read(); - Cr::En_mod::set(cr, Cr::En_mod::RELOAD); - Cr::Oci_en::set(cr, 1); - Cr::Prescaler::set(cr, Cr::Prescaler::DIVIDE_BY_1); - Cr::Clk_src::set(cr, Cr::Clk_src::HIGH_FREQ_REF_CLK); - Cr::Iovw::set(cr, 1); - write(cr); - - write(0xffffffff); - write(1); - - write(0xffffffff); -} - - -void Timer::_start_one_shot(time_t const ticks) -{ - /* - * First unset the interrupt flag, - * otherwise if the tick is small enough, we loose an interrupt - */ - _device.write(1); - _device.write(ticks - 1); -} - - -time_t Timer::ticks_to_us(time_t const ticks) const { - return timer_ticks_to_us(ticks, Board::Timer::TICS_PER_MS); } - - -time_t Timer::us_to_ticks(time_t const us) const { - return (us / 1000UL) * Board::Timer::TICS_PER_MS; } - - -time_t Timer::_max_value() const { - return 0xffffffff; } - - -time_t Timer::_duration() const -{ - using Device = Board::Timer; - Device::Cnt::access_t last = _last_timeout_duration; - Device::Cnt::access_t cnt = _device.read(); - Device::Cnt::access_t ret = (_device.read()) - ? _max_value() - cnt + last : last - cnt; - return ret; -} diff --git a/repos/base-hw/src/core/spec/arm/imx_epit.h b/repos/base-hw/src/core/spec/arm/imx_epit.h deleted file mode 100644 index 8a901dd29d..0000000000 --- a/repos/base-hw/src/core/spec/arm/imx_epit.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * \brief Timer driver for core - * \author Martin Stein - * \date 2012-04-23 - */ - -/* - * Copyright (C) 2012-2017 Kernel Labs GmbH - * - * This file is part of the Kernel OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _SRC__CORE__SPEC__ARM__IMX_EPIT_H_ -#define _SRC__CORE__SPEC__ARM__IMX_EPIT_H_ - -/* Kernel includes */ -#include - -namespace Board { class Timer; } - - -/** - * Timer driver for core - */ -struct Board::Timer : Genode::Mmio -{ - enum { TICS_PER_MS = 33333 }; - - /** - * Control register - */ - struct Cr : Register<0x0, 32> - { - struct En : Bitfield<0, 1> { }; /* enable timer */ - - struct En_mod : Bitfield<1, 1> /* reload on enable */ - { - enum { RELOAD = 1 }; - }; - - struct Oci_en : Bitfield<2, 1> { }; /* interrupt on compare */ - - struct Rld : Bitfield<3, 1> /* reload or roll-over */ - { - enum { RELOAD_FROM_LR = 1 }; - }; - - struct Prescaler : Bitfield<4, 12> /* clock input divisor */ - { - enum { DIVIDE_BY_1 = 0 }; - }; - - struct Swr : Bitfield<16, 1> { }; /* software reset bit */ - struct Iovw : Bitfield<17, 1> { }; /* enable overwrite */ - - struct Clk_src : Bitfield<24, 2> /* select clock input */ - { - enum { HIGH_FREQ_REF_CLK = 2 }; - }; - }; - - /** - * Status register - */ - struct Sr : Register<0x4, 32> - { - struct Ocif : Bitfield<0, 1> { }; /* IRQ status, write 1 clears */ - }; - - struct Lr : Register<0x8, 32> { }; /* load value register */ - struct Cmpr : Register<0xc, 32> { }; /* compare value register */ - struct Cnt : Register<0x10, 32> { }; /* counter register */ - - /** - * Disable timer and clear its interrupt output - */ - void reset() - { - /* wait until ongoing reset operations are finished */ - while (read()) ; - - /* disable timer */ - write(0); - - /* clear interrupt */ - write(1); - } - - Timer(unsigned); -}; - -#endif /* _SRC__CORE__SPEC__ARM__IMX_EPIT_H_ */ diff --git a/repos/base-hw/src/core/spec/arm/imx_tzic.cc b/repos/base-hw/src/core/spec/arm/imx_tzic.cc deleted file mode 100644 index a0c9a2eade..0000000000 --- a/repos/base-hw/src/core/spec/arm/imx_tzic.cc +++ /dev/null @@ -1,21 +0,0 @@ -/* - * \brief Freescale TrustZone aware interrupt controller for core - * \author Stefan Kalkowski - * \date 2012-10-24 - */ - -/* - * Copyright (C) 2012-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -/* core includes */ -#include -#include - -using namespace Genode; - - -Hw::Pic::Pic() : Mmio(Platform::mmio_to_virt(Board::IRQ_CONTROLLER_BASE)) { } diff --git a/repos/base-hw/src/core/spec/arm/kernel/lock.cc b/repos/base-hw/src/core/spec/arm/kernel/lock.cc index f017b7e93d..5815eb209d 100644 --- a/repos/base-hw/src/core/spec/arm/kernel/lock.cc +++ b/repos/base-hw/src/core/spec/arm/kernel/lock.cc @@ -15,7 +15,7 @@ #include #include -/* base-hw Core includes */ +/* base-hw core includes */ #include #include diff --git a/repos/base-hw/src/core/spec/arm/kernel/panic.cc b/repos/base-hw/src/core/spec/arm/kernel/panic.cc index 95da36f159..04dfa6094a 100644 --- a/repos/base-hw/src/core/spec/arm/kernel/panic.cc +++ b/repos/base-hw/src/core/spec/arm/kernel/panic.cc @@ -11,7 +11,7 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* base-hw Core includes */ +/* base-hw core includes */ #include diff --git a/repos/base-hw/src/core/spec/arm/kernel/thread.cc b/repos/base-hw/src/core/spec/arm/kernel/thread.cc index 838a730c79..c353745e46 100644 --- a/repos/base-hw/src/core/spec/arm/kernel/thread.cc +++ b/repos/base-hw/src/core/spec/arm/kernel/thread.cc @@ -15,7 +15,7 @@ /* base includes */ #include -/* base-hw Core includes */ +/* base-hw core includes */ #include #include #include @@ -26,6 +26,9 @@ using namespace Kernel; extern "C" void kernel_to_user_context_switch(Cpu::Context*, Cpu::Fpu_context*); +void Thread::_call_suspend() { } + + void Thread::exception(Cpu & cpu) { switch (regs->cpu_exception) { @@ -62,7 +65,13 @@ void Thread::exception(Cpu & cpu) * coprocessor registers (there might be ARM SoCs where this is not valid, * with several shareability domains, but until now we do not support them) */ -void Kernel::Thread::Tlb_invalidation::execute() { }; +void Kernel::Thread::Tlb_invalidation::execute(Cpu &) { } + + +void Thread::Flush_and_stop_cpu::execute(Cpu &) { } + + +void Cpu::Halt_job::proceed(Kernel::Cpu &) { } void Thread::proceed(Cpu & cpu) @@ -78,7 +87,8 @@ void Thread::proceed(Cpu & cpu) void Thread::user_ret_time(Kernel::time_t const t) { - regs->r0 = t >> 32UL; + /* split 64-bit time_t value into 2 register */ + regs->r0 = (addr_t) (t >> 32UL); regs->r1 = t & ~0UL; } diff --git a/repos/base-hw/src/core/spec/arm/kernel/thread_caches.cc b/repos/base-hw/src/core/spec/arm/kernel/thread_caches.cc index 2eee9b912b..27a18d3b20 100644 --- a/repos/base-hw/src/core/spec/arm/kernel/thread_caches.cc +++ b/repos/base-hw/src/core/spec/arm/kernel/thread_caches.cc @@ -11,7 +11,7 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* base-hw Core includes */ +/* base-hw core includes */ #include #include #include @@ -19,11 +19,10 @@ using namespace Kernel; -template -static void for_cachelines(addr_t base, - size_t const size, - Kernel::Thread & thread, - FN const & fn) +static void for_cachelines(addr_t base, + size_t const size, + Kernel::Thread &thread, + auto const &fn) { /** * sanity check that only one small page is affected, @@ -54,7 +53,7 @@ void Kernel::Thread::_call_cache_coherent_region() { for_cachelines((addr_t)user_arg_1(), (size_t)user_arg_2(), *this, [] (addr_t addr, size_t size) { - Genode::Cpu::cache_coherent_region(addr, size); }); + Core::Cpu::cache_coherent_region(addr, size); }); } @@ -62,7 +61,7 @@ void Kernel::Thread::_call_cache_clean_invalidate_data_region() { for_cachelines((addr_t)user_arg_1(), (size_t)user_arg_2(), *this, [] (addr_t addr, size_t size) { - Genode::Cpu::cache_clean_invalidate_data_region(addr, size); }); + Core::Cpu::cache_clean_invalidate_data_region(addr, size); }); } @@ -70,5 +69,12 @@ void Kernel::Thread::_call_cache_invalidate_data_region() { for_cachelines((addr_t)user_arg_1(), (size_t)user_arg_2(), *this, [] (addr_t addr, size_t size) { - Genode::Cpu::cache_invalidate_data_region(addr, size); }); + Core::Cpu::cache_invalidate_data_region(addr, size); }); +} + + +void Kernel::Thread::_call_cache_line_size() +{ + size_t const cache_line_size = Core::Cpu::cache_line_size(); + user_arg_0(cache_line_size); } diff --git a/repos/base-hw/src/core/spec/arm/platform_support.cc b/repos/base-hw/src/core/spec/arm/platform_support.cc index 5bef5904c3..7d952ffe85 100644 --- a/repos/base-hw/src/core/spec/arm/platform_support.cc +++ b/repos/base-hw/src/core/spec/arm/platform_support.cc @@ -14,20 +14,19 @@ /* core includes */ #include -using namespace Genode; +using namespace Core; void Platform::_init_io_port_alloc() { }; -void Platform::_init_additional_platform_info(Genode::Xml_generator&) { } +void Platform::_init_additional_platform_info(Xml_generator&) { } long Platform::irq(long const user_irq) { return user_irq; } -bool Platform::get_msi_params(const addr_t /* mmconf */, addr_t & /* address */, - addr_t & /* data */, unsigned & /* irq_number */) -{ - return false; -} +bool Platform::alloc_msi_vector(addr_t &, addr_t &) { return false; } + + +void Platform::free_msi_vector(addr_t, addr_t) { } diff --git a/repos/base-hw/src/core/spec/arm/trustzone_board.h b/repos/base-hw/src/core/spec/arm/trustzone_board.h index 28f7a616e0..63a669dbd2 100644 --- a/repos/base-hw/src/core/spec/arm/trustzone_board.h +++ b/repos/base-hw/src/core/spec/arm/trustzone_board.h @@ -14,20 +14,25 @@ #ifndef _CORE__SPEC__ARM_TRUSTZONE_BOARD_H_ #define _CORE__SPEC__ARM_TRUSTZONE_BOARD_H_ -#include +/* Genode includes */ +#include + +/* core includes */ +#include namespace Kernel { class Cpu; } namespace Board { - using Genode::Vm_state; + using Core::Vcpu_state; + using Vcpu_data = Core::Vcpu_state; enum { VCPU_MAX = 1 }; struct Vm_page_table {}; struct Vm_page_table_array {}; - class Global_interrupt_controller { }; + class Global_interrupt_controller { public: void init() {} }; struct Pic : Hw::Pic { struct Virtual_context {}; Pic(Global_interrupt_controller &) { } }; struct Vcpu_context { Vcpu_context(Kernel::Cpu &) {} }; } diff --git a/repos/base-hw/src/core/spec/arm/virtualization/board.h b/repos/base-hw/src/core/spec/arm/virtualization/board.h index e89c563e6f..cd1987b75b 100644 --- a/repos/base-hw/src/core/spec/arm/virtualization/board.h +++ b/repos/base-hw/src/core/spec/arm/virtualization/board.h @@ -14,13 +14,15 @@ #ifndef _CORE__SPEC__ARM__VIRTUALIZATION__BOARD_H_ #define _CORE__SPEC__ARM__VIRTUALIZATION__BOARD_H_ -/* base-hw Core includes */ +/* core includes */ #include #include /* base-hw internal includes */ #include +namespace Genode { struct Vcpu_state; } + namespace Board { using Vm_page_table = Hw::Level_1_stage_2_translation_table; @@ -29,7 +31,8 @@ namespace Board { struct Vcpu_context; - using Vm_state = Genode::Vm_state; + using Vcpu_state = Genode::Vcpu_state; + using Vcpu_data = Genode::Vcpu_state; }; diff --git a/repos/base-hw/src/core/spec/arm/virtualization/gicv2.cc b/repos/base-hw/src/core/spec/arm/virtualization/gicv2.cc index 39e7687c06..1dee16a90b 100644 --- a/repos/base-hw/src/core/spec/arm/virtualization/gicv2.cc +++ b/repos/base-hw/src/core/spec/arm/virtualization/gicv2.cc @@ -11,8 +11,10 @@ * under the terms of the GNU Affero General Public License version 3. */ +/* Genode includes */ #include +/* core includes */ #include #include @@ -21,7 +23,7 @@ using Board::Pic; Pic::Gich::Gich() : - Genode::Mmio(Genode::Platform::mmio_to_virt(Board::Cpu_mmio::IRQ_CONTROLLER_VT_CTRL_BASE)) + Mmio({(char *)Core::Platform::mmio_to_virt(Board::Cpu_mmio::IRQ_CONTROLLER_VT_CTRL_BASE), Mmio::SIZE}) { } diff --git a/repos/base-hw/src/core/spec/arm/virtualization/gicv2.h b/repos/base-hw/src/core/spec/arm/virtualization/gicv2.h index e8500dadb1..32fec30457 100644 --- a/repos/base-hw/src/core/spec/arm/virtualization/gicv2.h +++ b/repos/base-hw/src/core/spec/arm/virtualization/gicv2.h @@ -18,7 +18,7 @@ namespace Board { - class Global_interrupt_controller { }; + class Global_interrupt_controller { public: void init() {} }; class Pic; }; @@ -27,7 +27,9 @@ class Board::Pic : public Hw::Gicv2 { private: - struct Gich : Genode::Mmio + using uint32_t = Genode::uint32_t; + + struct Gich : Genode::Mmio<0x104> { struct Gich_hcr : Register<0x00, 32> { }; struct Gich_vmcr : Register<0x08, 32> { }; @@ -44,12 +46,12 @@ class Board::Pic : public Hw::Gicv2 struct Virtual_context { - Genode::uint32_t lr { 0 }; - Genode::uint32_t apr { 0 }; - Genode::uint32_t vmcr { 0x4c0000 }; - Genode::uint32_t misr { 0 }; - Genode::uint32_t eisr { 0 }; - Genode::uint32_t elrsr { 0xffffffff }; + uint32_t lr { 0 }; + uint32_t apr { 0 }; + uint32_t vmcr { 0x4c0000 }; + uint32_t misr { 0 }; + uint32_t eisr { 0 }; + uint32_t elrsr { 0xffffffff }; }; bool ack_virtual_irq(Virtual_context & c); diff --git a/repos/base-hw/src/core/spec/arm/virtualization/gicv3.h b/repos/base-hw/src/core/spec/arm/virtualization/gicv3.h index c79ce3ba8b..f8f11cbf1e 100644 --- a/repos/base-hw/src/core/spec/arm/virtualization/gicv3.h +++ b/repos/base-hw/src/core/spec/arm/virtualization/gicv3.h @@ -18,7 +18,7 @@ namespace Board { - class Global_interrupt_controller { }; + class Global_interrupt_controller { public: void init() {} }; class Pic; }; @@ -27,13 +27,17 @@ class Board::Pic : public Hw::Pic { public: - struct Virtual_context { - Genode::uint64_t lr { 0 }; - Genode::uint32_t apr { 0 }; - Genode::uint32_t vmcr { 0x4c0000 }; - Genode::uint32_t misr { 0 }; - Genode::uint32_t eisr { 0 }; - Genode::uint32_t elrsr { 0xffffffff }; + using uint32_t = Genode::uint32_t; + using uint64_t = Genode::uint64_t; + + struct Virtual_context + { + uint64_t lr { 0 }; + uint32_t apr { 0 }; + uint32_t vmcr { 0x4c0000 }; + uint32_t misr { 0 }; + uint32_t eisr { 0 }; + uint32_t elrsr { 0xffffffff }; }; bool ack_virtual_irq(Virtual_context & c) diff --git a/repos/base-hw/src/core/spec/arm/virtualization/platform_services.cc b/repos/base-hw/src/core/spec/arm/virtualization/platform_services.cc index 3053a6047b..67c15ca117 100644 --- a/repos/base-hw/src/core/spec/arm/virtualization/platform_services.cc +++ b/repos/base-hw/src/core/spec/arm/virtualization/platform_services.cc @@ -13,7 +13,6 @@ /* Genode includes */ #include -#include /* core includes */ #include @@ -24,20 +23,20 @@ #include #include +using namespace Core; -extern Genode::addr_t hypervisor_exception_vector; + +extern addr_t hypervisor_exception_vector; /* * Add ARM virtualization specific vm service */ -void Genode::platform_add_local_services(Rpc_entrypoint &ep, - Sliced_heap &sh, - Registry &services, - Trace::Source_registry &trace_sources) +void Core::platform_add_local_services(Rpc_entrypoint &ep, + Sliced_heap &sh, + Registry &services, + Core::Trace::Source_registry &trace_sources) { - using namespace Genode; - map_local(Platform::core_phys_addr((addr_t)&hypervisor_exception_vector), Hw::Mm::hypervisor_exception_vector().base, Hw::Mm::hypervisor_exception_vector().size / get_page_size(), diff --git a/repos/base-hw/src/core/spec/arm/virtualization/vm_session_component.cc b/repos/base-hw/src/core/spec/arm/virtualization/vm_session_component.cc index 8edbc971f3..9eb54ab608 100644 --- a/repos/base-hw/src/core/spec/arm/virtualization/vm_session_component.cc +++ b/repos/base-hw/src/core/spec/arm/virtualization/vm_session_component.cc @@ -24,7 +24,7 @@ #include #include -using namespace Genode; +using namespace Core; static Core_mem_allocator & cma() { @@ -42,10 +42,10 @@ void Vm_session_component::_attach(addr_t phys_addr, addr_t vm_addr, size_t size _table_array.alloc()); return; } catch(Hw::Out_of_tables &) { - Genode::error("Translation table needs to much RAM"); + error("Translation table needs to much RAM"); } catch(...) { - Genode::error("Invalid mapping ", Genode::Hex(phys_addr), " -> ", - Genode::Hex(vm_addr), " (", size, ")"); + error("Invalid mapping ", Hex(phys_addr), " -> ", + Hex(vm_addr), " (", size, ")"); } } @@ -87,7 +87,7 @@ void * Vm_session_component::_alloc_table() } -using Vmid_allocator = Genode::Bit_allocator<256>; +using Vmid_allocator = Bit_allocator<256>; static Vmid_allocator &alloc() { @@ -103,6 +103,12 @@ static Vmid_allocator &alloc() } +Genode::addr_t Vm_session_component::_alloc_vcpu_data(Genode::addr_t ds_addr) +{ + return ds_addr; +} + + Vm_session_component::Vm_session_component(Rpc_entrypoint &ds_ep, Resources resources, Label const &, @@ -138,7 +144,7 @@ Vm_session_component::~Vm_session_component() if (!_map.any_block_addr(&out_addr)) break; - detach(out_addr); + detach_at(out_addr); } /* free region in allocator */ diff --git a/repos/base-hw/src/core/spec/arm_v6/cpu.h b/repos/base-hw/src/core/spec/arm_v6/cpu.h index 6a9c6dfeb9..64a256f358 100644 --- a/repos/base-hw/src/core/spec/arm_v6/cpu.h +++ b/repos/base-hw/src/core/spec/arm_v6/cpu.h @@ -15,20 +15,20 @@ #ifndef _CORE__SPEC__ARM_V6__CPU_H_ #define _CORE__SPEC__ARM_V6__CPU_H_ -/* base-hw Core includes */ +/* base-hw core includes */ #include -#include +#include -namespace Genode { struct Cpu; } +namespace Core { struct Cpu; } -struct Genode::Cpu : Arm_cpu +struct Core::Cpu : Arm_cpu { static inline void synchronization_barrier() {} static inline size_t data_cache_line_size() { - struct Ctr : Genode::Register<32> { + struct Ctr : Register<32> { struct D_min_line : Bitfield<12,2> {}; }; @@ -44,7 +44,7 @@ struct Genode::Cpu : Arm_cpu static inline size_t instruction_cache_line_size() { - struct Ctr : Genode::Register<32> { + struct Ctr : Register<32> { struct I_min_line : Bitfield<0,2> {}; }; @@ -57,6 +57,9 @@ struct Genode::Cpu : Arm_cpu return instruction_cache_line_size; } + + static inline size_t cache_line_size() { + return min(data_cache_line_size(), instruction_cache_line_size()); } }; #endif /* _CORE__SPEC__ARM_V6__CPU_H_ */ diff --git a/repos/base-hw/src/core/spec/arm_v6/page_table.h b/repos/base-hw/src/core/spec/arm_v6/page_table.h new file mode 100644 index 0000000000..9d6d6f755c --- /dev/null +++ b/repos/base-hw/src/core/spec/arm_v6/page_table.h @@ -0,0 +1,35 @@ +/* + * \brief Armv6 translation table for core + * \author Martin Stein + * \author Stefan Kalkowski + * \date 2012-02-22 + */ + +/* + * Copyright (C) 2012-2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CORE__SPEC__ARM_V6__PAGE_TABLE_H_ +#define _CORE__SPEC__ARM_V6__PAGE_TABLE_H_ + +#include +#include +#include + + +constexpr unsigned Hw::Page_table::Descriptor_base::_device_tex() { + return 0; } + + +constexpr bool Hw::Page_table::Descriptor_base::_smp() { return false; } + + +void Hw::Page_table::_table_changed(unsigned long addr, unsigned long size) +{ + Core::Arm_cpu::cache_clean_data_region(addr, size); +} + +#endif /* _CORE__SPEC__ARM_V6__PAGE_TABLE_H_ */ diff --git a/repos/base-hw/src/core/spec/arm_v6/translation_table.h b/repos/base-hw/src/core/spec/arm_v6/translation_table.h deleted file mode 100644 index 11fb9ba0b4..0000000000 --- a/repos/base-hw/src/core/spec/arm_v6/translation_table.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * \brief Armv6 translation table for core - * \author Martin Stein - * \author Stefan Kalkowski - * \date 2012-02-22 - */ - -/* - * Copyright (C) 2012-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _CORE__SPEC__ARM_V6__TRANSLATION_TABLE_H_ -#define _CORE__SPEC__ARM_V6__TRANSLATION_TABLE_H_ - -#include -#include -#include - - -constexpr unsigned Hw::Page_table::Descriptor_base::_device_tex() { - return 0; } - - -constexpr bool Hw::Page_table::Descriptor_base::_smp() { return false; } - - -void Hw::Page_table::_table_changed(unsigned long addr, unsigned long size) -{ - Genode::Arm_cpu::cache_clean_data_region(addr, size); -} - -#endif /* _CORE__SPEC__ARM_V6__TRANSLATION_TABLE_H_ */ diff --git a/repos/base-hw/src/core/spec/arm_v7/cpu_support.h b/repos/base-hw/src/core/spec/arm_v7/cpu_support.h index 4085c7506e..b798999e30 100644 --- a/repos/base-hw/src/core/spec/arm_v7/cpu_support.h +++ b/repos/base-hw/src/core/spec/arm_v7/cpu_support.h @@ -17,10 +17,10 @@ /* core includes */ #include -namespace Genode { struct Arm_v7_cpu; } +namespace Core { struct Arm_v7_cpu; } -struct Genode::Arm_v7_cpu : Arm_cpu +struct Core::Arm_v7_cpu : Arm_cpu { /** * Returns whether this cpu implements the multiprocessor extensions @@ -50,7 +50,7 @@ struct Genode::Arm_v7_cpu : Arm_cpu static inline size_t data_cache_line_size() { - struct Ctr : Genode::Register<32> { + struct Ctr : Register<32> { struct D_min_line : Bitfield<16,4> {}; }; @@ -66,7 +66,7 @@ struct Genode::Arm_v7_cpu : Arm_cpu static inline size_t instruction_cache_line_size() { - struct Ctr : Genode::Register<32> { + struct Ctr : Register<32> { struct I_min_line : Bitfield<0,4> {}; }; @@ -79,6 +79,10 @@ struct Genode::Arm_v7_cpu : Arm_cpu return instruction_cache_line_size; } + + + static inline size_t cache_line_size() { + return min(data_cache_line_size(), instruction_cache_line_size()); } }; #endif /* _CORE__SPEC__ARM_V7__CPU_SUPPORT_H_ */ diff --git a/repos/base-hw/src/core/spec/arm_v7/trustzone/kernel/vm.cc b/repos/base-hw/src/core/spec/arm_v7/trustzone/kernel/vm.cc index e6cc8f2d00..16fddfcb6d 100644 --- a/repos/base-hw/src/core/spec/arm_v7/trustzone/kernel/vm.cc +++ b/repos/base-hw/src/core/spec/arm_v7/trustzone/kernel/vm.cc @@ -1,12 +1,13 @@ /* - * \brief Kernel backend for virtual machines - * \author Martin Stein - * \author Stefan Kalkowski - * \date 2013-10-30 + * \brief Kernel backend for virtual machines + * \author Martin Stein + * \author Stefan Kalkowski + * \author Benjamin Lamowski + * \date 2013-10-30 */ /* - * Copyright (C) 2013-2017 Genode Labs GmbH + * Copyright (C) 2013-2023 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -15,26 +16,30 @@ /* core includes */ #include #include -#include +#include using namespace Kernel; Vm::Vm(Irq::Pool & user_irq_pool, Cpu & cpu, - Genode::Vm_state & state, + Genode::Vcpu_data & data, Kernel::Signal_context & context, Identity & id) : Kernel::Object { *this }, - Cpu_job(Cpu_priority::min(), 0), + Cpu_job(Scheduler::Priority::min(), 0), _user_irq_pool(user_irq_pool), - _state(state), + _state(data), _context(context), _id(id), _vcpu_context(cpu) { affinity(cpu); + /* once constructed, exit with a startup exception */ + pause(); + _state.cpu_exception = Genode::VCPU_EXCEPTION_STARTUP; + _context.submit(1); } @@ -61,8 +66,7 @@ void Vm::exception(Cpu & cpu) bool secure_irq(unsigned const i); -extern "C" void monitor_mode_enter_normal_world(Genode::Vm_state&, void*); -extern void * kernel_stack; +extern "C" void monitor_mode_enter_normal_world(Genode::Vcpu_state&, void*); void Vm::proceed(Cpu & cpu) @@ -79,3 +83,11 @@ void Vm::proceed(Cpu & cpu) monitor_mode_enter_normal_world(_state, (void*) cpu.stack_start()); } + + +void Vm::_sync_to_vmm() +{} + + +void Vm::_sync_from_vmm() +{} diff --git a/repos/base-hw/src/core/spec/arm_v7/trustzone/platform_services.cc b/repos/base-hw/src/core/spec/arm_v7/trustzone/platform_services.cc index 1b3fa24c08..2a3919d40a 100644 --- a/repos/base-hw/src/core/spec/arm_v7/trustzone/platform_services.cc +++ b/repos/base-hw/src/core/spec/arm_v7/trustzone/platform_services.cc @@ -13,9 +13,8 @@ /* Genode includes */ #include -#include -/* Core includes */ +/* core includes */ #include #include #include @@ -30,10 +29,10 @@ extern int monitor_mode_exception_vector; /* * Add TrustZone specific vm service */ -void Genode::platform_add_local_services(Rpc_entrypoint &ep, - Sliced_heap &sliced_heap, - Registry &local_services, - Trace::Source_registry &trace_sources) +void Core::platform_add_local_services(Rpc_entrypoint &ep, + Sliced_heap &sliced_heap, + Registry &local_services, + Core::Trace::Source_registry &trace_sources) { static addr_t const phys_base = Platform::core_phys_addr((addr_t)&monitor_mode_exception_vector); diff --git a/repos/base-hw/src/core/spec/arm_v7/trustzone/vm_session_component.cc b/repos/base-hw/src/core/spec/arm_v7/trustzone/vm_session_component.cc index eb2e462221..a189cc5d8c 100644 --- a/repos/base-hw/src/core/spec/arm_v7/trustzone/vm_session_component.cc +++ b/repos/base-hw/src/core/spec/arm_v7/trustzone/vm_session_component.cc @@ -18,7 +18,7 @@ #include #include -using namespace Genode; +using namespace Core; static Board::Vm_page_table_array & dummy_array() @@ -52,6 +52,12 @@ void * Vm_session_component::_alloc_table() static unsigned id_alloc = 0; +Genode::addr_t Vm_session_component::_alloc_vcpu_data(Genode::addr_t ds_addr) +{ + return ds_addr; +} + + Vm_session_component::Vm_session_component(Rpc_entrypoint &ep, Resources resources, Label const &, @@ -86,7 +92,7 @@ Vm_session_component::~Vm_session_component() if (!_map.any_block_addr(&out_addr)) break; - detach(out_addr); + detach_at(out_addr); } /* free region in allocator */ diff --git a/repos/base-hw/src/core/spec/arm_v7/virtualization/hypervisor.h b/repos/base-hw/src/core/spec/arm_v7/virtualization/hypervisor.h index d9935902d6..11b914e276 100644 --- a/repos/base-hw/src/core/spec/arm_v7/virtualization/hypervisor.h +++ b/repos/base-hw/src/core/spec/arm_v7/virtualization/hypervisor.h @@ -14,8 +14,9 @@ #ifndef _SPEC__ARM_V7__VIRTUALIZATION_HYPERVISOR_H_ #define _SPEC__ARM_V7__VIRTUALIZATION_HYPERVISOR_H_ -#include -#include +/* core includes */ +#include +#include namespace Hypervisor { @@ -38,16 +39,16 @@ namespace Hypervisor { inline void invalidate_tlb(Genode::uint64_t vttbr) { hypervisor_call(TLB_INVALIDATE, - (vttbr & 0xffffffff), - ((vttbr >> 32U) & 0xffffffff)); + (Call_arg)vttbr, + (Call_arg)(vttbr >> 32U)); } - inline void switch_world(Genode::Vm_state & vm_state, + inline void switch_world(Core::Vcpu_state & vcpu_state, Host_context & host_state) { hypervisor_call(WORLD_SWITCH, - (Call_arg)&vm_state, + (Call_arg)&vcpu_state, (Call_arg)&host_state); } } diff --git a/repos/base-hw/src/core/spec/arm_v7/virtualization/kernel/vm.cc b/repos/base-hw/src/core/spec/arm_v7/virtualization/kernel/vm.cc index 416110121e..c8f5ece998 100644 --- a/repos/base-hw/src/core/spec/arm_v7/virtualization/kernel/vm.cc +++ b/repos/base-hw/src/core/spec/arm_v7/virtualization/kernel/vm.cc @@ -1,19 +1,19 @@ /* - * \brief Kernel backend for virtual machines - * \author Stefan Kalkowski - * \date 2015-02-10 + * \brief Kernel backend for virtual machines + * \author Stefan Kalkowski + * \author Benjamin Lamowski + * \date 2015-02-10 */ /* - * Copyright (C) 2015-2017 Genode Labs GmbH + * Copyright (C) 2015-2023 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. */ -#include #include -#include +#include #include #include @@ -65,7 +65,7 @@ struct Hypervisor::Host_context static Hypervisor::Host_context & host_context(Cpu & cpu) { static Genode::Constructible - host_context[NR_OF_CPUS]; + host_context[Board::NR_OF_CPUS]; if (!host_context[cpu.id()].constructed()) { host_context[cpu.id()].construct(); Hypervisor::Host_context & c = *host_context[cpu.id()]; @@ -135,19 +135,23 @@ void Board::Vcpu_context::Virtual_timer_irq::disable() Kernel::Vm::Vm(Irq::Pool & user_irq_pool, Cpu & cpu, - Genode::Vm_state & state, + Genode::Vcpu_data & data, Kernel::Signal_context & context, Identity & id) : Kernel::Object { *this }, - Cpu_job(Cpu_priority::min(), 0), + Cpu_job(Scheduler::Priority::min(), 0), _user_irq_pool(user_irq_pool), - _state(state), + _state(data), _context(context), _id(id), _vcpu_context(cpu) { affinity(cpu); + /* once constructed, exit with a startup exception */ + pause(); + _state.cpu_exception = Genode::VCPU_EXCEPTION_STARTUP; + _context.submit(1); } @@ -202,6 +206,14 @@ void Kernel::Vm::proceed(Cpu & cpu) } +void Vm::_sync_to_vmm() +{} + + +void Vm::_sync_from_vmm() +{} + + void Vm::inject_irq(unsigned irq) { _state.irqs.last_irq = irq; diff --git a/repos/base-hw/src/core/spec/arm_v8/cpu.cc b/repos/base-hw/src/core/spec/arm_v8/cpu.cc index 617b7fd70b..e64e9f88e9 100644 --- a/repos/base-hw/src/core/spec/arm_v8/cpu.cc +++ b/repos/base-hw/src/core/spec/arm_v8/cpu.cc @@ -15,31 +15,32 @@ #include #include -/* base-hw Core includes */ +/* base-hw core includes */ #include #include +using namespace Core; -Genode::Cpu::Context::Context(bool privileged) + +Cpu::Context::Context(bool privileged) { Spsr::El::set(pstate, privileged ? 1 : 0); } -bool Genode::Cpu::active(Mmu_context & mmu_context) +bool Cpu::active(Mmu_context & mmu_context) { return (mmu_context.id() == Ttbr::Asid::get(Ttbr0_el1::read())); } -void Genode::Cpu::switch_to(Mmu_context & mmu_context) +void Cpu::switch_to(Mmu_context & mmu_context) { Ttbr0_el1::write(mmu_context.ttbr); } -void Genode::Cpu::mmu_fault(Genode::Cpu::Context &, - Kernel::Thread_fault & fault) +void Cpu::mmu_fault(Cpu::Context &, Kernel::Thread_fault & fault) { Esr::access_t esr = Esr_el1::read(); @@ -54,57 +55,55 @@ void Genode::Cpu::mmu_fault(Genode::Cpu::Context &, ? Kernel::Thread_fault::WRITE : Kernel::Thread_fault::EXEC; return; default: - Genode::raw("MMU-fault not handled ESR=", Genode::Hex(esr)); + raw("MMU-fault not handled ESR=", Hex(esr)); fault.type = Kernel::Thread_fault::UNKNOWN; }; } -Genode::Cpu::Mmu_context:: -Mmu_context(addr_t table, - Board::Address_space_id_allocator &addr_space_id_alloc) +Cpu::Mmu_context::Mmu_context(addr_t table, + Board::Address_space_id_allocator &id_alloc) : - _addr_space_id_alloc(addr_space_id_alloc), + _addr_space_id_alloc(id_alloc), ttbr(Ttbr::Baddr::masked(table)) { - Ttbr::Asid::set(ttbr, (Genode::uint16_t)_addr_space_id_alloc.alloc()); + Ttbr::Asid::set(ttbr, (uint16_t)_addr_space_id_alloc.alloc()); } -Genode::Cpu::Mmu_context::~Mmu_context() +Cpu::Mmu_context::~Mmu_context() { _addr_space_id_alloc.free(id()); } -Genode::size_t Genode::Cpu::cache_line_size() +size_t Cpu::cache_line_size() { - static Genode::size_t cache_line_size = 0; + static size_t cache_line_size = 0; if (!cache_line_size) { - Genode::size_t i = 1 << Ctr_el0::I_min_line::get(Ctr_el0::read()); - Genode::size_t d = 1 << Ctr_el0::D_min_line::get(Ctr_el0::read()); - cache_line_size = Genode::min(i,d) * 4; /* word size is fixed in ARM */ + size_t i = 1 << Ctr_el0::I_min_line::get(Ctr_el0::read()); + size_t d = 1 << Ctr_el0::D_min_line::get(Ctr_el0::read()); + cache_line_size = min(i,d) * 4; /* word size is fixed in ARM */ } return cache_line_size; } -template -static inline void cache_maintainance(Genode::addr_t const base, - Genode::size_t const size, - FUNC & func) +static inline void cache_maintainance(addr_t const base, + size_t const size, + auto const &fn) { - Genode::addr_t start = (Genode::addr_t) base; - Genode::addr_t const end = base + size; - for (; start < end; start += Genode::Cpu::cache_line_size()) func(start); + /* align the start address to catch all related cache lines */ + addr_t start = (addr_t)base & ~(Cpu::cache_line_size()-1UL); + addr_t const end = base + size; + for (; start < end; start += Cpu::cache_line_size()) fn(start); } -void Genode::Cpu::cache_coherent_region(addr_t const base, - size_t const size) +void Cpu::cache_coherent_region(addr_t const base, size_t const size) { - Genode::memory_barrier(); + memory_barrier(); auto lambda = [] (addr_t const base) { asm volatile("dc cvau, %0" :: "r" (base)); @@ -118,10 +117,10 @@ void Genode::Cpu::cache_coherent_region(addr_t const base, } -void Genode::Cpu::cache_clean_invalidate_data_region(addr_t const base, - size_t const size) +void Cpu::cache_clean_invalidate_data_region(addr_t const base, + size_t const size) { - Genode::memory_barrier(); + memory_barrier(); auto lambda = [] (addr_t const base) { asm volatile("dc civac, %0" :: "r" (base)); }; @@ -133,10 +132,9 @@ void Genode::Cpu::cache_clean_invalidate_data_region(addr_t const base, } -void Genode::Cpu::cache_invalidate_data_region(addr_t const base, - size_t const size) +void Cpu::cache_invalidate_data_region(addr_t const base, size_t const size) { - Genode::memory_barrier(); + memory_barrier(); auto lambda = [] (addr_t const base) { asm volatile("dc ivac, %0" :: "r" (base)); }; @@ -148,11 +146,10 @@ void Genode::Cpu::cache_invalidate_data_region(addr_t const base, } -void Genode::Cpu::clear_memory_region(addr_t const addr, - size_t const size, +void Cpu::clear_memory_region(addr_t const addr, size_t const size, bool changed_cache_properties) { - Genode::memory_barrier(); + memory_barrier(); /* normal memory is cleared by D-cache zeroing */ auto normal = [] (addr_t const base) { diff --git a/repos/base-hw/src/core/spec/arm_v8/cpu.h b/repos/base-hw/src/core/spec/arm_v8/cpu.h index b9ff4dbde6..e4b38183cb 100644 --- a/repos/base-hw/src/core/spec/arm_v8/cpu.h +++ b/repos/base-hw/src/core/spec/arm_v8/cpu.h @@ -21,12 +21,13 @@ /* base internal includes */ #include +/* core includes */ +#include + /* base-hw internal includes */ #include - -/* base-hw Core includes */ #include -#include +#include namespace Kernel { struct Thread_fault; } @@ -34,15 +35,14 @@ namespace Kernel { struct Thread_fault; } namespace Board { class Address_space_id_allocator; } -namespace Genode { +namespace Core { struct Cpu; - using sizet_arithm_t = __uint128_t; - using uint128_t = __uint128_t; + using uint128_t = __uint128_t; } -struct Genode::Cpu : Hw::Arm_64_cpu +struct Core::Cpu : Hw::Arm_64_cpu { enum Exception_entry { SYNC_LEVEL_EL1 = 0x000, @@ -66,16 +66,17 @@ struct Genode::Cpu : Hw::Arm_64_cpu struct alignas(16) Fpu_state { - Genode::uint128_t q[32]; - Genode::uint64_t fpsr; - Genode::uint64_t fpcr; + uint128_t q[32]; + uint64_t fpsr; + uint64_t fpcr; }; struct alignas(16) Context : Cpu_state { - Genode::uint64_t pstate { }; - Genode::uint64_t exception_type { RESET }; - Fpu_state fpu_state { }; + uint64_t pstate { }; + uint64_t mdscr_el1 { }; + uint64_t exception_type { RESET }; + Fpu_state fpu_state { }; Context(bool privileged); }; @@ -95,8 +96,7 @@ struct Genode::Cpu : Hw::Arm_64_cpu ~Mmu_context(); - Genode::uint16_t id() { - return Ttbr::Asid::get(ttbr) & 0xffff; } + uint16_t id() { return Ttbr::Asid::get(ttbr) & 0xffff; } }; bool active(Mmu_context &); @@ -104,6 +104,12 @@ struct Genode::Cpu : Hw::Arm_64_cpu static void mmu_fault(Context &, Kernel::Thread_fault &); + static void single_step(Context ®s, bool on) + { + Cpu::Spsr::Ss::set(regs.pstate, on ? 1 : 0); + Cpu::Mdscr::Ss::set(regs.mdscr_el1, on ? 1 : 0); + }; + /** * Return kernel name of the executing CPU */ diff --git a/repos/base-hw/src/core/spec/arm_v8/crt0.s b/repos/base-hw/src/core/spec/arm_v8/crt0.s index 58cbdc240c..bd32f41265 100644 --- a/repos/base-hw/src/core/spec/arm_v8/crt0.s +++ b/repos/base-hw/src/core/spec/arm_v8/crt0.s @@ -11,6 +11,20 @@ * under the terms of the GNU Affero General Public License version 3. */ +.include "memory_consts.s" + +/** + * Store CPU number in register x0 + */ +.macro _cpu_number + mrs x0, mpidr_el1 + and x8, x0, #(1<<24) /* MT bit */ + cbz x8, 1f + lsr x0, x0, #8 +1: + and x0, x0, #0b11111111 +.endm + .section ".text" /*********************** @@ -21,20 +35,22 @@ _start: /* switch to cpu-specific kernel stack */ - /*adr r1, _kernel_stack - adr r2, _kernel_stack_size - ldr r1, [r1] - ldr r2, [r2] - ldr r2, [r2] - add r0, #1 - mul r0, r0, r2 - add sp, r1, r0*/ + _cpu_number + ldr x1, =_cpus_base + ldr x1, [x1] + mov x2, #HW_MM_CPU_LOCAL_MEMORY_SLOT_SIZE + mul x0, x0, x2 + add x1, x1, x0 + mov x2, #HW_MM_KERNEL_STACK_SIZE + add x1, x1, x2 + mov x2, #0x10 /* minus 16-byte to be aligned in stack */ + sub x1, x1, x2 + mov sp, x1 /* jump into init C code */ b _ZN6Kernel39main_initialize_and_handle_kernel_entryEv - _kernel_stack: .quad kernel_stack - _kernel_stack_size: .quad kernel_stack_size + _cpus_base: .quad HW_MM_CPU_LOCAL_MEMORY_AREA_START /********************************* diff --git a/repos/base-hw/src/core/spec/arm_v8/exception_vector.s b/repos/base-hw/src/core/spec/arm_v8/exception_vector.s index 8236b7feb3..510e4252da 100644 --- a/repos/base-hw/src/core/spec/arm_v8/exception_vector.s +++ b/repos/base-hw/src/core/spec/arm_v8/exception_vector.s @@ -34,11 +34,14 @@ stp x29, x30, [x0], #16 mrs x1, sp_el0 mrs x2, elr_el1 - mrs x3, spsr_el1 - adr x4, . - and x4, x4, #0xf80 + mrs x3, esr_el1 + mrs x4, spsr_el1 + mrs x5, mdscr_el1 + adr x6, . + and x6, x6, #0xf80 stp x1, x2, [x0], #16 stp x3, x4, [x0], #16 + stp x5, x6, [x0], #16 b _kernel_entry .balign 128 .endr @@ -91,11 +94,12 @@ _kernel_entry: mov sp, x1 /* reset stack */ str x0, [sp, #-16] /* store cpu state pointer */ add x1, x0, #8*31 - ldp x2, x3, [x1], #16 /* load sp, ip */ - ldr x4, [x1], #16 /* load pstate */ + ldp x2, x3, [x1], #16+8 /* load sp, ip, skip esr_el1 */ + ldp x4, x5, [x1], #16+8 /* load pstate, mdscr_el1, skip exception_type */ msr sp_el0, x2 msr elr_el1, x3 msr spsr_el1, x4 + msr mdscr_el1, x5 ldp q0, q1, [x1], #32 ldp q2, q3, [x1], #32 ldp q4, q5, [x1], #32 diff --git a/repos/base-hw/src/core/spec/arm_v8/kernel/thread.cc b/repos/base-hw/src/core/spec/arm_v8/kernel/thread.cc index 17e431043c..f4445005e9 100644 --- a/repos/base-hw/src/core/spec/arm_v8/kernel/thread.cc +++ b/repos/base-hw/src/core/spec/arm_v8/kernel/thread.cc @@ -24,6 +24,9 @@ extern "C" void kernel_to_user_context_switch(void *, void *); using namespace Kernel; +void Thread::_call_suspend() { } + + void Thread::exception(Cpu & cpu) { switch (regs->exception_type) { @@ -37,22 +40,25 @@ void Thread::exception(Cpu & cpu) case Cpu::SYNC_LEVEL_EL0: [[fallthrough]]; case Cpu::SYNC_LEVEL_EL1: { - Cpu::Esr::access_t esr = Cpu::Esr_el1::read(); - switch (Cpu::Esr::Ec::get(esr)) { + switch (Cpu::Esr::Ec::get(regs->esr_el1)) { case Cpu::Esr::Ec::SVC: _call(); return; case Cpu::Esr::Ec::INST_ABORT_SAME_LEVEL: [[fallthrough]]; case Cpu::Esr::Ec::DATA_ABORT_SAME_LEVEL: - Genode::raw("Fault in kernel/core ESR=", Genode::Hex(esr)); + Genode::raw("Fault in kernel/core ESR=", Genode::Hex(regs->esr_el1)); [[fallthrough]]; case Cpu::Esr::Ec::INST_ABORT_LOW_LEVEL: [[fallthrough]]; case Cpu::Esr::Ec::DATA_ABORT_LOW_LEVEL: _mmu_exception(); return; + case Cpu::Esr::Ec::SOFTWARE_STEP_LOW_LEVEL: [[fallthrough]]; + case Cpu::Esr::Ec::BRK: + _exception(); + return; default: - Genode::raw("Unknown cpu exception EC=", Cpu::Esr::Ec::get(esr), - " ISS=", Cpu::Esr::Iss::get(esr), + Genode::raw("Unknown cpu exception EC=", Cpu::Esr::Ec::get(regs->esr_el1), + " ISS=", Cpu::Esr::Iss::get(regs->esr_el1), " ip=", (void*)regs->ip); }; @@ -82,7 +88,13 @@ void Thread::exception(Cpu & cpu) * coprocessor registers (there might be ARM SoCs where this is not valid, * with several shareability domains, but until now we do not support them) */ -void Kernel::Thread::Tlb_invalidation::execute() { }; +void Kernel::Thread::Tlb_invalidation::execute(Cpu &) { } + + +void Thread::Flush_and_stop_cpu::execute(Cpu &) { } + + +void Cpu::Halt_job::proceed(Kernel::Cpu &) { } bool Kernel::Pd::invalidate_tlb(Cpu & cpu, addr_t addr, size_t size) diff --git a/repos/base-hw/src/core/spec/arm_v8/pd_session_support.cc b/repos/base-hw/src/core/spec/arm_v8/pd_session_support.cc index c23e68c7ab..3baffd243e 100644 --- a/repos/base-hw/src/core/spec/arm_v8/pd_session_support.cc +++ b/repos/base-hw/src/core/spec/arm_v8/pd_session_support.cc @@ -15,24 +15,51 @@ #include #include -using namespace Genode; +using namespace Core; using State = Genode::Pd_session::Managing_system_state; -State Pd_session_component::managing_system(State const & s) +class System_control_component : public Genode::Rpc_object, + public Core::System_control { - static constexpr addr_t SMCCC_NOT_SUPPORTED = 0xffffffffUL; + public: + State system_control(State const &) override; + + Capability control_cap(Affinity::Location const) const override; +}; + + +State System_control_component::system_control(State const &s) +{ State ret; - ret.r[0] = (_managing_system == Managing_system::DENIED) - ? SMCCC_NOT_SUPPORTED - : Hw::Psci_smc_functor::call(s.r[0], s.r[1], s.r[2], s.r[3]); + ret.r[0] = Hw::Psci_smc_functor::call(s.r[0], s.r[1], s.r[2], s.r[3]); return ret; } +static System_control_component &system_instance() +{ + static System_control_component system_component { }; + return system_component; +} + + +System_control & Core::init_system_control(Allocator &, Rpc_entrypoint &ep) +{ + ep.manage(&system_instance()); + return system_instance(); +} + + +Capability System_control_component::control_cap(Affinity::Location const) const +{ + return system_instance().cap(); +} + + /*************************** ** Dummy implementations ** ***************************/ @@ -40,5 +67,8 @@ State Pd_session_component::managing_system(State const & s) bool Pd_session_component::assign_pci(addr_t, uint16_t) { return true; } -void Pd_session_component::map(addr_t, addr_t) { } +Pd_session::Map_result Pd_session_component::map(Pd_session::Virt_range) +{ + return Map_result::OK; +} diff --git a/repos/base-hw/src/core/spec/arm_v8/translation_table.h b/repos/base-hw/src/core/spec/arm_v8/translation_table.h deleted file mode 100644 index 56fb10f856..0000000000 --- a/repos/base-hw/src/core/spec/arm_v8/translation_table.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * \brief Translation table definitions for core - * \author Stefan Kalkowski - * \date 2019-05-10 - */ - -/* - * Copyright (C) 2019 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _CORE__SPEC__ARM_V8__TRANSLATION_TABLE_H_ -#define _CORE__SPEC__ARM_V8__TRANSLATION_TABLE_H_ - -/* core includes */ -#include - -#endif /* _CORE__SPEC__ARM_V8__TRANSLATION_TABLE_H_ */ diff --git a/repos/base-hw/src/core/spec/arm_v8/virtualization/exception_vector.s b/repos/base-hw/src/core/spec/arm_v8/virtualization/exception_vector.s index a159d81c34..7d74b1dfae 100644 --- a/repos/base-hw/src/core/spec/arm_v8/virtualization/exception_vector.s +++ b/repos/base-hw/src/core/spec/arm_v8/virtualization/exception_vector.s @@ -27,7 +27,7 @@ hypervisor_exception_vector: mrs x30, hcr_el2 /* read HCR register */ tst x30, #1 /* check VM bit */ beq _from_host /* if VM bit is not set, its a host call */ - ldr x29, [sp, #32] /* otherwise, load vm_state pointer */ + ldr x29, [sp, #32] /* otherwise, load vcpu_state pointer */ adr x30, . /* hold exception vector offset in x30 */ and x30, x30, #0xf80 b _from_vm @@ -53,15 +53,19 @@ _to_vm: add x0, x0, #31*8 /* skip x0...x30, loaded later */ - ldr x1, [x0], #1*8 /* sp */ - ldp x2, x3, [x0], #2*8 /* ip, pstate */ + ldp x1, x2, [x0], #2*8 /* sp, ip */ + ldp x3, x4, [x0], #2*8 /* esr_el1, pstate */ msr sp_el0, x1 msr elr_el2, x2 - msr spsr_el2, x3 + msr esr_el1, x3 + msr spsr_el2, x4 add x0, x0, #2*8 /* skip exception_type and esr_el2 */ /** FPU register **/ + ldp w1, w2, [x0], #2*4 + msr fpcr, x1 + msr fpsr, x2 ldp q0, q1, [x0], #2*16 ldp q2, q3, [x0], #2*16 ldp q4, q5, [x0], #2*16 @@ -78,45 +82,40 @@ _to_vm: ldp q26, q27, [x0], #2*16 ldp q28, q29, [x0], #2*16 ldp q30, q31, [x0], #2*16 - ldp w1, w2, [x0], #2*4 - msr fpcr, x1 - msr fpsr, x2 /** system register **/ ldp x1, x2, [x0], #2*8 /* elr_el1, sp_el1 */ - ldp w3, w4, [x0], #2*4 /* spsr_el1, esr_el1 */ - ldp x5, x6, [x0], #2*8 /* sctlr_el1, actlr_el1 */ - ldr x7, [x0], #8 /* vbar_el1 */ - ldp w8, w9, [x0], #2*4 /* cpacr_el1, afsr0_el1 */ - ldp w10, w11, [x0], #2*4 /* afsr1_el1, contextidr_el1 */ - ldp x12, x13, [x0], #2*8 /* ttbr0_el1, ttbr1_el1 */ - ldp x14, x15, [x0], #2*8 /* tcr_el1, mair_el1 */ - ldp x16, x17, [x0], #2*8 /* amair_el1, far_el1 */ - ldp x18, x19, [x0], #2*8 /* par_el1, tpidrro_el0 */ - ldp x20, x21, [x0], #2*8 /* tpidr_el0, tpidr_el1 */ - ldr x22, [x0], #3*8 /* vmpidr_el2 */ + ldp x3, x4, [x0], #2*8 /* spsr_el1, sctlr_el1 */ + ldp x5, x6, [x0], #2*8 /* actlr_el1, vbar_el1 */ + ldp w7, w8, [x0], #2*4 /* cpacr_el1, afsr0_el1 */ + ldp w9, w10, [x0], #2*4 /* afsr1_el1, contextidr_el1 */ + ldp x11, x12, [x0], #2*8 /* ttbr0_el1, ttbr1_el1 */ + ldp x13, x14, [x0], #2*8 /* tcr_el1, mair_el1 */ + ldp x15, x16, [x0], #2*8 /* amair_el1, far_el1 */ + ldp x17, x18, [x0], #2*8 /* par_el1, tpidrro_el0 */ + ldp x19, x20, [x0], #2*8 /* tpidr_el0, tpidr_el1 */ + ldr x21, [x0], #3*8 /* vmpidr_el2 */ msr elr_el1, x1 msr sp_el1, x2 msr spsr_el1, x3 - msr esr_el1, x4 - msr sctlr_el1, x5 - msr actlr_el1, x6 - msr vbar_el1, x7 - msr cpacr_el1, x8 - msr afsr0_el1, x9 - msr afsr1_el1, x10 - msr contextidr_el1, x11 - msr ttbr0_el1, x12 - msr ttbr1_el1, x13 - msr tcr_el1, x14 - msr mair_el1, x15 - msr amair_el1, x16 - msr far_el1, x17 - msr par_el1, x18 - msr tpidrro_el0, x19 - msr tpidr_el0, x20 - msr tpidr_el1, x21 - msr vmpidr_el2, x22 + msr sctlr_el1, x4 + msr actlr_el1, x5 + msr vbar_el1, x6 + msr cpacr_el1, x7 + msr afsr0_el1, x8 + msr afsr1_el1, x9 + msr contextidr_el1, x10 + msr ttbr0_el1, x11 + msr ttbr1_el1, x12 + msr tcr_el1, x13 + msr mair_el1, x14 + msr amair_el1, x15 + msr far_el1, x16 + msr par_el1, x17 + msr tpidrro_el0, x18 + msr tpidr_el0, x19 + msr tpidr_el1, x20 + msr vmpidr_el2, x21 /********************** @@ -167,7 +166,7 @@ _to_vm: orr x0, x0, x1 msr hcr_el2, x0 - ldr x30, [sp, #16] /* load head of Vm_state again */ + ldr x30, [sp, #16] /* load head of Vcpu_state again */ /** general-purpose registers **/ ldp x0, x1, [x30], #2*8 @@ -224,16 +223,20 @@ _from_vm: stp x28, x29, [x0], #2*8 str x30, [x0], #1*8 - /** save sp, ip, pstate and exception reason **/ + /** save sp, ip, esr_el1, pstate and exception reason **/ mrs x2, sp_el0 mrs x3, elr_el2 - mrs x4, spsr_el2 - mrs x5, esr_el2 - stp x2, x3, [x0], #2*8 - stp x4, x1, [x0], #2*8 - str x5, [x0], #1*8 + mrs x4, esr_el1 + mrs x5, spsr_el2 + mrs x6, esr_el2 + stp x2, x3, [x0], #2*8 /* sp, ip */ + stp x4, x5, [x0], #2*8 /* esr_el1, pstate */ + stp x1, x6, [x0], #2*8 /* exception_type, esr_el2 */ /** fpu registers **/ + mrs x1, fpcr + mrs x2, fpsr + stp w1, w2, [x0], #2*4 stp q0, q1, [x0], #32 stp q2, q3, [x0], #32 stp q4, q5, [x0], #32 @@ -251,56 +254,51 @@ _from_vm: stp q28, q29, [x0], #32 stp q30, q31, [x0], #32 - mrs x1, fpcr - mrs x2, fpsr mrs x3, elr_el1 mrs x4, sp_el1 mrs x5, spsr_el1 - mrs x6, esr_el1 - mrs x7, sctlr_el1 - mrs x8, actlr_el1 - mrs x9, vbar_el1 - mrs x10, cpacr_el1 - mrs x11, afsr0_el1 - mrs x12, afsr1_el1 - mrs x13, contextidr_el1 - mrs x14, ttbr0_el1 - mrs x15, ttbr1_el1 - mrs x16, tcr_el1 - mrs x17, mair_el1 - mrs x18, amair_el1 - mrs x19, far_el1 - mrs x20, par_el1 - mrs x21, tpidrro_el0 - mrs x22, tpidr_el0 - mrs x23, tpidr_el1 - mrs x24, far_el2 - mrs x25, hpfar_el2 - stp w1, w2, [x0], #2*4 + mrs x6, sctlr_el1 + mrs x7, actlr_el1 + mrs x8, vbar_el1 + mrs x9, cpacr_el1 + mrs x10, afsr0_el1 + mrs x11, afsr1_el1 + mrs x12, contextidr_el1 + mrs x13, ttbr0_el1 + mrs x14, ttbr1_el1 + mrs x15, tcr_el1 + mrs x16, mair_el1 + mrs x17, amair_el1 + mrs x18, far_el1 + mrs x19, par_el1 + mrs x20, tpidrro_el0 + mrs x21, tpidr_el0 + mrs x22, tpidr_el1 + mrs x23, far_el2 + mrs x24, hpfar_el2 stp x3, x4, [x0], #2*8 - stp w5, w6, [x0], #2*4 + stp x5, x6, [x0], #2*8 stp x7, x8, [x0], #2*8 - str x9, [x0], #1*8 - stp w10, w11, [x0], #2*4 - stp w12, w13, [x0], #2*4 - stp x14, x15, [x0], #2*8 - stp x16, x17, [x0], #2*8 - stp x18, x19, [x0], #2*8 - stp x20, x21, [x0], #2*8 - stp x22, x23, [x0], #3*8 - stp x24, x25, [x0], #2*8 + stp w9, w10, [x0], #2*4 + stp w11, w12, [x0], #2*4 + stp x13, x14, [x0], #2*8 + stp x15, x16, [x0], #2*8 + stp x17, x18, [x0], #2*8 + stp x19, x20, [x0], #2*8 + stp x21, x22, [x0], #3*8 + stp x23, x24, [x0], #2*8 /********************** ** save timer state ** **********************/ - mrs x26, cntvoff_el2 - mrs x27, cntv_cval_el0 - mrs x28, cntv_ctl_el0 - mrs x29, cntkctl_el1 - stp x26, x27, [x0], #2*8 - stp w28, w29, [x0] + mrs x25, cntvoff_el2 + mrs x26, cntv_cval_el0 + mrs x27, cntv_ctl_el0 + mrs x28, cntkctl_el1 + stp x25, x26, [x0], #2*8 + stp w27, w28, [x0] mov x0, #0b111 msr cnthctl_el2, x0 @@ -332,17 +330,19 @@ _from_vm: ** Load host context ** ***********************/ - add x30, x30, #32*8 /* skip general-purpose regs, sp */ - ldp x0, x1, [x30] /* host state ip, and pstate */ - add x30, x30, #34*16 /* skip fpu regs etc. */ - ldp w2, w3, [x30], #4*4 /* fpcr and fpsr */ - ldr x4, [x30], #2*8 /* sp_el1 */ - ldp x5, x6, [x30], #2*8 /* sctlr_el1, actlr_el1 */ - ldr x7, [x30], #1*8 /* vbar_el1 */ - ldr w8, [x30], #4*4 /* cpacr_el1 */ - ldp x9, x10, [x30], #2*8 /* ttbr0_el1, ttbr1_el1 */ - ldp x11, x12, [x30], #2*8 /* tcr_el1, mair_el1 */ - ldr x13, [x30] /* amair_el1 */ + add x30, x30, #32*8 /* skip general-purpose regs, sp */ + ldr x0, [x30], #2*8 /* host state ip, skip esr_el1 */ + ldr x1, [x30], #3*8 /* host state pstate, + skip exception_type and esr_el2 */ + ldp w2, w3, [x30], #2*4 /* fpcr and fpsr */ + add x30, x30, #32*16+8 /* skip remaining fpu regs and elr_el1 */ + ldr x4, [x30], #2*8 /* sp_el1 */ + ldp x5, x6, [x30], #2*8 /* sctlr_el1, actlr_el1 */ + ldr x7, [x30], #1*8 /* vbar_el1 */ + ldr w8, [x30], #4*4 /* cpacr_el1 */ + ldp x9, x10, [x30], #2*8 /* ttbr0_el1, ttbr1_el1 */ + ldp x11, x12, [x30], #2*8 /* tcr_el1, mair_el1 */ + ldr x13, [x30] /* amair_el1 */ msr elr_el2, x0 msr spsr_el2, x1 diff --git a/repos/base-hw/src/core/spec/arm_v8/virtualization/kernel/vm.cc b/repos/base-hw/src/core/spec/arm_v8/virtualization/kernel/vm.cc index 30b6962865..511a0e99a1 100644 --- a/repos/base-hw/src/core/spec/arm_v8/virtualization/kernel/vm.cc +++ b/repos/base-hw/src/core/spec/arm_v8/virtualization/kernel/vm.cc @@ -1,18 +1,18 @@ /* - * \brief Kernel backend for virtual machines - * \author Stefan Kalkowski - * \date 2015-02-10 + * \brief Kernel backend for virtual machines + * \author Stefan Kalkowski + * \author Benjamin Lamowski + * \date 2015-02-10 */ /* - * Copyright (C) 2015-2017 Genode Labs GmbH + * Copyright (C) 2015-2023 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. */ -#include -#include +#include #include #include @@ -30,13 +30,14 @@ using Kernel::Cpu; using Kernel::Vm; -static Genode::Vm_state & host_context(Cpu & cpu) +static Genode::Vcpu_state & host_context(Cpu & cpu) { - static Genode::Constructible host_context[NR_OF_CPUS]; + static Genode::Constructible + host_context[Board::NR_OF_CPUS]; if (!host_context[cpu.id()].constructed()) { host_context[cpu.id()].construct(); - Genode::Vm_state & c = *host_context[cpu.id()]; + Genode::Vcpu_state & c = *host_context[cpu.id()]; c.sp_el1 = cpu.stack_start(); c.ip = (addr_t)&Kernel::main_handle_kernel_entry; c.pstate = 0; @@ -109,14 +110,14 @@ void Board::Vcpu_context::Virtual_timer_irq::disable() Vm::Vm(Irq::Pool & user_irq_pool, Cpu & cpu, - Genode::Vm_state & state, + Genode::Vcpu_data & data, Kernel::Signal_context & context, Identity & id) : Kernel::Object { *this }, - Cpu_job(Cpu_priority::min(), 0), + Cpu_job(Scheduler::Priority::min(), 0), _user_irq_pool(user_irq_pool), - _state(state), + _state(data), _context(context), _id(id), _vcpu_context(cpu) @@ -149,6 +150,11 @@ Vm::Vm(Irq::Pool & user_irq_pool, _state.ccsidr_data_el1[level] = Cpu::Ccsidr_el1::read(); } } + + /* once constructed, exit with a startup exception */ + pause(); + _state.exception_type = Genode::VCPU_EXCEPTION_STARTUP; + _context.submit(1); } @@ -208,6 +214,14 @@ void Vm::proceed(Cpu & cpu) } +void Vm::_sync_to_vmm() +{} + + +void Vm::_sync_from_vmm() +{} + + void Vm::inject_irq(unsigned irq) { _state.irqs.last_irq = irq; diff --git a/repos/base-hw/src/core/spec/cortex_a15/cpu.cc b/repos/base-hw/src/core/spec/cortex_a15/cpu.cc deleted file mode 100644 index 7a582d49ef..0000000000 --- a/repos/base-hw/src/core/spec/cortex_a15/cpu.cc +++ /dev/null @@ -1,54 +0,0 @@ -/* - * \brief Cortex A15 specific MMU context initialization - * \author Stefan Kalkowski - * \date 2017-10-17 - */ - -/* - * Copyright (C) 2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -/* base-hw Core includes */ -#include -#include - - -Genode::Cpu::Mmu_context:: -Mmu_context(addr_t table, - Board::Address_space_id_allocator &addr_space_id_alloc) -: - _addr_space_id_alloc(addr_space_id_alloc), - ttbr0(Ttbr_64bit::Ba::masked((Ttbr_64bit::access_t)table)) -{ - Ttbr_64bit::Asid::set(ttbr0, (Genode::uint8_t)addr_space_id_alloc.alloc()); -} - - -Genode::Cpu::Mmu_context::~Mmu_context() -{ - /* flush TLB by ASID */ - Cpu::Tlbiasid::write(id()); - _addr_space_id_alloc.free(id()); -} - - -void Genode::Cpu::mmu_fault_status(Genode::Cpu::Fsr::access_t fsr, - Kernel::Thread_fault & fault) -{ - enum { - FAULT_MASK = 0b111100, - TRANSLATION = 0b000100, - PERMISSION = 0b001100, - }; - - using Fault = Kernel::Thread_fault; - - switch(fsr & FAULT_MASK) { - case TRANSLATION: fault.type = Fault::PAGE_MISSING; return; - case PERMISSION: fault.type = Fault::EXEC; return; - default: fault.type = Fault::UNKNOWN; - }; -}; diff --git a/repos/base-hw/src/core/spec/cortex_a15/cpu.h b/repos/base-hw/src/core/spec/cortex_a15/cpu.h deleted file mode 100644 index ca1a447ec2..0000000000 --- a/repos/base-hw/src/core/spec/cortex_a15/cpu.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * \brief CPU driver for core - * \author Martin stein - * \author Stefan Kalkowski - * \date 2011-11-03 - */ - -/* - * Copyright (C) 2011-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _CORE__SPEC__CORTEX_A15__CPU_H_ -#define _CORE__SPEC__CORTEX_A15__CPU_H_ - -/* base-hw Core includes */ -#include -#include - -namespace Genode { class Cpu; } - - -class Genode::Cpu : public Arm_v7_cpu -{ - public: - - /********************************* - ** Virtualization extensions ** - *********************************/ - - /** - * Hypervisor system trap register - */ - struct Hstr : Register<32> - { - /* System coprocessor primary register access trap */ - template - struct T : Bitfield {}; - - static access_t init() - { - /* - * allow everything except c0, c11, c12, and c15 accesses. - */ - access_t v = 0; - T<0>::set(v, 1); - T<11>::set(v, 1); - T<12>::set(v, 1); - T<15>::set(v, 1); - return v; - }; - }; - - /** - * Hypervisor control register - */ - struct Hcr : Register<32> - { - struct Vm : Bitfield<0, 1> {}; /* VT MMU enabled */ - struct Fmo : Bitfield<3, 1> {}; /* FIQ cannot been masked */ - struct Imo : Bitfield<4, 1> {}; /* IRQ cannot been masked */ - struct Amo : Bitfield<5, 1> {}; /* A bit cannot been masked */ - struct Twi : Bitfield<13, 1> {}; /* trap on WFI instruction */ - struct Twe : Bitfield<14, 1> {}; /* trap on WFE instruction */ - struct Tidcp : Bitfield<20, 1> {}; /* trap lockdown */ - struct Tac : Bitfield<21, 1> {}; /* trap ACTLR accesses */ - - static access_t init() - { - access_t v = 0; - Vm::set(v, 1); - Fmo::set(v, 1); - Imo::set(v, 1); - Amo::set(v, 1); - Twi::set(v, 1); - Twe::set(v, 1); - Tidcp::set(v, 1); - Tac::set(v, 1); - return v; - }; - }; - - - /** - * An usermode execution state - */ - class Mmu_context - { - private: - - Board::Address_space_id_allocator &_addr_space_id_alloc; - - public: - - Ttbr_64bit::access_t ttbr0; - - Mmu_context(addr_t table, - Board::Address_space_id_allocator &addr_space_id_alloc); - - ~Mmu_context(); - - Genode::uint8_t id() const - { - return Ttbr_64bit::Asid::get(ttbr0); - } - }; - - static void mmu_fault_status(Fsr::access_t fsr, - Kernel::Thread_fault & fault); - - /** - * Return kernel name of the executing CPU - */ - static unsigned executing_id() { return Mpidr::Aff_0::get(Mpidr::read()); } - - bool active(Mmu_context & mmu_context) - { - return (Ttbr0_64bit::read() == mmu_context.ttbr0); - } - - void switch_to(Mmu_context & mmu_context) - { - Ttbr0_64bit::write(mmu_context.ttbr0); - } -}; - -#endif /* _CORE__SPEC__CORTEX_A15__CPU_H_ */ diff --git a/repos/base-hw/src/core/spec/cortex_a15/translation_table.h b/repos/base-hw/src/core/spec/cortex_a15/translation_table.h deleted file mode 100644 index 3f67ed4f82..0000000000 --- a/repos/base-hw/src/core/spec/cortex_a15/translation_table.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * \brief Translation table definitions for core - * \author Stefan Kalkowski - * \date 2015-01-30 - */ - -/* - * Copyright (C) 2015-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _CORE__SPEC__CORTEX_A15__TRANSLATION_TABLE_H_ -#define _CORE__SPEC__CORTEX_A15__TRANSLATION_TABLE_H_ - -/* core includes */ -#include - -#endif /* _CORE__SPEC__CORTEX_A15__TRANSLATION_TABLE_H_ */ diff --git a/repos/base-hw/src/core/spec/cortex_a8/cpu.h b/repos/base-hw/src/core/spec/cortex_a8/cpu.h deleted file mode 100644 index b59b787248..0000000000 --- a/repos/base-hw/src/core/spec/cortex_a8/cpu.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * \brief ARM Cortex A8 CPU driver for core - * \author Martin stein - * \author Stefan Kalkowski - * \date 2011-11-03 - */ - -/* - * Copyright (C) 2011-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _CORE__SPEC__CORTEX_A8__CPU_H_ -#define _CORE__SPEC__CORTEX_A8__CPU_H_ - -/* base-hw Core includes */ -#include -#include - -namespace Genode { using Cpu = Arm_v7_cpu; } - -#endif /* _CORE__SPEC__CORTEX_A8__CPU_H_ */ diff --git a/repos/base-hw/src/core/spec/cortex_a8/translation_table.h b/repos/base-hw/src/core/spec/cortex_a8/translation_table.h deleted file mode 100644 index 1898f5261f..0000000000 --- a/repos/base-hw/src/core/spec/cortex_a8/translation_table.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * \brief Translation table definitions for core - * \author Martin Stein - * \author Stefan Kalkowski - * \date 2012-02-22 - */ - -/* - * Copyright (C) 2012-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _CORE__SPEC__CORTEX_A8__TRANSLATION_TABLE_H_ -#define _CORE__SPEC__CORTEX_A8__TRANSLATION_TABLE_H_ - -/* base-hw internal includes */ -#include - -/* base-hw Core includes */ -#include - - -constexpr unsigned Hw::Page_table::Descriptor_base::_device_tex() { - return 2; } - - -constexpr bool Hw::Page_table::Descriptor_base::_smp() { return false; } - - -void Hw::Page_table::_table_changed(unsigned long addr, unsigned long size) -{ - /* - * The Cortex-A8 CPU can't use the L1 cache on page-table - * walks. Therefore, as the page-tables lie in write-back cacheable - * memory we've to clean the corresponding cache-lines even when a - * page table entry is added. We only do this as core as the kernel - * adds translations solely before MMU and caches are enabled. - */ - Genode::Arm_cpu::cache_clean_data_region(addr, size); -} - -#endif /* _CORE__SPEC__CORTEX_A8__TRANSLATION_TABLE_H_ */ diff --git a/repos/base-hw/src/core/spec/cortex_a9/board.cc b/repos/base-hw/src/core/spec/cortex_a9/board.cc deleted file mode 100644 index c0dcf9b7dd..0000000000 --- a/repos/base-hw/src/core/spec/cortex_a9/board.cc +++ /dev/null @@ -1,24 +0,0 @@ -/* - * \brief Board implementation specific to Cortex A9 - * \author Stefan Kalkowski - * \date 2016-01-07 - */ - -/* - * Copyright (C) 2016-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#include -#include - - -Board::L2_cache & Board::l2_cache() -{ - using namespace Genode; - - static L2_cache cache(Platform::mmio_to_virt(Board::PL310_MMIO_BASE)); - return cache; -} diff --git a/repos/base-hw/src/core/spec/cortex_a9/cpu.cc b/repos/base-hw/src/core/spec/cortex_a9/cpu.cc deleted file mode 100644 index 0272eb5d6a..0000000000 --- a/repos/base-hw/src/core/spec/cortex_a9/cpu.cc +++ /dev/null @@ -1,25 +0,0 @@ -/* - * \brief CPU driver for core - * \author Martin stein - * \author Stefan Kalkowski - * \date 2011-11-03 - */ - -/* - * Copyright (C) 2011-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -/* base-hw Core includes */ -#include -#include - - -void Genode::Cpu::cache_clean_invalidate_data_region(addr_t const base, - size_t const size) -{ - Arm_cpu::cache_clean_invalidate_data_region(base, size); - Board::l2_cache().clean_invalidate(); -} diff --git a/repos/base-hw/src/core/spec/cortex_a9/cpu.h b/repos/base-hw/src/core/spec/cortex_a9/cpu.h deleted file mode 100644 index 18fe5c246d..0000000000 --- a/repos/base-hw/src/core/spec/cortex_a9/cpu.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * \brief CPU driver for core - * \author Martin stein - * \author Stefan Kalkowski - * \date 2011-11-03 - */ - -/* - * Copyright (C) 2011-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _CORE__SPEC__CORTEX_A9__CPU_H_ -#define _CORE__SPEC__CORTEX_A9__CPU_H_ - -/* base-hw Core includes */ -#include -#include - -namespace Genode { struct Cpu; } - - -struct Genode::Cpu : Arm_v7_cpu -{ - /** - * Clean and invalidate data-cache for virtual region - * 'base' - 'base + size' - */ - static void cache_clean_invalidate_data_region(addr_t const base, - size_t const size); - - static unsigned executing_id() { return Mpidr::Aff_0::get(Mpidr::read()); } -}; - -#endif /* _CORE__SPEC__CORTEX_A9__CPU_H_ */ diff --git a/repos/base-hw/src/core/spec/cortex_a9/translation_table.h b/repos/base-hw/src/core/spec/cortex_a9/translation_table.h deleted file mode 100644 index 14201acffc..0000000000 --- a/repos/base-hw/src/core/spec/cortex_a9/translation_table.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * \brief Translation table definitions for core - * \author Martin Stein - * \author Stefan Kalkowski - * \date 2012-02-22 - */ - -/* - * Copyright (C) 2012-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _CORE__SPEC__CORTEX_A9__TRANSLATION_TABLE_H_ -#define _CORE__SPEC__CORTEX_A9__TRANSLATION_TABLE_H_ - -#include - - -constexpr unsigned Hw::Page_table::Descriptor_base::_device_tex() { - return 2; } - - -constexpr bool Hw::Page_table::Descriptor_base::_smp() { return true; } - - -void Hw::Page_table::_table_changed(unsigned long, unsigned long) { } - -#endif /* _CORE__SPEC__CORTEX_A9__TRANSLATION_TABLE_H_ */ diff --git a/repos/base-hw/src/core/spec/riscv/cpu.cc b/repos/base-hw/src/core/spec/riscv/cpu.cc index e2e77f2aa5..df9495c743 100644 --- a/repos/base-hw/src/core/spec/riscv/cpu.cc +++ b/repos/base-hw/src/core/spec/riscv/cpu.cc @@ -15,15 +15,17 @@ /* base-hw internal includes */ #include -/* base-hw Core includes */ +/* base-hw core includes */ #include #include #include -using Mmu_context = Genode::Cpu::Mmu_context; +using Mmu_context = Core::Cpu::Mmu_context; + +using namespace Core; -Genode::Cpu::Context::Context(bool) +Cpu::Context::Context(bool) { /* * initialize cpu_exception with something that gets ignored in @@ -33,13 +35,12 @@ Genode::Cpu::Context::Context(bool) } -Mmu_context:: -Mmu_context(addr_t page_table_base, - Board::Address_space_id_allocator &addr_space_id_alloc) +Mmu_context::Mmu_context(addr_t page_table_base, + Board::Address_space_id_allocator &id_alloc) : - _addr_space_id_alloc(addr_space_id_alloc) + _addr_space_id_alloc(id_alloc) { - Satp::Asid::set(satp, (Genode::uint8_t)_addr_space_id_alloc.alloc()); + Satp::Asid::set(satp, (uint8_t)_addr_space_id_alloc.alloc()); Satp::Ppn::set(satp, page_table_base >> 12); Satp::Mode::set(satp, 8); } @@ -53,31 +54,30 @@ Mmu_context::~Mmu_context() } -bool Genode::Cpu::active(Mmu_context & context) +bool Cpu::active(Mmu_context &context) { return Satp::read() == context.satp; } -void Genode::Cpu::switch_to(Mmu_context & context) +void Cpu::switch_to(Mmu_context &context) { Satp::write(context.satp); sfence(); } -void Genode::Cpu::mmu_fault(Context &, Kernel::Thread_fault & f) +void Cpu::mmu_fault(Context &, Kernel::Thread_fault &f) { - f.addr = Genode::Cpu::Stval::read(); + f.addr = Cpu::Stval::read(); f.type = Kernel::Thread_fault::PAGE_MISSING; } -void Genode::Cpu::clear_memory_region(addr_t const addr, - size_t const size, bool) +void Cpu::clear_memory_region(addr_t const addr, size_t const size, bool) { memset((void*)addr, 0, size); /* FIXME: is this really necessary? */ - Genode::Cpu::sfence(); + Cpu::sfence(); } diff --git a/repos/base-hw/src/core/spec/riscv/cpu.h b/repos/base-hw/src/core/spec/riscv/cpu.h index d719abcb1c..40db57db70 100644 --- a/repos/base-hw/src/core/spec/riscv/cpu.h +++ b/repos/base-hw/src/core/spec/riscv/cpu.h @@ -26,7 +26,8 @@ #include #include -/* base-hw Core includes */ +/* base-hw core includes */ +#include #include #include @@ -36,25 +37,23 @@ namespace Kernel { struct Thread_fault; } namespace Board { class Address_space_id_allocator; } -namespace Genode { +namespace Core { /** * CPU driver for core */ class Cpu; - - typedef __uint128_t sizet_arithm_t; } namespace Kernel { class Pd; } -class Genode::Cpu : public Hw::Riscv_cpu +class Core::Cpu : public Hw::Riscv_cpu { public: - struct alignas(8) Context : Cpu_state + struct alignas(8) Context : Genode::Cpu_state { Context(bool); }; @@ -69,8 +68,7 @@ class Genode::Cpu : public Hw::Riscv_cpu Satp::access_t satp = 0; - Mmu_context(addr_t page_table_base, - Board::Address_space_id_allocator &addr_space_id_alloc); + Mmu_context(addr_t page_table_base, Board::Address_space_id_allocator &); ~Mmu_context(); }; @@ -101,6 +99,8 @@ class Genode::Cpu : public Hw::Riscv_cpu void switch_to(Mmu_context & context); static void mmu_fault(Context & c, Kernel::Thread_fault & f); + static void single_step(Context &, bool) { }; + static unsigned executing_id() { return 0; } static void clear_memory_region(addr_t const addr, @@ -112,7 +112,7 @@ class Genode::Cpu : public Hw::Riscv_cpu template void Sv39::Level_x_translation_table::_translation_added(addr_t, size_t) { - Genode::Cpu::sfence(); + Core::Cpu::sfence(); } diff --git a/repos/base-hw/src/core/spec/riscv/crt0.s b/repos/base-hw/src/core/spec/riscv/crt0.s index b106768555..b73b88472c 100644 --- a/repos/base-hw/src/core/spec/riscv/crt0.s +++ b/repos/base-hw/src/core/spec/riscv/crt0.s @@ -11,6 +11,8 @@ * under the terms of the GNU Affero General Public License version 3. */ +.include "memory_consts.s" + .section ".text" /*********************** @@ -20,9 +22,10 @@ .global _start _start: - la x29, kernel_stack - la x30, kernel_stack_size - ld x30, (x30) + li x29, HW_MM_CPU_LOCAL_MEMORY_AREA_START + li x30, HW_MM_CPU_LOCAL_MEMORY_SLOT_STACK_OFFSET + add x29, x29, x30 + li x30, HW_MM_KERNEL_STACK_SIZE add sp, x29, x30 la x30, _ZN6Kernel39main_initialize_and_handle_kernel_entryEv diff --git a/repos/base-hw/src/core/spec/riscv/exception_vector.s b/repos/base-hw/src/core/spec/riscv/exception_vector.s index d70e238a9e..6163251dd2 100644 --- a/repos/base-hw/src/core/spec/riscv/exception_vector.s +++ b/repos/base-hw/src/core/spec/riscv/exception_vector.s @@ -12,6 +12,8 @@ * under the terms of the GNU Affero General Public License version 3. */ +.include "memory_consts.s" + .set CPU_IP, 0 .set CPU_EXCEPTION, 8 .set CPU_X1, 2*8 @@ -45,9 +47,10 @@ _kernel_entry: csrr x30, sscratch sd x30, CPU_X1 + 8 * 30(x31) - la x29, kernel_stack - la x30, kernel_stack_size - ld x30, (x30) + li x29, HW_MM_CPU_LOCAL_MEMORY_AREA_START + li x30, HW_MM_CPU_LOCAL_MEMORY_SLOT_STACK_OFFSET + add x29, x29, x30 + li x30, HW_MM_KERNEL_STACK_SIZE add sp, x29, x30 la x30, _ZN6Kernel24main_handle_kernel_entryEv diff --git a/repos/base-hw/src/core/spec/riscv/kernel/interface.cc b/repos/base-hw/src/core/spec/riscv/kernel/interface.cc index 5e2d2f3d11..65691bf312 100644 --- a/repos/base-hw/src/core/spec/riscv/kernel/interface.cc +++ b/repos/base-hw/src/core/spec/riscv/kernel/interface.cc @@ -21,7 +21,6 @@ /* Genode includes */ #include -#include #include using namespace Kernel; diff --git a/repos/base-hw/src/core/spec/riscv/kernel/pd.cc b/repos/base-hw/src/core/spec/riscv/kernel/pd.cc index 8f7d00d38f..d2396b990b 100644 --- a/repos/base-hw/src/core/spec/riscv/kernel/pd.cc +++ b/repos/base-hw/src/core/spec/riscv/kernel/pd.cc @@ -16,7 +16,7 @@ bool Kernel::Pd::invalidate_tlb(Kernel::Cpu&, addr_t, size_t) { - Genode::Cpu::sfence(); + Core::Cpu::sfence(); return false; } diff --git a/repos/base-hw/src/core/spec/riscv/kernel/thread.cc b/repos/base-hw/src/core/spec/riscv/kernel/thread.cc index 10814fde15..fbbd300cc6 100644 --- a/repos/base-hw/src/core/spec/riscv/kernel/thread.cc +++ b/repos/base-hw/src/core/spec/riscv/kernel/thread.cc @@ -19,13 +19,19 @@ using namespace Kernel; -void Thread::Tlb_invalidation::execute() {} +void Thread::Tlb_invalidation::execute(Cpu &) { } + + +void Thread::Flush_and_stop_cpu::execute(Cpu &) { } + + +void Cpu::Halt_job::proceed(Kernel::Cpu &) { } void Thread::exception(Cpu & cpu) { - using Context = Genode::Cpu::Context; - using Stval = Genode::Cpu::Stval; + using Context = Core::Cpu::Context; + using Stval = Core::Cpu::Stval; if (regs->is_irq()) { /* cpu-local timer interrupt */ @@ -83,12 +89,15 @@ void Thread::exception(Cpu & cpu) default: Genode::raw(*this, ": unhandled exception ", regs->cpu_exception, " at ip=", (void*)regs->ip, - " addr=", Genode::Hex(Genode::Cpu::Stval::read())); + " addr=", Genode::Hex(Core::Cpu::Stval::read())); _die(); } } +void Thread::_call_suspend() { } + + void Thread::_call_cache_coherent_region() { } @@ -98,6 +107,12 @@ void Kernel::Thread::_call_cache_clean_invalidate_data_region() { } void Kernel::Thread::_call_cache_invalidate_data_region() { } +void Kernel::Thread::_call_cache_line_size() +{ + user_arg_0(0); +} + + void Kernel::Thread::proceed(Cpu & cpu) { /* diff --git a/repos/base-hw/src/core/spec/riscv/pic.cc b/repos/base-hw/src/core/spec/riscv/pic.cc index a08b09daf4..605f38e258 100644 --- a/repos/base-hw/src/core/spec/riscv/pic.cc +++ b/repos/base-hw/src/core/spec/riscv/pic.cc @@ -11,14 +11,13 @@ * under the terms of the GNU Affero General Public License version 3. */ - #include #include #include Board::Pic::Pic(Global_interrupt_controller &) : - _plic(Genode::Platform::mmio_to_virt(Board::PLIC_BASE)) + _plic({(char *)Core::Platform::mmio_to_virt(Board::PLIC_BASE), Board::PLIC_SIZE}) { /* enable external interrupts */ enum { SEIE = 0x200 }; diff --git a/repos/base-hw/src/core/spec/riscv/pic.h b/repos/base-hw/src/core/spec/riscv/pic.h index d85ec9751f..39ac46cb18 100644 --- a/repos/base-hw/src/core/spec/riscv/pic.h +++ b/repos/base-hw/src/core/spec/riscv/pic.h @@ -22,7 +22,7 @@ namespace Board { - class Global_interrupt_controller { }; + class Global_interrupt_controller { public: void init() {} }; class Pic; } diff --git a/repos/base-hw/src/core/spec/riscv/platform_support.cc b/repos/base-hw/src/core/spec/riscv/platform_support.cc index 702c1b0c35..6cba39462c 100644 --- a/repos/base-hw/src/core/spec/riscv/platform_support.cc +++ b/repos/base-hw/src/core/spec/riscv/platform_support.cc @@ -16,18 +16,19 @@ #include #include -using namespace Genode; +using namespace Core; void Platform::_init_io_port_alloc() { } -void Platform::_init_additional_platform_info(Genode::Xml_generator&) { } +void Platform::_init_additional_platform_info(Xml_generator &) { } long Platform::irq(long const user_irq ) { return user_irq; } -bool Platform::get_msi_params(addr_t /* mmconf */, addr_t & /* address */, - addr_t & /* data */, unsigned & /* irq_number */) { - return false; } +bool Platform::alloc_msi_vector(addr_t &, addr_t &) { return false; } + + +void Platform::free_msi_vector(addr_t, addr_t) { } diff --git a/repos/base-hw/src/core/spec/riscv/timer.cc b/repos/base-hw/src/core/spec/riscv/timer.cc index 4538533bfb..06ba8b1457 100644 --- a/repos/base-hw/src/core/spec/riscv/timer.cc +++ b/repos/base-hw/src/core/spec/riscv/timer.cc @@ -5,13 +5,13 @@ */ /* - * Copyright (C) 2021 Genode Labs GmbH + * Copyright (C) 2021-2022 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. */ -/* Core includes */ +/* core includes */ #include #include #include @@ -21,6 +21,12 @@ using namespace Kernel; Board::Timer::Timer(unsigned) +{ + init(); +} + + +void Board::Timer::init() { /* enable timer interrupt */ enum { STIE = 0x20 }; @@ -39,8 +45,7 @@ time_t Board::Timer::stime() const void Timer::_start_one_shot(time_t const ticks) { - _device.last_time = _device.stime(); - Sbi::set_timer(_device.last_time + ticks); + Sbi::set_timer(_time + ticks); } @@ -58,7 +63,7 @@ time_t Timer::_max_value() const { time_t Timer::_duration() const { - return _device.stime() - _device.last_time; + return _device.stime() - _time; } diff --git a/repos/base-hw/src/core/spec/riscv/timer.h b/repos/base-hw/src/core/spec/riscv/timer.h index 04138565cd..38f9f2bf58 100644 --- a/repos/base-hw/src/core/spec/riscv/timer.h +++ b/repos/base-hw/src/core/spec/riscv/timer.h @@ -16,6 +16,8 @@ /* Genode includes */ #include + +/* core includes */ #include namespace Board { class Timer; } @@ -31,11 +33,11 @@ struct Board::Timer TICKS_PER_US = TICKS_PER_MS / 1000, }; - Kernel::time_t last_time { 0 }; - Kernel::time_t stime() const; Timer(unsigned); + + void init(); }; #endif /* _SRC__CORE__SPEC__RISCV__TIMER_H_ */ diff --git a/repos/base-hw/src/core/spec/x86_64/address_space_id_allocator.h b/repos/base-hw/src/core/spec/x86_64/address_space_id_allocator.h index e87f581b9b..cb1c4b52b7 100644 --- a/repos/base-hw/src/core/spec/x86_64/address_space_id_allocator.h +++ b/repos/base-hw/src/core/spec/x86_64/address_space_id_allocator.h @@ -17,9 +17,6 @@ /* base includes */ #include -namespace Board { - - class Address_space_id_allocator { }; -} +namespace Board { class Address_space_id_allocator { }; } #endif /* _X86_64__ADDRESS_SPACE_ID_ALLOCATOR_H_ */ diff --git a/repos/base-hw/src/core/spec/x86_64/bios_data_area.cc b/repos/base-hw/src/core/spec/x86_64/bios_data_area.cc index 79ca36d108..d93f6a6254 100644 --- a/repos/base-hw/src/core/spec/x86_64/bios_data_area.cc +++ b/repos/base-hw/src/core/spec/x86_64/bios_data_area.cc @@ -18,4 +18,4 @@ using namespace Genode; -addr_t Bios_data_area::_mmio_base_virt() { return Platform::mmio_to_virt(0); } +addr_t Bios_data_area::_mmio_base_virt() { return Core::Platform::mmio_to_virt(0); } diff --git a/repos/base-hw/src/core/spec/x86_64/cpu.cc b/repos/base-hw/src/core/spec/x86_64/cpu.cc index 689e4f9e3d..249b53e5ab 100644 --- a/repos/base-hw/src/core/spec/x86_64/cpu.cc +++ b/repos/base-hw/src/core/spec/x86_64/cpu.cc @@ -19,6 +19,8 @@ extern int __idt; extern int __idt_end; +using namespace Core; + /** * Pseudo Descriptor @@ -27,15 +29,15 @@ extern int __idt_end; */ struct Pseudo_descriptor { - Genode::uint16_t const limit = 0; - Genode::uint64_t const base = 0; + uint16_t const limit = 0; + uint64_t const base = 0; + + constexpr Pseudo_descriptor(uint16_t l, uint64_t b) : limit(l), base(b) {} - constexpr Pseudo_descriptor(Genode::uint16_t l, Genode::uint64_t b) - : limit(l), base(b) {} } __attribute__((packed)); -Genode::Cpu::Context::Context(bool core) +Cpu::Context::Context(bool core) { eflags = EFLAGS_IF_SET; cs = core ? 0x8 : 0x1b; @@ -43,19 +45,18 @@ Genode::Cpu::Context::Context(bool core) } -Genode::Cpu::Mmu_context::Mmu_context(addr_t table, - Board::Address_space_id_allocator &) +Cpu::Mmu_context::Mmu_context(addr_t table, Board::Address_space_id_allocator &) : cr3(Cr3::Pdb::masked(table)) { } -void Genode::Cpu::Tss::init() +void Cpu::Tss::init() { enum { TSS_SELECTOR = 0x28, }; asm volatile ("ltr %w0" : : "r" (TSS_SELECTOR)); } -void Genode::Cpu::Idt::init() +void Cpu::Idt::init() { Pseudo_descriptor descriptor { (uint16_t)((addr_t)&__idt_end - (addr_t)&__idt), @@ -64,7 +65,7 @@ void Genode::Cpu::Idt::init() } -void Genode::Cpu::Gdt::init(addr_t tss_addr) +void Cpu::Gdt::init(addr_t tss_addr) { tss_desc[0] = ((((tss_addr >> 24) & 0xff) << 24 | ((tss_addr >> 16) & 0xff) | @@ -79,7 +80,7 @@ void Genode::Cpu::Gdt::init(addr_t tss_addr) } -void Genode::Cpu::mmu_fault(Context & regs, Kernel::Thread_fault & fault) +void Cpu::mmu_fault(Context ®s, Kernel::Thread_fault &fault) { using Fault = Kernel::Thread_fault::Type; @@ -102,59 +103,52 @@ void Genode::Cpu::mmu_fault(Context & regs, Kernel::Thread_fault & fault) else return Fault::UNKNOWN; }; - fault.addr = Genode::Cpu::Cr2::read(); + fault.addr = Cpu::Cr2::read(); fault.type = fault_lambda(regs.errcode); } -extern void const * const kernel_stack; -extern Genode::size_t const kernel_stack_size; - - -bool Genode::Cpu::active(Mmu_context &mmu_context) +bool Cpu::active(Mmu_context &mmu_context) { return (mmu_context.cr3 == Cr3::read()); } -void Genode::Cpu::switch_to(Mmu_context &mmu_context) +void Cpu::switch_to(Mmu_context &mmu_context) { Cr3::write(mmu_context.cr3); } -void Genode::Cpu::switch_to(Context & context) +void Cpu::switch_to(Context &context) { - tss.ist[0] = (addr_t)&context + sizeof(Genode::Cpu_state); - - addr_t const stack_base = reinterpret_cast(&kernel_stack); - context.kernel_stack = stack_base + - (Cpu::executing_id() + 1) * kernel_stack_size - - sizeof(addr_t); + tss.ist[0] = (addr_t)&context + sizeof(Cpu_state); } -unsigned Genode::Cpu::executing_id() +unsigned Cpu::executing_id() { - void * const stack_ptr = nullptr; - addr_t const stack_addr = reinterpret_cast(&stack_ptr); - addr_t const stack_base = reinterpret_cast(&kernel_stack); - - unsigned const cpu_id = (unsigned)((stack_addr - stack_base) / kernel_stack_size); - - return cpu_id; + return Cpu::Cpuid_1_ebx::Apic_id::get(Cpu::Cpuid_1_ebx::read()); } -void Genode::Cpu::clear_memory_region(Genode::addr_t const addr, - Genode::size_t const size, bool) +void Cpu::clear_memory_region(addr_t const addr, size_t const size, bool) { if (align_addr(addr, 3) == addr && align_addr(size, 3) == size) { - Genode::addr_t start = addr; - Genode::size_t count = size / 8; + addr_t start = addr; + size_t count = size / 8; asm volatile ("rep stosq" : "+D" (start), "+c" (count) : "a" (0) : "memory"); } else { - Genode::memset((void*)addr, 0, size); + memset((void*)addr, 0, size); } } + + +void Cpu::single_step(Context ®s, bool on) +{ + if (on) + regs.eflags |= Context::Eflags::EFLAGS_TF; + else + regs.eflags &= ~Context::Eflags::EFLAGS_TF; +} diff --git a/repos/base-hw/src/core/spec/x86_64/cpu.h b/repos/base-hw/src/core/spec/x86_64/cpu.h index 781fa38373..e612cc0321 100644 --- a/repos/base-hw/src/core/spec/x86_64/cpu.h +++ b/repos/base-hw/src/core/spec/x86_64/cpu.h @@ -27,10 +27,11 @@ /* base internal includes */ #include -/* base-hw Core includes */ +/* core includes */ +#include #include #include -#include +#include namespace Kernel { struct Thread_fault; } @@ -38,14 +39,13 @@ namespace Kernel { struct Thread_fault; } namespace Board { class Address_space_id_allocator; } -namespace Genode { +namespace Core { class Cpu; - using sizet_arithm_t = __uint128_t; } -class Genode::Cpu : public Hw::X86_64_cpu +class Core::Cpu : public Hw::X86_64_cpu { public: @@ -91,15 +91,10 @@ class Genode::Cpu : public Hw::X86_64_cpu } __attribute__((packed)) gdt { }; - /** - * Extend basic CPU state by members relevant for 'base-hw' only - */ - struct Kernel_stack { unsigned long kernel_stack { }; }; - - /* exception_vector.s depends on the position of the Kernel_stack */ - struct alignas(16) Context : Cpu_state, Kernel_stack, Fpu_context + struct alignas(16) Context : Cpu_state, Fpu_context { enum Eflags { + EFLAGS_TF = 1 << 8, EFLAGS_IF_SET = 1 << 9, EFLAGS_IOPL_3 = 3 << 12, }; @@ -133,12 +128,12 @@ class Genode::Cpu : public Hw::X86_64_cpu static void mmu_fault(Context & regs, Kernel::Thread_fault & fault); + static void single_step(Context ®s, bool on); + /** * Invalidate the whole TLB */ - static void invalidate_tlb() { - Genode::Cpu::Cr3::write(Genode::Cpu::Cr3::read()); } - + static void invalidate_tlb() { Cr3::write(Cr3::read()); } static void clear_memory_region(addr_t const addr, size_t const size, diff --git a/repos/base-hw/src/core/spec/x86_64/crt0.s b/repos/base-hw/src/core/spec/x86_64/crt0.s index 0ca72835b8..4697eb2c2d 100644 --- a/repos/base-hw/src/core/spec/x86_64/crt0.s +++ b/repos/base-hw/src/core/spec/x86_64/crt0.s @@ -13,6 +13,8 @@ * under the terms of the GNU Affero General Public License version 3. */ +.include "stack_switch.s" + .section ".text" /*********************** @@ -22,20 +24,7 @@ .global _start _start: - /* load kernel stack size */ - movq kernel_stack_size@GOTPCREL(%rip), %rbx - movq (%rbx), %rax - - /* calculate stack top (rdi contains cpu_id), stack top is stored in rax */ - movq %rdi, %rbx - inc %rbx - mulq %rbx - - /* switch to kernel stack */ - movq kernel_stack@GOTPCREL(%rip), %rbx - addq %rbx, %rax - subq $8, %rax - movq %rax, %rsp + switch_to_kernel_stack /* jump to C entry code */ jmp _ZN6Kernel39main_initialize_and_handle_kernel_entryEv diff --git a/repos/base-hw/src/core/spec/x86_64/exception_vector.s b/repos/base-hw/src/core/spec/x86_64/exception_vector.s index e5e9deed8d..c1c0603cf7 100644 --- a/repos/base-hw/src/core/spec/x86_64/exception_vector.s +++ b/repos/base-hw/src/core/spec/x86_64/exception_vector.s @@ -14,13 +14,14 @@ * under the terms of the GNU Affero General Public License version 3. */ +.include "stack_switch.s" + /* offsets of member variables in a CPU context */ .set IP_OFFSET, 17 * 8 .set SP_OFFSET, 20 * 8 /* virtual addresses */ -.set BASE, 0xffffffc000000000 -.set ISR, BASE +.set ISR, HW_MM_KERNEL_START .set ISR_ENTRY_SIZE, 12 .set IDT_FLAGS_PRIVILEGED, 0x8e01 @@ -93,6 +94,7 @@ .set vec, vec + 1 .endr + .global _kernel_entry _kernel_entry: pushq %rbp @@ -113,13 +115,12 @@ /** * Calculate offset into Kernel_stack member of Cpu::Context as defined - * in cpu.h - struct Context : Cpu_state, Kernel_stack, Fpu_context + * in cpu.h - struct Context : Cpu_state, Fpu_context */ .set REGISTER_COUNT, 22 .set REGISTER_SIZE, 8 .set SIZEOF_CPU_STATE, REGISTER_COUNT * REGISTER_SIZE /* sizeof (Cpu_state) */ - .set KERNEL_STACK_OFFSET, SIZEOF_CPU_STATE - .set FPU_CONTEXT_OFFSET, KERNEL_STACK_OFFSET + 8 + .set FPU_CONTEXT_OFFSET, SIZEOF_CPU_STATE /* rsp contains pointer to Cpu::Context */ /* save FPU context */ @@ -128,10 +129,7 @@ movq (%rax), %rax fxsave (%rax) - /* Restore kernel stack and continue kernel execution */ - movq %rsp, %rax - addq $KERNEL_STACK_OFFSET, %rax - movq (%rax), %rsp + switch_to_kernel_stack _load_address _ZN6Kernel24main_handle_kernel_entryEv rcx jmp *%rcx @@ -146,9 +144,19 @@ .align 8 __idt: - /* first 128 entries */ + /* first 3 entries */ .set isr_addr, ISR - .rept 0x80 + .rept 3 + _idt_entry isr_addr IDT_FLAGS_PRIVILEGED + .set isr_addr, isr_addr + ISR_ENTRY_SIZE + .endr + + /* int3 */ + _idt_entry isr_addr IDT_FLAGS_UNPRIVILEGED + .set isr_addr, isr_addr + ISR_ENTRY_SIZE + + /* entries 4-127 */ + .rept 124 _idt_entry isr_addr IDT_FLAGS_PRIVILEGED .set isr_addr, isr_addr + ISR_ENTRY_SIZE .endr diff --git a/repos/base-hw/src/core/spec/x86_64/fpu.h b/repos/base-hw/src/core/spec/x86_64/fpu.h index b3bf484f95..817a26b716 100644 --- a/repos/base-hw/src/core/spec/x86_64/fpu.h +++ b/repos/base-hw/src/core/spec/x86_64/fpu.h @@ -35,14 +35,14 @@ class Genode::Fpu_context */ char _fxsave_area[527]; - struct Context : Mmio + struct Context : Mmio<512> { struct Fcw : Register<0, 16> { }; struct Mxcsr : Register<24, 32> { }; - Context(addr_t const base) : Mmio(base) + Context(addr_t const base) : Mmio({(char *)base, Mmio::SIZE}) { - memset((void *)base, 0, 512); + memset((void *)base, 0, Mmio::SIZE); write(0x37f); /* mask exceptions SysV ABI */ write(0x1f80); } diff --git a/repos/base-hw/src/core/spec/x86_64/kernel/cpu.cc b/repos/base-hw/src/core/spec/x86_64/kernel/cpu.cc index 7c1798df62..134c16b55f 100644 --- a/repos/base-hw/src/core/spec/x86_64/kernel/cpu.cc +++ b/repos/base-hw/src/core/spec/x86_64/kernel/cpu.cc @@ -22,7 +22,10 @@ void Kernel::Cpu::_arch_init() Idt::init(); Tss::init(); + _pic.init(); + _timer.init(); + _ipi_irq.init(); + /* enable timer interrupt */ - _pic.store_apic_id(id()); _pic.unmask(_timer.interrupt_id(), id()); } diff --git a/repos/base-hw/src/core/spec/x86_64/kernel/panic.h b/repos/base-hw/src/core/spec/x86_64/kernel/panic.h new file mode 100644 index 0000000000..94249ee461 --- /dev/null +++ b/repos/base-hw/src/core/spec/x86_64/kernel/panic.h @@ -0,0 +1,34 @@ +/* + * \brief x86 kernel panic + * \author Benjamin Lamowski + * \date 2024-02-28 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CORE__SPEC__X86_64__KERNEL__PANIC_H_ +#define _CORE__SPEC__X86_64__KERNEL__PANIC_H_ + +/* base includes */ +#include + +namespace Kernel { + + inline void panic(auto &&... args) + { + Genode::error("Kernel panic: ", args...); + /* This is CPU local, but should be sufficient for now. */ + asm volatile( + "cli;" + "hlt;" + : : : + ); + } +} + +#endif /* _CORE__SPEC__X86_64__KERNEL__PANIC_H_ */ diff --git a/repos/base-hw/src/core/spec/x86_64/kernel/thread.cc b/repos/base-hw/src/core/spec/x86_64/kernel/thread.cc index df3332a4de..89d87ad049 100644 --- a/repos/base-hw/src/core/spec/x86_64/kernel/thread.cc +++ b/repos/base-hw/src/core/spec/x86_64/kernel/thread.cc @@ -7,7 +7,7 @@ */ /* - * Copyright (C) 2013-2017 Genode Labs GmbH + * Copyright (C) 2013-2023 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -18,8 +18,13 @@ #include #include +#include +#include -void Kernel::Thread::Tlb_invalidation::execute() +#include + + +void Kernel::Thread::Tlb_invalidation::execute(Cpu &) { /* invalidate cpu-local TLB */ Cpu::invalidate_tlb(); @@ -29,7 +34,131 @@ void Kernel::Thread::Tlb_invalidation::execute() global_work_list.remove(&_le); caller._restart(); } -}; +} + + +void Kernel::Thread::Flush_and_stop_cpu::execute(Cpu &cpu) +{ + if (--cpus_left == 0) { + /* last CPU triggers final ACPI suspend outside kernel lock */ + cpu.suspend.typ_a = suspend.typ_a; + cpu.suspend.typ_b = suspend.typ_b; + cpu.next_state_suspend(); + return; + } + + /* halt CPU outside kernel lock */ + cpu.next_state_halt(); + + /* adhere to ACPI specification */ + asm volatile ("wbinvd" : : : "memory"); +} + + +void Kernel::Cpu::Halt_job::Halt_job::proceed(Kernel::Cpu &cpu) +{ + switch (cpu.state()) { + case HALT: + while (true) { + asm volatile ("hlt"); } + break; + case SUSPEND: + using Core::Platform; + + Platform::apply_with_boot_info([&](auto const &boot_info) { + auto table = boot_info.plat_info.acpi_fadt; + auto acpi_fadt_table = reinterpret_cast(Platform::mmio_to_virt(table)); + + /* paranoia */ + if (!acpi_fadt_table) + return; + + /* all CPUs signaled that they are stopped, trigger ACPI suspend */ + Hw::Acpi_fadt fadt(acpi_fadt_table); + + /* ack all GPEs, otherwise we may wakeup immediately */ + fadt.clear_gpe0_status(); + fadt.clear_gpe1_status(); + + /* adhere to ACPI specification */ + asm volatile ("wbinvd" : : : "memory"); + + fadt.suspend(cpu.suspend.typ_a, cpu.suspend.typ_b); + + Genode::raw("kernel: unexpected resume"); + }); + break; + default: + break; + } + + Genode::raw("unknown cpu state"); + while (true) { + asm volatile ("hlt"); + } +} + + +void Kernel::Thread::_call_suspend() +{ + using Genode::uint8_t; + using Core::Platform; + + Hw::Acpi_generic * acpi_fadt_table { }; + unsigned cpu_count { }; + + Platform::apply_with_boot_info([&](auto const &boot_info) { + auto table = boot_info.plat_info.acpi_fadt; + if (table) + acpi_fadt_table = reinterpret_cast(Platform::mmio_to_virt(table)); + + cpu_count = boot_info.cpus; + }); + + if (!acpi_fadt_table || !cpu_count) { + user_arg_0(0 /* fail */); + return; + } + + if (_stop_cpu.constructed()) { + if (_stop_cpu->cpus_left) { + Genode::raw("kernel: resume still ongoing"); + user_arg_0(0 /* fail */); + return; + } + + /* remove & destruct Flush_and_stop_cpu object */ + _stop_cpu.destruct(); + user_arg_0(1 /* success */); + + return; + } + + auto const sleep_typ_a = uint8_t(user_arg_1()); + auto const sleep_typ_b = uint8_t(user_arg_1() >> 8); + + _stop_cpu.construct(_cpu_pool.work_list(), cpu_count - 1, + Hw::Suspend_type { sleep_typ_a, sleep_typ_b }); + + /* single core CPU case */ + if (cpu_count == 1) { + /* current CPU triggers final ACPI suspend outside kernel lock */ + _cpu->next_state_suspend(); + return; + } + + /* trigger IPIs to all beside current CPU */ + _cpu_pool.for_each_cpu([&] (Cpu &cpu) { + + if (cpu.id() == Cpu::executing_id()) { + /* halt CPU outside kernel lock */ + cpu.next_state_halt(); + return; + } + + cpu.trigger_ip_interrupt(); + }); +} void Kernel::Thread::_call_cache_coherent_region() { } @@ -41,6 +170,12 @@ void Kernel::Thread::_call_cache_clean_invalidate_data_region() { } void Kernel::Thread::_call_cache_invalidate_data_region() { } +void Kernel::Thread::_call_cache_line_size() +{ + user_arg_0(0); +} + + void Kernel::Thread::proceed(Cpu & cpu) { if (!cpu.active(pd().mmu_regs) && type() != CORE) diff --git a/repos/base-hw/src/core/spec/x86_64/kernel/thread_exception.cc b/repos/base-hw/src/core/spec/x86_64/kernel/thread_exception.cc index 25ccaeae65..7551a62f10 100644 --- a/repos/base-hw/src/core/spec/x86_64/kernel/thread_exception.cc +++ b/repos/base-hw/src/core/spec/x86_64/kernel/thread_exception.cc @@ -30,9 +30,12 @@ void Thread::exception(Cpu & cpu) _mmu_exception(); return; + case Cpu_state::DIVIDE_ERROR: + case Cpu_state::DEBUG: + case Cpu_state::BREAKPOINT: case Cpu_state::UNDEFINED_INSTRUCTION: - Genode::raw(*this, ": undefined instruction at ip=", (void*)regs->ip); - _die(); + case Cpu_state::GENERAL_PROTECTION: + _exception(); return; case Cpu_state::SUPERVISOR_CALL: diff --git a/repos/base-hw/src/core/spec/x86_64/pd_session_support.cc b/repos/base-hw/src/core/spec/x86_64/pd_session_support.cc new file mode 100644 index 0000000000..cd30c0d074 --- /dev/null +++ b/repos/base-hw/src/core/spec/x86_64/pd_session_support.cc @@ -0,0 +1,89 @@ +/* + * \brief Core implementation of the PD session interface + * \author Alexander Boettcher + * \date 2022-12-02 + */ + +/* + * Copyright (C) 2022 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#include +#include + +using namespace Core; +using State = Genode::Pd_session::Managing_system_state; + + +class System_control_component : public Genode::Rpc_object, + public Core::System_control +{ + public: + + State system_control(State const &) override; + + Capability control_cap(Affinity::Location const) const override; +}; + + +State System_control_component::system_control(State const &request) +{ + bool const suspend = (request.trapno == State::ACPI_SUSPEND_REQUEST); + State respond { }; + + if (!suspend) { + /* report failed attempt */ + respond.trapno = 0; + return respond; + } + + /* + * The trapno/ip/sp registers used below are just convention to transfer + * the intended sleep state S0 ... S5. The values are read out by an + * ACPI AML component and are of type TYP_SLPx as described in the + * ACPI specification, e.g. TYP_SLPa and TYP_SLPb. The values differ + * between different PC systems/boards. + * + * \note trapno/ip/sp registers are chosen because they exist in + * Managing_system_state for x86_32 and x86_64. + */ + unsigned const sleep_type_a = request.ip & 0xffu; + unsigned const sleep_type_b = request.sp & 0xffu; + + respond.trapno = Kernel::suspend((sleep_type_b << 8) | sleep_type_a); + + return respond; +} + + +static System_control_component &system_instance() +{ + static System_control_component system_component { }; + return system_component; +} + + +System_control & Core::init_system_control(Allocator &, Rpc_entrypoint &ep) +{ + ep.manage(&system_instance()); + return system_instance(); +} + + +Capability System_control_component::control_cap(Affinity::Location const) const +{ + return system_instance().cap(); +} + + +/*************************** + ** Dummy implementations ** + ***************************/ + +bool Pd_session_component::assign_pci(addr_t, uint16_t) { return true; } + + +Pd_session::Map_result Pd_session_component::map(Pd_session::Virt_range) { return Map_result::OK; } diff --git a/repos/base-hw/src/core/spec/x86_64/pic.cc b/repos/base-hw/src/core/spec/x86_64/pic.cc index b267faa870..c4e9073c43 100644 --- a/repos/base-hw/src/core/spec/x86_64/pic.cc +++ b/repos/base-hw/src/core/spec/x86_64/pic.cc @@ -15,13 +15,12 @@ /* Genode includes */ #include -#include /* core includes */ #include #include -using namespace Genode; +using namespace Core; using namespace Board; enum { @@ -40,8 +39,13 @@ enum { Local_interrupt_controller:: Local_interrupt_controller(Global_interrupt_controller &global_irq_ctrl) : - Mmio { Platform::mmio_to_virt(Hw::Cpu_memory_map::lapic_phys_base()) }, + Local_apic({Platform::mmio_to_virt(Hw::Cpu_memory_map::lapic_phys_base())}), _global_irq_ctrl { global_irq_ctrl } +{ + init(); +} + +void Local_interrupt_controller::init() { /* Start initialization sequence in cascade mode */ outb(PIC_CMD_MASTER, 0x11); @@ -132,7 +136,7 @@ void Local_interrupt_controller::send_ipi(unsigned const cpu_id) Icr_high::access_t icr_high = 0; Icr_low::access_t icr_low = 0; - Icr_high::Destination::set(icr_high, _global_irq_ctrl.lapic_id(cpu_id)); + Icr_high::Destination::set(icr_high, cpu_id); Icr_low::Vector::set(icr_low, Local_interrupt_controller::IPI); Icr_low::Level_assert::set(icr_low); @@ -147,19 +151,6 @@ void Local_interrupt_controller::send_ipi(unsigned const cpu_id) ** Board::Global_interrupt_controller ** ****************************************/ -uint8_t Global_interrupt_controller::lapic_id(unsigned cpu_id) const -{ - return _lapic_id[cpu_id]; -} - - -void Global_interrupt_controller::lapic_id(unsigned cpu_id, - uint8_t lapic_id) -{ - _lapic_id[cpu_id] = lapic_id; -} - - void Global_interrupt_controller::irq_mode(unsigned irq_number, unsigned trigger, unsigned polarity) @@ -231,7 +222,7 @@ Global_interrupt_controller::_create_irt_entry(unsigned const irq) Global_interrupt_controller::Global_interrupt_controller() : - Mmio(Platform::mmio_to_virt(Hw::Cpu_memory_map::MMIO_IOAPIC_BASE)) + Mmio({(char *)Platform::mmio_to_virt(Hw::Cpu_memory_map::MMIO_IOAPIC_BASE), Mmio::SIZE}) { write(IOAPICVER); _irte_count = read() + 1; @@ -246,17 +237,24 @@ Global_interrupt_controller::Global_interrupt_controller() _irq_mode[i].trigger_mode = TRIGGER_LEVEL; _irq_mode[i].polarity = POLARITY_LOW; } - - /* remap all IRQs managed by I/O APIC */ - if (i < _irte_count) { - Irte::access_t irte = _create_irt_entry(i); - write(IOREDTBL + 2 * i + 1); - write((Iowin::access_t)(irte >> Iowin::ACCESS_WIDTH)); - write(IOREDTBL + 2 * i); - write((Iowin::access_t)(irte)); - } } -}; + + init(); +} + + +void Global_interrupt_controller::init() +{ + /* remap all IRQs managed by I/O APIC */ + for (unsigned i = 0; i < _irte_count; i++) + { + Irte::access_t irte = _create_irt_entry(i); + write(IOREDTBL + 2 * i + 1); + write((Iowin::access_t)(irte >> Iowin::ACCESS_WIDTH)); + write(IOREDTBL + 2 * i); + write((Iowin::access_t)(irte)); + } +} void Global_interrupt_controller::toggle_mask(unsigned const vector, diff --git a/repos/base-hw/src/core/spec/x86_64/pic.h b/repos/base-hw/src/core/spec/x86_64/pic.h index 3f61994192..283032ee38 100644 --- a/repos/base-hw/src/core/spec/x86_64/pic.h +++ b/repos/base-hw/src/core/spec/x86_64/pic.h @@ -17,6 +17,8 @@ /* Genode includes */ #include +#include +#include namespace Board { @@ -47,7 +49,7 @@ struct Board::Irte : Genode::Register<64> }; -class Board::Global_interrupt_controller : public Genode::Mmio +class Board::Global_interrupt_controller : public Genode::Mmio { private: @@ -85,7 +87,6 @@ class Board::Global_interrupt_controller : public Genode::Mmio }; unsigned _irte_count = 0; /* number of redirection table entries */ - uint8_t _lapic_id[NR_OF_CPUS]; /* unique name of the LAPIC of each CPU */ Irq_mode _irq_mode[IRQ_COUNT]; /** @@ -114,6 +115,8 @@ class Board::Global_interrupt_controller : public Genode::Mmio Global_interrupt_controller(); + void init(); + /** * Set/unset mask bit of IRTE for given vector * @@ -133,55 +136,13 @@ class Board::Global_interrupt_controller : public Genode::Mmio void irq_mode(unsigned irq_number, unsigned trigger, unsigned polarity); - - - /*************** - ** Accessors ** - ***************/ - - void lapic_id(unsigned cpu_id, uint8_t lapic_id); - - uint8_t lapic_id(unsigned cpu_id) const; }; -class Board::Local_interrupt_controller : public Genode::Mmio +class Board::Local_interrupt_controller : private Hw::Local_apic { private: - /* - * Registers - */ - - struct Id : Register<0x020, 32> { }; - struct EOI : Register<0x0b0, 32, true> { }; - struct Svr : Register<0x0f0, 32> - { - struct APIC_enable : Bitfield<8, 1> { }; - }; - - /* - * ISR register, see Intel SDM Vol. 3A, section 10.8.4. - * - * Each of the 8 32-bit ISR values is followed by 12 bytes of padding. - */ - struct Isr : Register_array<0x100, 32, 8 * 4, 32> { }; - - /* - * Interrupt control register - */ - struct Icr_low : Register<0x300, 32, true> - { - struct Vector : Bitfield< 0, 8> { }; - struct Delivery_status : Bitfield<12, 1> { }; - struct Level_assert : Bitfield<14, 1> { }; - }; - - struct Icr_high : Register<0x310, 32, true> - { - struct Destination : Bitfield<24, 8> { }; - }; - Global_interrupt_controller &_global_irq_ctrl; /** @@ -219,15 +180,9 @@ class Board::Local_interrupt_controller : public Genode::Mmio void irq_mode(unsigned irq, unsigned trigger, unsigned polarity); - void store_apic_id(unsigned const cpu_id) - { - if (cpu_id < NR_OF_CPUS) { - Id::access_t const lapic_id = read(); - _global_irq_ctrl.lapic_id(cpu_id, (unsigned char)((lapic_id >> 24) & 0xff)); - } - } - void send_ipi(unsigned const); + + void init(); }; #endif /* _CORE__SPEC__X86_64__PIC_H_ */ diff --git a/repos/base-hw/src/core/spec/x86_64/pit.cc b/repos/base-hw/src/core/spec/x86_64/pit.cc index a2f00feddd..bb895b9084 100644 --- a/repos/base-hw/src/core/spec/x86_64/pit.cc +++ b/repos/base-hw/src/core/spec/x86_64/pit.cc @@ -22,7 +22,7 @@ #include #include -using namespace Genode; +using namespace Core; using namespace Kernel; @@ -55,7 +55,13 @@ uint32_t Board::Timer::pit_calc_timer_freq(void) Board::Timer::Timer(unsigned) : - Mmio(Platform::mmio_to_virt(Hw::Cpu_memory_map::lapic_phys_base())) + Mmio({(char *)Platform::mmio_to_virt(Hw::Cpu_memory_map::lapic_phys_base()), Mmio::SIZE}) +{ + init(); +} + + +void Board::Timer::init() { /* enable LAPIC timer in one-shot mode */ write(Board::TIMER_VECTOR_KERNEL); @@ -63,6 +69,12 @@ Board::Timer::Timer(unsigned) write(0); write(0); + /* use very same divider after ACPI resume as used during initial boot */ + if (divider) { + write((uint8_t)divider); + return; + } + /* calibrate LAPIC frequency to fullfill our requirements */ for (Divide_configuration::access_t div = Divide_configuration::Divide_value::MAX; div && ticks_per_ms < TIMER_MIN_TICKS_PER_MS; div--) @@ -75,6 +87,7 @@ Board::Timer::Timer(unsigned) /* Calculate timer frequency */ ticks_per_ms = pit_calc_timer_freq(); + divider = div; } /** @@ -96,7 +109,7 @@ time_t Timer::ticks_to_us(time_t const ticks) const { time_t Timer::us_to_ticks(time_t const us) const { - return (us / 1000) * _device.ticks_per_ms; } + return (us * _device.ticks_per_ms) / 1000; } time_t Timer::_max_value() const { diff --git a/repos/base-hw/src/core/spec/x86_64/pit.h b/repos/base-hw/src/core/spec/x86_64/pit.h index 8b8d6cc124..026e293d9a 100644 --- a/repos/base-hw/src/core/spec/x86_64/pit.h +++ b/repos/base-hw/src/core/spec/x86_64/pit.h @@ -28,7 +28,7 @@ namespace Board { class Timer; } /** * LAPIC-based timer driver for core */ -struct Board::Timer: Genode::Mmio +struct Board::Timer: Genode::Mmio { enum { /* PIT constants */ @@ -66,12 +66,15 @@ struct Board::Timer: Genode::Mmio struct Calibration_failed : Genode::Exception { }; - Genode::uint32_t ticks_per_ms = 0; + Divide_configuration::access_t divider = 0; + Genode::uint32_t ticks_per_ms = 0; /* Measure LAPIC timer frequency using PIT channel 2 */ Genode::uint32_t pit_calc_timer_freq(void); Timer(unsigned); + + void init(); }; #endif /* _SRC__CORE__SPEC__ARM__PIT_H_ */ diff --git a/repos/base-hw/src/core/spec/x86_64/platform_support.cc b/repos/base-hw/src/core/spec/x86_64/platform_support.cc index 70bdf6a40d..d7dcb4528c 100644 --- a/repos/base-hw/src/core/spec/x86_64/platform_support.cc +++ b/repos/base-hw/src/core/spec/x86_64/platform_support.cc @@ -1,11 +1,12 @@ /* * \brief Platform implementations specific for x86_64 * \author Reto Buerki + * \author Benjamin Lamowski * \date 2015-05-04 */ /* - * Copyright (C) 2015-2017 Genode Labs GmbH + * Copyright (C) 2015-2024 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -15,18 +16,19 @@ #include #include #include +#include -using namespace Genode; +using namespace Core; void Platform::_init_additional_platform_info(Xml_generator &xml) { if (_boot_info().plat_info.efi_system_table != 0) { - xml.node("efi-system-table", [&] () { + xml.node("efi-system-table", [&] { xml.attribute("address", String<32>(Hex(_boot_info().plat_info.efi_system_table))); }); } - xml.node("acpi", [&] () { + xml.node("acpi", [&] { uint32_t const revision = _boot_info().plat_info.acpi_rsdp.revision; uint32_t const rsdt = _boot_info().plat_info.acpi_rsdp.rsdt; uint64_t const xsdt = _boot_info().plat_info.acpi_rsdp.xsdt; @@ -40,8 +42,8 @@ void Platform::_init_additional_platform_info(Xml_generator &xml) xml.attribute("xsdt", String<32>(Hex(xsdt))); } }); - xml.node("boot", [&] () { - xml.node("framebuffer", [&] () { + xml.node("boot", [&] { + xml.node("framebuffer", [&] { Hw::Framebuffer const &boot_fb = _boot_info().plat_info.framebuffer; xml.attribute("phys", String<32>(Hex(boot_fb.addr))); xml.attribute("width", boot_fb.width); @@ -51,17 +53,41 @@ void Platform::_init_additional_platform_info(Xml_generator &xml) xml.attribute("pitch", boot_fb.pitch); }); }); - xml.node("hardware", [&] () { - xml.node("features", [&] () { - xml.attribute("svm", false); - xml.attribute("vmx", false); + xml.node("hardware", [&] { + xml.node("features", [&] { + xml.attribute("svm", Hw::Virtualization_support::has_svm()); + xml.attribute("vmx", Hw::Virtualization_support::has_vmx()); + }); + xml.node("tsc", [&] { + xml.attribute("invariant", Hw::Lapic::invariant_tsc()); + xml.attribute("freq_khz", Hw::Lapic::tsc_freq()); }); }); } -bool Platform::get_msi_params(addr_t, addr_t &, addr_t &, unsigned &) { - return false; } +Bit_allocator<64> &msi_allocator() +{ + static Bit_allocator<64> msi_allocator; + return msi_allocator; +} + + +bool Platform::alloc_msi_vector(addr_t & address, addr_t & value) +{ + try { + address = Hw::Cpu_memory_map::lapic_phys_base(); + value = Board::Pic::IPI - 1 - msi_allocator().alloc(); + return true; + } catch(...) {} + return false; +} + + +void Platform::free_msi_vector(addr_t, addr_t value) +{ + msi_allocator().free(Board::Pic::IPI - 1 - value); +} Board::Serial::Serial(addr_t, size_t, unsigned baudrate) diff --git a/repos/base-hw/src/core/spec/x86_64/platform_support_common.cc b/repos/base-hw/src/core/spec/x86_64/platform_support_common.cc index e3fe495a18..136459a4f9 100644 --- a/repos/base-hw/src/core/spec/x86_64/platform_support_common.cc +++ b/repos/base-hw/src/core/spec/x86_64/platform_support_common.cc @@ -17,7 +17,7 @@ #include #include -using namespace Genode; +using namespace Core; void Platform::_init_io_port_alloc() diff --git a/repos/base-hw/src/core/spec/x86_64/port_io.h b/repos/base-hw/src/core/spec/x86_64/port_io.h index 10798a8650..ebfcf2095c 100644 --- a/repos/base-hw/src/core/spec/x86_64/port_io.h +++ b/repos/base-hw/src/core/spec/x86_64/port_io.h @@ -14,9 +14,10 @@ #ifndef _CORE__SPEC__X86_64__PORT_IO_H_ #define _CORE__SPEC__X86_64__PORT_IO_H_ -#include +/* core includes */ +#include -namespace Genode { +namespace Core { /** * Read byte from I/O port diff --git a/repos/base-hw/src/core/spec/x86_64/stack_switch.s b/repos/base-hw/src/core/spec/x86_64/stack_switch.s new file mode 100644 index 0000000000..7c5242b8d0 --- /dev/null +++ b/repos/base-hw/src/core/spec/x86_64/stack_switch.s @@ -0,0 +1,35 @@ +/* + * \brief Assembler macros for x86 kernel stack switch + * \author Stefan Kalkowski + * \date 2024-07-02 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +.include "memory_consts.s" + +/* calculate stack from cpu memory area and cpu apic id */ +.macro switch_to_kernel_stack + /* request cpuid 1, result in ebx contains 1-byte apic id at bit 24 */ + movq $1, %rax + cpuid + shr $24, %rbx + and $0xff, %rbx + + /* calculate cpu local memory slot by apic id */ + movq $HW_MM_CPU_LOCAL_MEMORY_SLOT_SIZE, %rax + mulq %rbx + movq $HW_MM_CPU_LOCAL_MEMORY_AREA_START, %rbx + addq %rbx, %rax + + /* calculate top of stack and switch to it */ + movq $HW_MM_KERNEL_STACK_SIZE, %rbx + addq %rbx, %rax + subq $8, %rax + movq %rax, %rsp +.endm diff --git a/repos/base-hw/src/core/spec/x86_64/translation_table.h b/repos/base-hw/src/core/spec/x86_64/translation_table.h deleted file mode 100644 index dc7543cf8f..0000000000 --- a/repos/base-hw/src/core/spec/x86_64/translation_table.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * \brief x86_64 translation table definitions for core - * \author Adrian-Ken Rueegsegger - * \date 2015-02-06 - */ - -/* - * Copyright (C) 2015-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _CORE__SPEC__X86_64__TRANSLATION_TABLE_H_ -#define _CORE__SPEC__X86_64__TRANSLATION_TABLE_H_ - -#include - -#endif /* _CORE__SPEC__X86_64__TRANSLATION_TABLE_H_ */ diff --git a/repos/base-hw/src/core/spec/x86_64/virtualization/board.h b/repos/base-hw/src/core/spec/x86_64/virtualization/board.h new file mode 100644 index 0000000000..889c6cd2d1 --- /dev/null +++ b/repos/base-hw/src/core/spec/x86_64/virtualization/board.h @@ -0,0 +1,95 @@ +/* + * + * \brief Board with PC virtualization support + * \author Benjamin Lamowski + * \date 2022-10-14 + */ + +/* + * Copyright (C) 2022-2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CORE__SPEC__PC__VIRTUALIZATION__BOARD_H_ +#define _CORE__SPEC__PC__VIRTUALIZATION__BOARD_H_ + +/* base-hw core includes */ +#include +#include + +#include +#include +#include +#include +#include +#include + +using Genode::addr_t; +using Genode::uint64_t; + +namespace Board { + struct Vcpu_context; + using Vcpu_data = Genode::Vcpu_data; + using Vcpu_state = Genode::Vcpu_state; + + enum { + VCPU_MAX = 16 + }; + + enum Platform_exitcodes : uint64_t { + EXIT_NPF = 0xfc, + EXIT_INIT = 0xfd, + EXIT_STARTUP = 0xfe, + EXIT_PAUSED = 0xff, + }; + + enum Custom_trapnos : uint64_t { + TRAP_VMEXIT = 256, + TRAP_VMSKIP = 257, + }; +}; + + +namespace Kernel { + class Cpu; + class Vm; +}; + + +struct Board::Vcpu_context +{ + Vcpu_context(unsigned id, Vcpu_data &vcpu_data); + void initialize(Kernel::Cpu &cpu, addr_t table_phys_addr); + void read_vcpu_state(Vcpu_state &state); + void write_vcpu_state(Vcpu_state &state); + + Genode::Align_at regs; + + Virt_interface &virt; + + uint64_t tsc_aux_host = 0U; + uint64_t tsc_aux_guest = 0U; + uint64_t exit_reason = EXIT_INIT; + + static Virt_interface &detect_virtualization(Vcpu_data &vcpu_data, + unsigned id) + { + if (Hw::Virtualization_support::has_svm()) + return *Genode::construct_at( + vcpu_data.virt_area, + vcpu_data, + id); + else if (Hw::Virtualization_support::has_vmx()) { + return *Genode::construct_at( + vcpu_data.virt_area, + vcpu_data); + } else { + Genode::error( "No virtualization support detected."); + throw Core::Service_denied(); + } + } +}; + +#endif /* _CORE__SPEC__PC__VIRTUALIZATION__BOARD_H_ */ diff --git a/repos/base-hw/src/core/spec/x86_64/virtualization/ept.h b/repos/base-hw/src/core/spec/x86_64/virtualization/ept.h new file mode 100644 index 0000000000..e097f11772 --- /dev/null +++ b/repos/base-hw/src/core/spec/x86_64/virtualization/ept.h @@ -0,0 +1,198 @@ +/* + * \brief EPT page table definitions + * \author Benjamin Lamowski + * \date 2024-04-23 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CORE__SPEC__PC__VIRTUALIZATION__EPT_H_ +#define _CORE__SPEC__PC__VIRTUALIZATION__EPT_H_ + +#include +#include +#include + +namespace Hw { + class Ept; + using namespace Genode; + + /* + * Common EPT Permissions + * + * For further details see Intel SDM Vol. 3C + * Table 29-2. Format of an EPT PML4 Entry (PML4E) that References an + * EPT Page-Directory-Pointer Table + */ + struct Ept_common_descriptor : Genode::Register<64> + { + struct R : Bitfield< 0,1> { }; /* Read */ + struct W : Bitfield< 1,1> { }; /* Write */ + struct X : Bitfield< 2,1> { }; /* Execute */ + struct A : Bitfield< 8,1> { }; /* Accessed */ + struct D : Bitfield< 9,1> { }; /* Dirty (ignored in tables) */ + struct UX : Bitfield<10,1> { }; /* User-mode execute access */ + + static bool present(access_t const v) { return R::get(v); } + + static access_t create(Page_flags const &flags) + { + return R::bits(1) + | W::bits(flags.writeable) + | UX::bits(!flags.privileged) + | X::bits(flags.executable); + } + + /** + * Return descriptor value with cleared accessed and dirty flags. These + * flags can be set by the MMU. + */ + static access_t clear_mmu_flags(access_t value) + { + A::clear(value); + D::clear(value); + return value; + } + }; + + + template + struct Pml4e_table_descriptor : Ept_common_descriptor + { + static constexpr size_t PAGE_SIZE_LOG2 = _PAGE_SIZE_LOG2; + static constexpr size_t SIZE_LOG2 = _SIZE_LOG2; + + struct Pa : Bitfield<12, SIZE_LOG2> { }; /* Physical address */ + + static access_t create(addr_t const pa) + { + /* XXX: Set memory type depending on active PAT */ + static Page_flags flags { RW, EXEC, USER, NO_GLOBAL, + RAM, Genode::CACHED }; + return Ept_common_descriptor::create(flags) | Pa::masked(pa); + } + }; + + struct Ept_page_directory_base_descriptor : Ept_common_descriptor + { + using Common = Ept_common_descriptor; + + struct Ps : Common::template Bitfield<7, 1> { }; /* Page size */ + + static bool maps_page(access_t const v) { return Ps::get(v); } + }; + + + template + struct Ept_page_directory_descriptor : Ept_page_directory_base_descriptor + { + static constexpr size_t PAGE_SIZE_LOG2 = _PAGE_SIZE_LOG2; + + struct Page; + struct Table; + }; + + + /* Table 29-7. Format of an EPT Page-Table Entry that Maps a 4-KByte Page */ + template + struct Ept_page_table_entry_descriptor : Ept_common_descriptor + { + using Common = Ept_common_descriptor; + + static constexpr size_t PAGE_SIZE_LOG2 = _PAGE_SIZE_LOG2; + + struct Type : Bitfield< 3, 3> { }; /* Ept memory type, see Section 29.3.7 */ + struct Pat : Bitfield< 6, 1> { }; /* Ignore PAT memory type, see 29.3.7 */ + struct Pa : Bitfield<12,36> { }; /* Physical address */ + + static access_t create(Page_flags const &flags, addr_t const pa) + { + return Common::create(flags) | Pa::masked(pa) | Type::bits(6) | Pat::bits(1); + } + }; + + struct Ept_page_table + : + Genode::Final_table> + { } __attribute__((aligned(1 << ALIGNM_LOG2))); + + struct Ept_pd + : + Genode::Page_directory> + { } __attribute__((aligned(1 << ALIGNM_LOG2))); + + struct Ept_pdpt + : + Genode::Page_directory> + { } __attribute__((aligned(1 << ALIGNM_LOG2))); + + struct Pml4e_table + : + Genode::Pml4_table> + { } __attribute__((aligned(1 << ALIGNM_LOG2))); +} + + +template +struct Hw::Ept_page_directory_descriptor<_PAGE_SIZE_LOG2>::Table + : Ept_page_directory_base_descriptor +{ + using Base = Ept_page_directory_base_descriptor; + + /** + * Physical address + */ + struct Pa : Base::template Bitfield<12, 36> { }; + + static typename Base::access_t create(addr_t const pa) + { + static Page_flags flags { RW, EXEC, USER, NO_GLOBAL, + RAM, Genode::CACHED }; + return Base::create(flags) | Pa::masked(pa); + } +}; + + +template +struct Hw::Ept_page_directory_descriptor<_PAGE_SIZE_LOG2>::Page + : Ept_page_directory_base_descriptor +{ + using Base = Ept_page_directory_base_descriptor; + + struct Type : Bitfield< 3,3> { }; /* Ept memory type, see Section 29.3.7 */ + struct Pat : Bitfield< 6,1> { }; /* Ignore PAT memory type, see 29.3.7 */ + /** + * Physical address + */ + struct Pa : Base::template Bitfield { }; + + + static typename Base::access_t create(Page_flags const &flags, + addr_t const pa) + { + return Base::create(flags) + | Base::Ps::bits(1) + | Pa::masked(pa) + | Type::bits(6) + | Pat::bits(1); + + } +}; + +class Hw::Ept : public Pml4e_table +{ + public: + using Allocator = Genode::Page_table_allocator<1UL << SIZE_LOG2_4KB>; + using Pml4e_table::Pml4e_table; +}; + +#endif /* _CORE__SPEC__PC__VIRTUALIZATION__EPT_H_ */ diff --git a/repos/base-hw/src/core/spec/x86_64/virtualization/hpt.h b/repos/base-hw/src/core/spec/x86_64/virtualization/hpt.h new file mode 100644 index 0000000000..13125f5300 --- /dev/null +++ b/repos/base-hw/src/core/spec/x86_64/virtualization/hpt.h @@ -0,0 +1,229 @@ +/* + * \brief x86_64 AMD nested page table definitions + * \author Benjamin Lamowski + * \date 2024-05-16 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CORE__SPEC__PC__VIRTUALIZATION__HPT_H_ +#define _CORE__SPEC__PC__VIRTUALIZATION__HPT_H_ + +#include +#include +#include + +namespace Hw { + using namespace Genode; + + class Hpt; + + /** + * IA-32e common descriptor. + * + * Table entry containing descriptor fields common to all four levels. + */ + struct Hpt_common_descriptor : Register<64> + { + struct P : Bitfield<0, 1> { }; /* present */ + struct Rw : Bitfield<1, 1> { }; /* read/write */ + struct Us : Bitfield<2, 1> { }; /* user/supervisor */ + struct Pwt : Bitfield<3, 1> { }; /* write-through or PAT defined */ + struct Pcd : Bitfield<4, 1> { }; /* cache disable or PAT defined */ + struct A : Bitfield<5, 1> { }; /* accessed */ + struct D : Bitfield<6, 1> { }; /* dirty */ + struct Xd : Bitfield<63, 1> { }; /* execute-disable */ + + static bool present(access_t const v) { return P::get(v); } + + static access_t create(Page_flags const &flags) + { + return P::bits(1) + | Rw::bits(flags.writeable) + | Us::bits(!flags.privileged) + | Xd::bits(!flags.executable); + } + + /** + * Return descriptor value with cleared accessed and dirty flags. These + * flags can be set by the MMU. + */ + static access_t clear_mmu_flags(access_t value) + { + A::clear(value); + D::clear(value); + return value; + } + }; + + template + struct Pml4_table_descriptor : Hpt_common_descriptor + { + static constexpr size_t SIZE_LOG2 = _SIZE_LOG2; + static constexpr size_t PAGE_SIZE_LOG2 = _PAGE_SIZE_LOG2; + + struct Pa : Bitfield<12, SIZE_LOG2> { }; /* physical address */ + + static access_t create(addr_t const pa) + { + /* XXX: Set memory type depending on active PAT */ + static Page_flags flags { RW, EXEC, USER, NO_GLOBAL, + RAM, CACHED }; + return Hpt_common_descriptor::create(flags) | Pa::masked(pa); + } + }; + + struct Hpt_page_directory_base_descriptor : Hpt_common_descriptor + { + using Common = Hpt_common_descriptor; + + struct Ps : Common::template Bitfield<7, 1> { }; /* page size */ + + static bool maps_page(access_t const v) { return Ps::get(v); } + }; + + template + struct Hpt_page_directory_descriptor : Hpt_page_directory_base_descriptor + { + static constexpr size_t PAGE_SIZE_LOG2 = _PAGE_SIZE_LOG2; + + struct Page; + struct Table; + }; + + + template + struct Page_table_entry_descriptor : Hpt_common_descriptor + { + using Common = Hpt_common_descriptor; + + static constexpr size_t PAGE_SIZE_LOG2 = _PAGE_SIZE_LOG2; + + struct Pat : Bitfield<7, 1> { }; /* page attribute table */ + struct G : Bitfield<8, 1> { }; /* global */ + struct Pa : Bitfield<12, 36> { }; /* physical address */ + + static access_t create(Page_flags const &flags, addr_t const pa) + { + bool const wc = flags.cacheable == Cache::WRITE_COMBINED; + + return Common::create(flags) + | G::bits(flags.global) + | Pa::masked(pa) + | Pwt::bits(wc ? 1 : 0); + } + }; + + struct Level1_translation_table + : + Genode::Final_table> + { } __attribute__((aligned(1 << ALIGNM_LOG2))); + + struct Pd + : + Genode::Page_directory> + { } __attribute__((aligned(1 << ALIGNM_LOG2))); + + struct Pdpt + : + Genode::Page_directory> + { } __attribute__((aligned(1 << ALIGNM_LOG2))); + + struct Pml4_adapted_table + : + Genode::Pml4_table> + { } __attribute__((aligned(1 << ALIGNM_LOG2))); +} + + +template +struct Hw::Hpt_page_directory_descriptor<_PAGE_SIZE_LOG2>::Table + : Hpt_page_directory_base_descriptor +{ + using Base = Hpt_page_directory_base_descriptor; + + /** + * Physical address + */ + struct Pa : Base::template Bitfield<12, 36> { }; + + /** + * Memory types + */ + static typename Base::access_t create(addr_t const pa) + { + /* XXX: Set memory type depending on active PAT */ + static Page_flags flags { RW, EXEC, USER, NO_GLOBAL, + RAM, CACHED }; + return Base::create(flags) | Pa::masked(pa); + } +}; + + +template +struct Hw::Hpt_page_directory_descriptor<_PAGE_SIZE_LOG2>::Page + : Hpt_page_directory_base_descriptor +{ + using Base = Hpt_page_directory_base_descriptor; + + /** + * Global attribute + */ + struct G : Base::template Bitfield<8, 1> { }; + + /** + * Page attribute table + */ + struct Pat : Base::template Bitfield<12, 1> { }; + + /** + * Physical address + */ + struct Pa : Base::template Bitfield { }; + + static typename Base::access_t create(Page_flags const &flags, + addr_t const pa) + { + bool const wc = flags.cacheable == Cache::WRITE_COMBINED; + + return Base::create(flags) + | Base::Ps::bits(1) + | G::bits(flags.global) + | Pa::masked(pa) + | Base::Pwt::bits(wc ? 1 : 0); + } +}; + + +class Hw::Hpt : public Pml4_adapted_table +{ + public: + using Allocator = Genode::Page_table_allocator<1UL << SIZE_LOG2_4KB>; + using Pml4_adapted_table::Pml4_adapted_table; + + bool lookup_rw_translation(addr_t const, addr_t &, Allocator &) + { + raw(__func__, " not implemented yet"); + return false; + } + + enum { + TABLE_LEVEL_X_SIZE_LOG2 = SIZE_LOG2_4KB, + CORE_VM_AREA_SIZE = 1024 * 1024 * 1024, + CORE_TRANS_TABLE_COUNT = + _count(CORE_VM_AREA_SIZE, SIZE_LOG2_512GB) + + _count(CORE_VM_AREA_SIZE, SIZE_LOG2_1GB) + + _count(CORE_VM_AREA_SIZE, SIZE_LOG2_2MB) + }; +}; + +#endif /* _CORE__SPEC__PC__VIRTUALIZATION__HPT_H_ */ diff --git a/repos/base-hw/src/core/spec/x86_64/virtualization/hypervisor.h b/repos/base-hw/src/core/spec/x86_64/virtualization/hypervisor.h new file mode 100644 index 0000000000..86c3935257 --- /dev/null +++ b/repos/base-hw/src/core/spec/x86_64/virtualization/hypervisor.h @@ -0,0 +1,58 @@ +/* + * \brief Interface between kernel and hypervisor + * \author Benjamin Lamowski + * \date 2022-10-14 + */ + +/* + * Copyright (C) 2022 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _SPEC__PC__VIRTUALIZATION_HYPERVISOR_H_ +#define _SPEC__PC__VIRTUALIZATION_HYPERVISOR_H_ + +#include +#include + +namespace Hypervisor { + + using Call_arg = Genode::umword_t; + using Call_ret = Genode::umword_t; + + + inline void restore_state_for_entry(Call_arg regs, Call_arg fpu_context) + { + asm volatile( + "fxrstor (%[fpu_context]);" + "mov %[regs], %%rsp;" + "popq %%r8;" + "popq %%r9;" + "popq %%r10;" + "popq %%r11;" + "popq %%r12;" + "popq %%r13;" + "popq %%r14;" + "popq %%r15;" + "popq %%rax;" + "popq %%rbx;" + "popq %%rcx;" + "popq %%rdx;" + "popq %%rdi;" + "popq %%rsi;" + "popq %%rbp;" + "sti;" /* maybe enter the kernel to handle an external + interrupt that occured ... */ + "nop;" + "cli;" /* ... otherwise, just disable interrupts again */ + "jmp _kernel_entry;" + : + : [regs] "r"(regs), [fpu_context] "r"(fpu_context) + + : "memory"); + }; +} + +#endif /* _SPEC__PC__VIRTUALIZATION_HYPERVISOR_H_ */ diff --git a/repos/base-hw/src/core/spec/x86_64/virtualization/kernel/svm.cc b/repos/base-hw/src/core/spec/x86_64/virtualization/kernel/svm.cc new file mode 100644 index 0000000000..2b5099b415 --- /dev/null +++ b/repos/base-hw/src/core/spec/x86_64/virtualization/kernel/svm.cc @@ -0,0 +1,514 @@ +/* + * \brief SVM specific implementations + * \author Benjamin Lamowski + * \date 2022-10-14 + */ + +/* + * Copyright (C) 2022-2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#include +#include +#include +#include +#include +#include +#include + +using namespace Genode; + +using Kernel::Cpu; +using Kernel::Vm; +using Board::Vmcb; +using Board::Vmcb_buf; + + +Vmcb_buf::Vmcb_buf(addr_t vmcb_page_addr, uint32_t id) +: + Mmio({(char *)vmcb_page_addr, Mmio::SIZE}) +{ + memset((void *) vmcb_page_addr, 0, get_page_size()); + + write(id); + write(dummy_msrpm()); + write(dummy_iopm()); + + /* + * Set the guest PAT register to the default value. + * See: AMD Vol.2 7.8 Page-Attribute Table Mechanism + */ + write(0x0007040600070406ULL); +} + + +Vmcb::Vmcb(Vcpu_data &vcpu_data, uint32_t id) +: + Board::Virt_interface(vcpu_data), + v((addr_t) vcpu_data.virt_area + get_page_size(), id) +{ +} + + +Vmcb_buf &Vmcb::host_vmcb(size_t cpu_id) +{ + static uint8_t host_vmcb_pages[get_page_size() * NR_OF_CPUS]; + static Constructible host_vmcb[NR_OF_CPUS]; + + if (!host_vmcb[cpu_id].constructed()) { + host_vmcb[cpu_id].construct( + (addr_t) host_vmcb_pages + + get_page_size() * cpu_id, + Asid_host); + } + return *host_vmcb[cpu_id]; +} + +void Vmcb::initialize(Kernel::Cpu &cpu, addr_t page_table_phys_addr, + Core::Cpu::Context &) +{ + using Cpu = Hw::X86_64_cpu; + + Cpu::Ia32_efer::access_t ia32_efer_msr = Cpu::Ia32_efer::read(); + Cpu::Ia32_efer::Svme::set(ia32_efer_msr, 1); + Cpu::Ia32_efer::write(ia32_efer_msr); + + Cpu::Amd_vm_syscvg::access_t amd_vm_syscvg_msr = + Cpu::Amd_vm_syscvg::read(); + Cpu::Amd_vm_syscvg::Nested_paging::set(amd_vm_syscvg_msr, 1); + Cpu::Amd_vm_syscvg::write(amd_vm_syscvg_msr); + + root_vmcb_phys = + Core::Platform::core_phys_addr(host_vmcb(cpu.id()).base()); + asm volatile ("vmsave" : : "a" (root_vmcb_phys) : "memory"); + Cpu::Amd_vm_hsavepa::write((Cpu::Amd_vm_hsavepa::access_t) root_vmcb_phys); + + /* + * enable nested paging + */ + v.write(1); + v.write(page_table_phys_addr); + + v.write(1); /* See 15.2 */ + v.write(17); /* AC */ + + enforce_intercepts(); +} + + +/* + * Enforce SVM intercepts + */ +void Vmcb::enforce_intercepts(uint32_t desired_primary, uint32_t desired_secondary) +{ + v.write( + desired_primary | + Vmcb_buf::Intercept_misc1::Intr::bits(1) | + Vmcb_buf::Intercept_misc1::Nmi::bits(1) | + Vmcb_buf::Intercept_misc1::Init::bits(1) | + Vmcb_buf::Intercept_misc1::Invd::bits(1) | + Vmcb_buf::Intercept_misc1::Hlt::bits(1) | + Vmcb_buf::Intercept_misc1::Ioio_prot::bits(1) | + Vmcb_buf::Intercept_misc1::Msr_prot::bits(1) | + Vmcb_buf::Intercept_misc1::Shutdown::bits(1) + ); + v.write( + desired_secondary | + Vmcb_buf::Intercept_misc2::Vmload::bits(1) | + Vmcb_buf::Intercept_misc2::Vmsave::bits(1) | + Vmcb_buf::Intercept_misc2::Clgi::bits(1) | + Vmcb_buf::Intercept_misc2::Skinit::bits(1) + ); +} + + +/* + * AMD Vol.2 15.11: MSR Permissions Map + * All set to 1 since we want all MSRs to be intercepted. + */ +addr_t Vmcb_buf::dummy_msrpm() +{ + static Board::Msrpm msrpm; + + return Core::Platform::core_phys_addr((addr_t) &msrpm); +} + + +/* + * AMD Vol.2 15.10.1 I/O Permissions Map + * All set to 1 since we want all IO port accesses to be intercepted. + */ +addr_t Vmcb_buf::dummy_iopm() +{ + static Board::Iopm iopm; + + return Core::Platform::core_phys_addr((addr_t) &iopm); +} + + +Board::Msrpm::Msrpm() +{ + memset(this, 0xFF, sizeof(*this)); +} + + +Board::Iopm::Iopm() +{ + memset(this, 0xFF, sizeof(*this)); +} + + +void Vmcb::write_vcpu_state(Vcpu_state &state) +{ + state.ax.charge(v.read()); + state.ip.charge(v.read()); + /* + * SVM doesn't use ip_len, so just leave the old value. + * We still have to charge it when charging ip. + */ + state.ip_len.set_charged(); + + state.flags.charge(v.read()); + state.sp.charge(v.read()); + + state.dr7.charge(v.read()); + + state.cr0.charge(v.read()); + state.cr2.charge(v.read()); + state.cr3.charge(v.read()); + state.cr4.charge(v.read()); + + state.cs.charge(Vcpu_state::Segment { + .sel = v.cs.read(), + .ar = v.cs.read(), + .limit = v.cs.read(), + .base = v.cs.read(), + }); + + state.ss.charge(Vcpu_state::Segment { + .sel = v.ss.read(), + .ar = v.ss.read(), + .limit = v.ss.read(), + .base = v.ss.read(), + }); + + state.es.charge(Vcpu_state::Segment { + .sel = v.es.read(), + .ar = v.es.read(), + .limit = v.es.read(), + .base = v.es.read(), + }); + + state.ds.charge(Vcpu_state::Segment { + .sel = v.ds.read(), + .ar = v.ds.read(), + .limit = v.ds.read(), + .base = v.ds.read(), + }); + + state.fs.charge(Vcpu_state::Segment { + .sel = v.fs.read(), + .ar = v.fs.read(), + .limit = v.fs.read(), + .base = v.fs.read(), + }); + + state.gs.charge(Vcpu_state::Segment { + .sel = v.gs.read(), + .ar = v.gs.read(), + .limit = v.gs.read(), + .base = v.gs.read(), + }); + + state.tr.charge(Vcpu_state::Segment { + .sel = v.tr.read(), + .ar = v.tr.read(), + .limit = v.tr.read(), + .base = v.tr.read(), + }); + + state.ldtr.charge(Vcpu_state::Segment { + .sel = v.ldtr.read(), + .ar = v.ldtr.read(), + .limit = v.ldtr.read(), + .base = v.ldtr.read(), + }); + + state.gdtr.charge(Vcpu_state::Range { + .limit = v.gdtr.read(), + .base = v.gdtr.read(), + }); + + state.idtr.charge(Vcpu_state::Range { + .limit = v.idtr.read(), + .base = v.idtr.read(), + }); + + + state.sysenter_cs.charge(v.read()); + state.sysenter_sp.charge(v.read()); + state.sysenter_ip.charge(v.read()); + + state.qual_primary.charge(v.read()); + state.qual_secondary.charge(v.read()); + + /* Charging ctrl_primary and ctrl_secondary breaks Virtualbox 6 */ + + state.inj_info.charge(v.read() & 0xFFFFFFFF); + state.inj_error.charge( + (uint32_t)(v.read() >> 32)); + + /* Guest is in an interrupt shadow, see 15.21.5 */ + state.intr_state.charge( + (unsigned)v.read()); + /* Guest activity state (actv) not used by SVM */ + state.actv_state.set_charged(); + + state.tsc.charge(Hw::Lapic::rdtsc()); + state.tsc_offset.charge(v.read()); + + state.efer.charge(v.read()); + + /* pdpte not used by SVM */ + + state.star.charge(v.read()); + state.lstar.charge(v.read()); + state.cstar.charge(v.read()); + state.fmask.charge(v.read()); + state.kernel_gs_base.charge(v.read()); + + /* Task Priority Register, see 15.24 */ + state.tpr.charge((unsigned)v.read()); + /* TPR threshold not used by SVM */ +} + + +void Vmcb::read_vcpu_state(Vcpu_state &state) +{ + if (state.ax.charged()) v.write(state.ax.value()); + if (state.flags.charged()) v.write(state.flags.value()); + if (state.sp.charged()) v.write(state.sp.value()); + if (state.ip.charged()) v.write(state.ip.value()); + /* ip_len not used by SVM */ + if (state.dr7.charged()) v.write(state.dr7.value()); + + if (state.cr0.charged()) v.write(state.cr0.value()); + if (state.cr2.charged()) v.write(state.cr2.value()); + if (state.cr3.charged()) v.write(state.cr3.value()); + if (state.cr4.charged()) v.write(state.cr4.value()); + + if (state.cs.charged()) { + v.cs.write(state.cs.value().sel); + v.cs.write(state.cs.value().ar); + v.cs.write(state.cs.value().limit); + v.cs.write(state.cs.value().base); + } + + if (state.ss.charged()) { + v.ss.write(state.ss.value().sel); + v.ss.write(state.ss.value().ar); + v.ss.write(state.ss.value().limit); + v.ss.write(state.ss.value().base); + } + + if (state.es.charged()) { + v.es.write(state.es.value().sel); + v.es.write(state.es.value().ar); + v.es.write(state.es.value().limit); + v.es.write(state.es.value().base); + } + + if (state.ds.charged()) { + v.ds.write(state.ds.value().sel); + v.ds.write(state.ds.value().ar); + v.ds.write(state.ds.value().limit); + v.ds.write(state.ds.value().base); + } + + if (state.fs.charged()) { + v.gs.write(state.gs.value().sel); + v.gs.write(state.gs.value().ar); + v.gs.write(state.gs.value().limit); + v.gs.write(state.gs.value().base); + } + + if (state.gs.charged()) { + v.fs.write(state.fs.value().sel); + v.fs.write(state.fs.value().ar); + v.fs.write(state.fs.value().limit); + v.fs.write(state.fs.value().base); + } + + if (state.tr.charged()) { + v.tr.write(state.tr.value().sel); + v.tr.write(state.tr.value().ar); + v.tr.write(state.tr.value().limit); + v.tr.write(state.tr.value().base); + } + + if (state.ldtr.charged()) { + v.ldtr.write(state.ldtr.value().sel); + v.ldtr.write(state.ldtr.value().ar); + v.ldtr.write(state.ldtr.value().limit); + v.ldtr.write(state.ldtr.value().base); + } + + if (state.gdtr.charged()) { + v.gdtr.write(state.gdtr.value().limit); + v.gdtr.write(state.gdtr.value().base); + } + + if (state.idtr.charged()) { + v.idtr.write(state.idtr.value().limit); + v.idtr.write(state.idtr.value().base); + } + + if (state.sysenter_cs.charged()) + v.write(state.sysenter_cs.value()); + + if (state.sysenter_sp.charged()) + v.write(state.sysenter_sp.value()); + + if (state.sysenter_ip.charged()) + v.write(state.sysenter_ip.value()); + + if (state.ctrl_primary.charged() || state.ctrl_secondary.charged()) { + enforce_intercepts(state.ctrl_primary.value(), + state.ctrl_secondary.value()); + } + + if (state.inj_info.charged() || state.inj_error.charged()) { + /* Honor special signaling bit */ + if (state.inj_info.value() & 0x1000) { + v.write(1); + v.write(1); + v.write(1); + } else { + v.write(0); + v.write(0); + v.write(0); + } + + v.write( + /* Filter out special signaling bits */ + (state.inj_info.value() & + (uint32_t) ~0x3000) | + (((uint64_t) state.inj_error.value()) << 32) + ); + } + + if (state.intr_state.charged()) { + v.write( + state.intr_state.value()); + } + /* Guest activity state (actv) not used by SVM */ + + if (state.tsc_offset.charged()) { + /* state.tsc not used by SVM */ + v.write(v.read() + + state.tsc_offset.value()); + } + + if (state.efer.charged()) { + v.write(state.efer.value()); + } + + /* pdpte not used by SVM */ + + if (state.star.charged()) v.write(state.star.value()); + if (state.cstar.charged()) v.write(state.cstar.value()); + if (state.lstar.charged()) v.write(state.lstar.value()); + if (state.fmask.charged()) v.write(state.lstar.value()); + if (state.kernel_gs_base.charged()) + v.write(state.kernel_gs_base.value()); + + if (state.tpr.charged()) + v.write(state.tpr.value()); + /* TPR threshold not used on AMD */ +} + + +uint64_t Vmcb::handle_vm_exit() +{ + enum Svm_exitcodes : uint64_t + { + SVM_EXIT_INVALID = -1ULL, + SVM_VMEXIT_INTR = 0x60, + SVM_VMEXIT_NPF = 0x400, + }; + + uint64_t exitcode = v.read(); + switch (exitcode) { + case SVM_EXIT_INVALID: + error("VM: invalid SVM state!"); + break; + case 0x40 ... 0x5f: + error("VM: unhandled SVM exception ", + Hex(exitcode)); + break; + case SVM_VMEXIT_INTR: + exitcode = EXIT_PAUSED; + break; + case SVM_VMEXIT_NPF: + exitcode = EXIT_NPF; + break; + default: + break; + } + + return exitcode; +} + +void Vmcb::switch_world(Core::Cpu::Context ®s) +{ + /* + * We push the host context's physical address to trapno so that + * we can pop it later + */ + regs.trapno = root_vmcb_phys; + asm volatile( + "fxrstor (%[fpu_context]);" + "mov %[guest_state], %%rax;" + "mov %[regs], %%rsp;" + "popq %%r8;" + "popq %%r9;" + "popq %%r10;" + "popq %%r11;" + "popq %%r12;" + "popq %%r13;" + "popq %%r14;" + "popq %%r15;" + "add $8, %%rsp;" /* don't pop rax */ + "popq %%rbx;" + "popq %%rcx;" + "popq %%rdx;" + "popq %%rdi;" + "popq %%rsi;" + "popq %%rbp;" + "clgi;" + "sti;" + "vmload;" + "vmrun;" + "vmsave;" + "popq %%rax;" /* get the physical address of the host VMCB from + the stack */ + "vmload;" + "stgi;" /* maybe enter the kernel to handle an external interrupt + that occured ... */ + "nop;" + "cli;" /* ... otherwise, just disable interrupts again */ + "pushq %[trap_vmexit];" /* make the stack point to trapno, the right place + to jump to _kernel_entry. We push 256 because + this is outside of the valid range for interrupts + */ + "jmp _kernel_entry;" /* jump to _kernel_entry to save the + GPRs without breaking any */ + : + : [regs] "r"(®s.r8), [fpu_context] "r"(regs.fpu_context()), + [guest_state] "r"(vcpu_data.phys_addr + get_page_size()), + [trap_vmexit] "i"(TRAP_VMEXIT) + : "rax", "memory"); +} diff --git a/repos/base-hw/src/core/spec/x86_64/virtualization/kernel/vm.cc b/repos/base-hw/src/core/spec/x86_64/virtualization/kernel/vm.cc new file mode 100644 index 0000000000..750d8f2d5f --- /dev/null +++ b/repos/base-hw/src/core/spec/x86_64/virtualization/kernel/vm.cc @@ -0,0 +1,271 @@ +/* + * \brief Kernel backend for x86 virtual machines + * \author Benjamin Lamowski + * \date 2022-10-14 + */ + +/* + * Copyright (C) 2022-2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace Genode; + +using Kernel::Cpu; +using Kernel::Vm; + + +Vm::Vm(Irq::Pool & user_irq_pool, + Cpu & cpu, + Vcpu_data & data, + Kernel::Signal_context & context, + Identity & id) +: + Kernel::Object { *this }, + Cpu_job(Scheduler::Priority::min(), 0), + _user_irq_pool(user_irq_pool), + _state(*data.vcpu_state), + _context(context), + _id(id), + _vcpu_context(id.id, data) +{ + affinity(cpu); +} + + +Vm::~Vm() +{ +} + + +void Vm::proceed(Cpu & cpu) +{ + using namespace Board; + cpu.switch_to(*_vcpu_context.regs); + + if (_vcpu_context.exit_reason == EXIT_INIT) { + _vcpu_context.regs->trapno = TRAP_VMSKIP; + Hypervisor::restore_state_for_entry((addr_t)&_vcpu_context.regs->r8, + _vcpu_context.regs->fpu_context()); + /* jumps to _kernel_entry */ + } + + Cpu::Ia32_tsc_aux::write( + (Cpu::Ia32_tsc_aux::access_t)_vcpu_context.tsc_aux_guest); + + _vcpu_context.virt.switch_world(*_vcpu_context.regs); + /* + * This will fall into an interrupt or otherwise jump into + * _kernel_entry. If VMX encountered a severe error condition, + * it will print an error message and regularly return from the world + * switch. In this case, just remove the vCPU thread from the scheduler. + */ + _pause_vcpu(); +} + + +void Vm::exception(Cpu & cpu) +{ + using namespace Board; + + bool pause = false; + + switch (_vcpu_context.regs->trapno) { + case TRAP_VMEXIT: + _vcpu_context.exit_reason = + _vcpu_context.virt.handle_vm_exit(); + /* + * If handle_vm_exit() returns EXIT_PAUSED, the vCPU has + * exited due to a host interrupt. The exit reason is + * set to EXIT_PAUSED so that if the VMM queries the + * vCPU state while the vCPU is stopped, it is clear + * that it does not need to handle a synchronous vCPU exit. + * + * VMX jumps directly to __kernel_entry when exiting + * guest mode and skips the interrupt vectors, therefore + * trapno will not be set to the host interrupt and we + * have to explicitly handle interrupts here. + * + * SVM on the other hand will service the host interrupt + * after the stgi instruction (see + * AMD64 Architecture Programmer's Manual Vol 2 + * 15.17 Global Interrupt Flag, STGI and CLGI Instructions) + * and will jump to the interrupt vector, setting trapno + * to the host interrupt. This means the exception + * handler should actually skip this case branch, which + * is fine because _vcpu_context.exit_reason is set to + * EXIT_PAUSED by default, so a VMM querying the vCPU + * state will still get the right value. + * + * For any other exit reason, we exclude this vCPU + * thread from being scheduled and signal the VMM that + * it needs to handle an exit. + */ + if (_vcpu_context.exit_reason == EXIT_PAUSED) + _interrupt(_user_irq_pool, cpu.id()); + else + pause = true; + break; + case Cpu_state::INTERRUPTS_START ... Cpu_state::INTERRUPTS_END: + _interrupt(_user_irq_pool, cpu.id()); + break; + case TRAP_VMSKIP: + /* vCPU is running for the first time */ + _vcpu_context.initialize(cpu, + reinterpret_cast(_id.table)); + _vcpu_context.tsc_aux_host = cpu.id(); + /* + * We set the artificial startup exit code, stop the + * vCPU thread and ask the VMM to handle it. + */ + _vcpu_context.exit_reason = EXIT_STARTUP; + pause = true; + break; + default: + error("VM: triggered unknown exception ", + _vcpu_context.regs->trapno, + " with error code ", _vcpu_context.regs->errcode, + " at ip=", + (void *)_vcpu_context.regs->ip, " sp=", + (void *)_vcpu_context.regs->sp); + _pause_vcpu(); + break; + }; + + if (pause == true) { + _pause_vcpu(); + _context.submit(1); + } +} + + +void Vm::_sync_to_vmm() +{ + _vcpu_context.write_vcpu_state(_state); + + /* + * Set exit code so that if _run() was not called after an exit, the + * next exit due to a signal will be interpreted as PAUSE request. + */ + _vcpu_context.exit_reason = Board::EXIT_PAUSED; +} + + +void Vm::_sync_from_vmm() +{ + /* first run() will skip through to issue startup exit */ + if (_vcpu_context.exit_reason == Board::EXIT_INIT) + return; + + _vcpu_context.read_vcpu_state(_state); +} + +Board::Vcpu_context::Vcpu_context(unsigned id, Vcpu_data &vcpu_data) +: + regs(1), + virt(detect_virtualization(vcpu_data, id)) +{ + regs->trapno = TRAP_VMEXIT; +} + +void Board::Vcpu_context::read_vcpu_state(Vcpu_state &state) +{ + virt.read_vcpu_state(state); + + if (state.cx.charged() || state.dx.charged() || state.bx.charged()) { + regs->rax = state.ax.value(); + regs->rcx = state.cx.value(); + regs->rdx = state.dx.value(); + regs->rbx = state.bx.value(); + } + + if (state.bp.charged() || state.di.charged() || state.si.charged()) { + regs->rdi = state.di.value(); + regs->rsi = state.si.value(); + regs->rbp = state.bp.value(); + } + + if (state.r8 .charged() || state.r9 .charged() || + state.r10.charged() || state.r11.charged() || + state.r12.charged() || state.r13.charged() || + state.r14.charged() || state.r15.charged()) { + + regs->r8 = state.r8.value(); + regs->r9 = state.r9.value(); + regs->r10 = state.r10.value(); + regs->r11 = state.r11.value(); + regs->r12 = state.r12.value(); + regs->r13 = state.r13.value(); + regs->r14 = state.r14.value(); + regs->r15 = state.r15.value(); + } + + if (state.fpu.charged()) { + state.fpu.with_state( + [&](Vcpu_state::Fpu::State const &fpu) { + memcpy((void *) regs->fpu_context(), &fpu, sizeof(fpu)); + }); + } +} + +void Board::Vcpu_context::write_vcpu_state(Vcpu_state &state) +{ + state.discharge(); + state.exit_reason = (unsigned) exit_reason; + + state.fpu.charge([&](Vcpu_state::Fpu::State &fpu) { + memcpy(&fpu, (void *) regs->fpu_context(), sizeof(fpu)); + }); + + /* SVM will overwrite rax but VMX doesn't. */ + state.ax.charge(regs->rax); + state.cx.charge(regs->rcx); + state.dx.charge(regs->rdx); + state.bx.charge(regs->rbx); + + state.di.charge(regs->rdi); + state.si.charge(regs->rsi); + state.bp.charge(regs->rbp); + + state.r8.charge(regs->r8); + state.r9.charge(regs->r9); + state.r10.charge(regs->r10); + state.r11.charge(regs->r11); + state.r12.charge(regs->r12); + state.r13.charge(regs->r13); + state.r14.charge(regs->r14); + state.r15.charge(regs->r15); + + state.tsc.charge(Hw::Lapic::rdtsc()); + + tsc_aux_guest = Cpu::Ia32_tsc_aux::read(); + state.tsc_aux.charge(tsc_aux_guest); + Cpu::Ia32_tsc_aux::write((Cpu::Ia32_tsc_aux::access_t) tsc_aux_host); + + virt.write_vcpu_state(state); +} + + +void Board::Vcpu_context::initialize(Kernel::Cpu &cpu, addr_t table_phys_addr) +{ + virt.initialize(cpu, table_phys_addr, *regs); +} diff --git a/repos/base-hw/src/core/spec/x86_64/virtualization/kernel/vmx.cc b/repos/base-hw/src/core/spec/x86_64/virtualization/kernel/vmx.cc new file mode 100644 index 0000000000..83900e6df4 --- /dev/null +++ b/repos/base-hw/src/core/spec/x86_64/virtualization/kernel/vmx.cc @@ -0,0 +1,924 @@ +/* + * VMX virtualization + * \author Benjamin Lamowski + * \date 2023-10-04 + */ + +/* + * Copyright (C) 2023-2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using Genode::addr_t; +using Kernel::Cpu; +using Kernel::Vm; +using Board::Vmcs; +using Board::Vmcs_buf; + +extern "C" +{ + extern Genode::addr_t _kernel_entry; +} + +Genode::uint32_t Vmcs::system_rev = 0U; +Genode::uint32_t Vmcs::pinbased_allowed_0 = 0U; +Genode::uint32_t Vmcs::pinbased_allowed_1 = 0U; +Genode::uint32_t Vmcs::pri_exit_allowed_0 = 0U; +Genode::uint32_t Vmcs::pri_exit_allowed_1 = 0U; +Genode::uint32_t Vmcs::vm_entry_allowed_0 = 0U; +Genode::uint32_t Vmcs::vm_entry_allowed_1 = 0U; +Genode::uint32_t Vmcs::pri_procbased_allowed_0 = 0U; +Genode::uint32_t Vmcs::pri_procbased_allowed_1 = 0U; +Genode::uint32_t Vmcs::sec_procbased_allowed_0 = 0U; +Genode::uint32_t Vmcs::sec_procbased_allowed_1 = 0U; +Genode::uint64_t Vmcs::cr0_fixed0 = 0U; +Genode::uint64_t Vmcs::cr0_fixed1 = 0U; +Genode::uint64_t Vmcs::cr0_mask = 0U; +Genode::uint64_t Vmcs::cr4_fixed0 = 0U; +Genode::uint64_t Vmcs::cr4_fixed1 = 0U; +Genode::uint64_t Vmcs::cr4_mask = 0U; +extern int __idt; + +Vmcs * current_vmcs[Hw::Pc_board::NR_OF_CPUS] = { nullptr }; + +Vmcs_buf::Vmcs_buf(Genode::uint32_t system_rev) +{ + Genode::memset((void *) this, 0, sizeof(Vmcs_buf)); + rev = system_rev; +} + +Vmcs::Vmcs(Genode::Vcpu_data &vcpu_data) +: + Board::Virt_interface(vcpu_data) +{ + if (!system_rev) + setup_vmx_info(); + + Genode::construct_at((void *)(((addr_t) vcpu_data.virt_area) + + get_page_size()), system_rev); +} + + +void Vmcs::construct_host_vmcs() +{ + static Genode::Constructible host_vmcs_buf[NR_OF_CPUS]; + + if (!host_vmcs_buf[_cpu_id].constructed()) { + host_vmcs_buf[_cpu_id].construct(system_rev); + + Genode::addr_t host_vmcs_phys = + Core::Platform::core_phys_addr( + (addr_t)& host_vmcs_buf[_cpu_id]); + + vmxon(host_vmcs_phys); + } +} + +/* + * Setup static VMX information. This only works well as long as Intel's E and P + * cores report the same feature set. + */ +void Vmcs::setup_vmx_info() +{ + using Cpu = Hw::X86_64_cpu; + + + /* Get revision */ + Cpu::Ia32_vmx_basic::access_t vmx_basic = Cpu::Ia32_vmx_basic::read(); + system_rev = Cpu::Ia32_vmx_basic::Rev::get(vmx_basic); + + + /* Get pin-based controls */ + bool clear_controls = + Cpu::Ia32_vmx_basic::Clear_controls::get(vmx_basic); + + + Genode::uint64_t pinbased_ctls { }; + + if (clear_controls) + pinbased_ctls = Cpu::Ia32_vmx_true_pinbased_ctls::read(); + else + pinbased_ctls = Cpu::Ia32_vmx_pinbased_ctls::read(); + + pinbased_allowed_0 = + Cpu::Ia32_vmx_pinbased_ctls::Allowed_0_settings::get(pinbased_ctls); + + /* + * Vol. 3C of the Intel SDM (September 2023): + * 25.6.1 Pin-Based VM-Execution Controls + * "Logical processors that support the 0-settings of any of these bits + * will support the VMX capability MSR IA32_VMX_TRUE_PIN- BASED_CTLS + * MSR, and software should consult this MSR to discover support for the + * 0-settings of these bits. Software that is not aware of the + * functionality of any one of these bits should set that bit to 1. + */ + Pin_based_execution_controls::Bit_1::set(pinbased_allowed_0); + Pin_based_execution_controls::Bit_2::set(pinbased_allowed_0); + Pin_based_execution_controls::Bit_4::set(pinbased_allowed_0); + pinbased_allowed_1 = + Cpu::Ia32_vmx_pinbased_ctls::Allowed_1_settings::get(pinbased_ctls); + + + /* Get entry controls */ + Genode::uint64_t vm_entry_ctls { }; + + if (clear_controls) + vm_entry_ctls = Cpu::Ia32_vmx_true_entry_ctls::read(); + else + vm_entry_ctls = Cpu::Ia32_vmx_entry_ctls::read(); + + vm_entry_allowed_0 = + Cpu::Ia32_vmx_entry_ctls::Allowed_0_settings::get(vm_entry_ctls); + vm_entry_allowed_1 = + Cpu::Ia32_vmx_entry_ctls::Allowed_1_settings::get(vm_entry_ctls); + + + /* Get primary exit controls */ + Genode::uint64_t pri_exit_ctls { }; + + if (clear_controls) + pri_exit_ctls = Cpu::Ia32_vmx_true_exit_ctls::read(); + else + pri_exit_ctls = Cpu::Ia32_vmx_exit_ctls::read(); + + pri_exit_allowed_0 = + Cpu::Ia32_vmx_exit_ctls::Allowed_0_settings::get(pri_exit_ctls); + pri_exit_allowed_1 = + Cpu::Ia32_vmx_exit_ctls::Allowed_1_settings::get(pri_exit_ctls); + + /* Get primary proc-based exit controls */ + Genode::uint64_t pri_procbased_ctls { }; + + if (clear_controls) + pri_procbased_ctls = Cpu::Ia32_vmx_true_procbased_ctls::read(); + else + pri_procbased_ctls = Cpu::Ia32_vmx_procbased_ctls::read(); + + pri_procbased_allowed_0 = + Cpu::Ia32_vmx_procbased_ctls::Allowed_0_settings::get( + pri_procbased_ctls); + pri_procbased_allowed_1 = + Cpu::Ia32_vmx_procbased_ctls::Allowed_1_settings::get( + pri_procbased_ctls); + + /* + * Make sure that required features are available. + * At this point the VM session is already established. + * To our knowledge the required feature set should be available on any + * x86_64 processor that indicated VMX support, so we resolve to panic + * if the required feature set is not available. + */ + if (!Primary_proc_based_execution_controls:: + Activate_secondary_controls::get(pri_procbased_allowed_1)) { + Kernel::panic("Processor does not support secondary controls"); + } + + /* Get secondary proc-based exec controls */ + Cpu::Ia32_vmx_procbased_ctls2::access_t sec_procbased_ctls = + Cpu::Ia32_vmx_procbased_ctls2::read(); + sec_procbased_allowed_0 = + Cpu::Ia32_vmx_procbased_ctls::Allowed_0_settings::get( + sec_procbased_ctls); + sec_procbased_allowed_1 = + Cpu::Ia32_vmx_procbased_ctls::Allowed_1_settings::get( + sec_procbased_ctls); + + if (!Secondary_proc_based_execution_controls::Enable_ept::get( + sec_procbased_allowed_1)) { + Kernel::panic("Processor does not support nested page tables"); + } + + if (!Secondary_proc_based_execution_controls::Unrestricted_guest::get( + sec_procbased_allowed_1)) { + Kernel::panic("Processor does not support Unrestricted guest mode"); + } + + if (!Primary_proc_based_execution_controls::Use_tpr_shadow::get( + pri_procbased_allowed_1)) { + Kernel::panic("Processor does not support VTPR"); + } + + /* CR0 and CR4 fixed values */ + cr0_fixed0 = Cpu::Ia32_vmx_cr0_fixed0::read(); + cr0_fixed1 = Cpu::Ia32_vmx_cr0_fixed1::read(); + + /* + * We demand that unrestriced guest mode is used, hence don't force PE + * and PG + * For details, see Vol. 3C of the Intel SDM (September 2023): + * 24.8 Restrictions on VMX Operation + * Yes, forced-to-one bits are in fact read from IA32_VMX_CR0_FIXED0. + */ + Cpu::Cr0::Pe::clear(cr0_fixed0); + Cpu::Cr0::Pg::clear(cr0_fixed0); + + cr0_mask = ~cr0_fixed1 | cr0_fixed0; + Cpu::Cr0::Cd::set(cr0_mask); + Cpu::Cr0::Nw::set(cr0_mask); + + cr4_fixed0 = Cpu::Ia32_vmx_cr4_fixed0::read(); + cr4_fixed1 = Cpu::Ia32_vmx_cr4_fixed1::read(); + cr4_mask = ~cr4_fixed1 | cr4_fixed0; +} + +void Vmcs::initialize(Kernel::Cpu &cpu, Genode::addr_t page_table_phys, + Core::Cpu::Context ®s) +{ + using Cpu = Hw::X86_64_cpu; + + /* Enable VMX */ + Cpu::Ia32_feature_control::access_t feature_control = + Cpu::Ia32_feature_control::read(); + if (!Cpu::Ia32_feature_control::Vmx_no_smx::get(feature_control)) { + Genode::log("Enabling VMX."); + if (!Cpu::Ia32_feature_control::Lock::get(feature_control)) { + Cpu::Ia32_feature_control::Vmx_no_smx::set(feature_control, 1); + Cpu::Ia32_feature_control::Lock::set(feature_control, 1); + Cpu::Ia32_feature_control::write(feature_control); + } else { + /* + * Since the lock condition has been checked in + * Hw::Virtualization_support::has_vmx(), this should never happen. + */ + Kernel::panic("VMX feature disabled"); + } + } + + Cpu::Cr4::access_t cr4 = Cpu::Cr4::read(); + Cpu::Cr4::Vmxe::set(cr4); + Cpu::Cr4::write(cr4); + + _cpu_id = cpu.id(); + + construct_host_vmcs(); + + Genode::construct_at( + (void *)(((addr_t) vcpu_data.virt_area) + 2 * get_page_size())); + + + vmclear(vcpu_data.phys_addr + get_page_size()); + _load_pointer(); + + prepare_vmcs(); + + /* + * Set the VMCS link pointer to ~0UL according to spec + * For details, see Vol. 3C of the Intel SDM (September 2023): + * 25.4.2 Guest Non-Register State: vmcs link pointer + */ + write(E_VMCS_LINK_POINTER, ~0ULL); + + /* + * Set up the Embedded Page Table Pointer + * For details, see Vol. 3C of the Intel SDM (September 2023): + * 25.6.11 Extended-Page-Table Pointer (EPTP) + */ + struct Ept_ptr : Genode::Register<64> { + struct Memory_type : Bitfield< 0,3> { }; + struct Ept_walk_length_minus_1 : Bitfield< 3,3> { }; + struct Phys_addr_4k_aligned : Bitfield<12,51> { }; + }; + + enum Memory_type { + EPT_UNCACHEABLE = 0, + EPT_WRITEBACK = 6, + }; + + /* We have a 4 level page table */ + const uint8_t ept_length = 4; + Ept_ptr::access_t ept_ptr { 0 }; + Ept_ptr::Memory_type::set(ept_ptr, EPT_WRITEBACK); + Ept_ptr::Ept_walk_length_minus_1::set(ept_ptr, ept_length - 1); + Ept_ptr::Phys_addr_4k_aligned::set(ept_ptr, page_table_phys >> 12); + write(E_EPT_POINTER, ept_ptr); + + + write(E_HOST_IA32_EFER, Cpu::Ia32_efer::read()); + + /* + * If this looks the wrong way around then you are in good company. + * For details, and a nonchalant explanation of this cursed interface, + * see Vol. 3D of the Intel SDM (September 2023): + * A.7 VMX-Fixed Bits in CR0 + */ + Genode::uint64_t cr0 = Cpu::Cr0::read(); + + cr0 = (cr0 & cr0_fixed1) | cr0_fixed0; + /* NW and CD shouln'd be set by hw in the first place, but to be sure. */ + Cpu::Cr0::Nw::clear(cr0); + Cpu::Cr0::Cd::clear(cr0); + Cpu::Cr0::write(cr0); + write(E_HOST_CR0, cr0); + write(E_CR0_GUEST_HOST_MASK, cr0_mask); + + write(E_HOST_CR3, Cpu::Cr3::read()); + + /* See above */ + cr4 = (cr4 & cr4_fixed1) | cr4_fixed0; + Cpu::Cr4::write(cr4); + write(E_HOST_CR4, cr4); + write(E_CR4_GUEST_HOST_MASK, cr4_mask); + + + /* offsets from GDT in src/core/spec/x86_64/cpu.h */ + write(E_HOST_CS_SELECTOR, 0x8); + + write(E_HOST_FS_SELECTOR, 0); + write(E_HOST_GS_SELECTOR, 0); + + write(E_HOST_TR_BASE, reinterpret_cast(&(cpu.tss))); + /* see Cpu::Tss::init() / the tss_descriptor is in slot 5 of the GDT */ + write(E_HOST_TR_SELECTOR, 0x28); + write(E_HOST_GDTR_BASE, reinterpret_cast(&(cpu.gdt))); + write(E_HOST_IDTR_BASE, reinterpret_cast(&__idt)); + + write(E_HOST_IA32_SYSENTER_ESP, reinterpret_cast(&(cpu.tss.rsp[0]))); + write(E_HOST_IA32_SYSENTER_CS, 0x8); + write(E_HOST_IA32_SYSENTER_EIP, reinterpret_cast(&_kernel_entry)); + + /* + * Set the RSP to trapno, so that _kernel_entry will save the registers + * into the right fields. + */ + write(E_HOST_RSP, reinterpret_cast(&(regs.trapno))); + write(E_HOST_RIP, reinterpret_cast(&_kernel_entry)); +} + + +/* + * Enforce VMX intercepts + */ +void Vmcs::enforce_execution_controls(Genode::uint32_t desired_primary, + Genode::uint32_t desired_secondary) +{ + /* + * Processor-Based VM-Execution Controls + * + * For details, see Vol. 3C of the Intel SDM (September 2023): + * 25.6.2 Processor-Based VM-Execution Controls + */ + + /* Exit on HLT instruction */ + Primary_proc_based_execution_controls::Hlt_exiting::set(desired_primary); + + /* Enforce use of nested paging */ + Primary_proc_based_execution_controls::Invlpg_exiting::clear(desired_primary); + Primary_proc_based_execution_controls::Cr3_load_exiting::clear(desired_primary); + Primary_proc_based_execution_controls::Cr3_store_exiting::clear(desired_primary); + Primary_proc_based_execution_controls::Activate_secondary_controls::set(desired_primary); + Secondary_proc_based_execution_controls::Enable_ept::set(desired_secondary); + Secondary_proc_based_execution_controls::Unrestricted_guest::set(desired_secondary); + Secondary_proc_based_execution_controls::Enable_vpid::clear(desired_secondary); + + /* + * Always exit on IO and MSR accesses. + * For details, see Vol. 3C of the Intel SDM (September 2023): + * 26.1.3 Instructions That Cause VM Exits Conditionally + */ + Primary_proc_based_execution_controls::Unconditional_io_exiting::set(desired_primary); + Primary_proc_based_execution_controls::Use_io_bitmaps::clear(desired_primary); + Primary_proc_based_execution_controls::Use_msr_bitmaps::clear(desired_primary); + + /* + * Force a Virtual task-priority register (VTPR) + * For details, see Vol. 3C of the Intel SDM (September 2023): + * 30.1.1 Virtualized APIC Registers + */ + Primary_proc_based_execution_controls::Use_tpr_shadow::set(desired_primary); + + Genode::uint32_t pri_procbased_set = + (desired_primary | pri_procbased_allowed_0) + & pri_procbased_allowed_1; + write(E_PRI_PROC_BASED_VM_EXEC_CTRL, pri_procbased_set); + + Genode::uint32_t sec_procbased_set = + (desired_secondary | sec_procbased_allowed_0) + & sec_procbased_allowed_1; + write(E_SEC_PROC_BASED_VM_EXEC_CTRL, sec_procbased_set); +} + +void Vmcs::prepare_vmcs() +{ + /* + * Pin-Based VM-Execution Controls + * + * For details, see Vol. 3C of the Intel SDM (September 2023): + * 25.6.1 Pin-Based VM-Execution Controls + */ + Genode::uint32_t pinbased_want = 0U; + Pin_based_execution_controls::External_interrupt_exiting::set(pinbased_want); + Pin_based_execution_controls::Nmi_exiting::set(pinbased_want); + Pin_based_execution_controls::Virtual_nmis::set(pinbased_want); + Genode::uint32_t pinbased_set = (pinbased_want | pinbased_allowed_0) + & pinbased_allowed_1; + write(E_PIN_BASED_VM_EXECUTION_CTRL, pinbased_set); + + /* + * Primary VM-Exit Controls + * + * For details, see Vol. 3C of the Intel SDM (September 2023): + * Table 25-13. Definitions of Primary VM-Exit Controls + */ + Genode::uint32_t primary_exit_want = 0U; + Primary_vm_exit_controls::Save_debug_controls::set(primary_exit_want); + Primary_vm_exit_controls::Host_address_space_size::set(primary_exit_want); + Primary_vm_exit_controls::Ack_interrupt_on_exit::set(primary_exit_want); + Primary_vm_exit_controls::Save_ia32_efer::set(primary_exit_want); + Primary_vm_exit_controls::Load_ia32_efer::set(primary_exit_want); + Genode::uint32_t primary_exit_set = + (primary_exit_want | pri_exit_allowed_0) & pri_exit_allowed_1; + write(E_PRIMARY_VM_EXIT_CONTROLS, primary_exit_set); + + /* + * VM-Entry Controls + * + * For details, see Vol. 3C of the Intel SDM (September 2023): + * Table 25-13. Definitions of Primary VM-Exit Controls + * 25.8.1 VM-Entry Controls + */ + Genode::uint32_t vm_entry_want = 0U; + Vm_entry_controls::Load_debug_controls::set(vm_entry_want); + Vm_entry_controls::Load_ia32_efer::set(vm_entry_want); + Genode::uint32_t vm_entry_set = + (vm_entry_want | vm_entry_allowed_0) & vm_entry_allowed_1; + write(E_VM_ENTRY_CONTROLS, vm_entry_set); + + + enforce_execution_controls(0U, 0U); + + write(E_VM_EXIT_MSR_STORE_ADDRESS, msr_phys_addr(&guest_msr_store_area)); + write(E_VM_EXIT_MSR_STORE_COUNT, Board::Msr_store_area::get_count()); + write(E_VM_ENTRY_MSR_LOAD_ADDRESS, msr_phys_addr(&guest_msr_store_area)); + write(E_VM_ENTRY_MSR_LOAD_COUNT, Board::Msr_store_area::get_count()); + + write(E_VM_EXIT_MSR_LOAD_ADDRESS, msr_phys_addr(&host_msr_store_area)); + write(E_VM_EXIT_MSR_LOAD_COUNT, Board::Msr_store_area::get_count()); + + write(E_VIRTUAL_APIC_ADDRESS, vcpu_data.phys_addr + 2 * get_page_size()); + + /* + * For details, see Vol. 3C of the Intel SDM (September 2023): + * 26.2 Other Causes Of VM Exits: Exceptions + */ + write(E_EXCEPTION_BITMAP, (1 << Genode::Cpu_state::ALIGNMENT_CHECK) | + (1 << Genode::Cpu_state::DEBUG)); + write(E_PAGE_FAULT_ERROR_CODE_MASK, 0U); + write(E_PAGE_FAULT_ERROR_CODE_MATCH, 0U); + + /* + * For now, don't use CR3 targets. + * For details, see Vol. 3C of the Intel SDM (September 2023): + * 25.6.7 CR3-Target Controls + */ + write(E_CR3_TARGET_COUNT, 0U); +} + +void Vmcs::write_vcpu_state(Genode::Vcpu_state &state) +{ + using Range = Genode::Vcpu_state::Range; + using Segment = Genode::Vcpu_state::Segment; + using Cpu = Hw::X86_64_cpu; + + using Genode::uint16_t; + using Genode::uint32_t; + + _load_pointer(); + + state.ip.charge(read(E_GUEST_RIP)); + state.ip_len.charge(read(E_VM_EXIT_INSTRUCTION_LENGTH)); + + state.flags.charge(read(E_GUEST_RFLAGS)); + state.sp.charge(read(E_GUEST_RSP)); + + state.dr7.charge(read(E_GUEST_DR7)); + + state.cr0.charge(read(E_GUEST_CR0)); + state.cr2.charge(Cpu::Cr2::read()); + state.cr3.charge(read(E_GUEST_CR3)); + state.cr4.charge(read(E_GUEST_CR4)); + + state.cs.charge(Segment { + .sel = static_cast(read(E_GUEST_CS_SELECTOR)), + .ar = _ar_convert_to_genode(read(E_GUEST_CS_ACCESS_RIGHTS)), + .limit = static_cast(read(E_GUEST_CS_LIMIT)), + .base = read(E_GUEST_CS_BASE) + }); + + state.ss.charge(Segment { + .sel = static_cast(read(E_GUEST_SS_SELECTOR)), + .ar = _ar_convert_to_genode(read(E_GUEST_SS_ACCESS_RIGHTS)), + .limit = static_cast(read(E_GUEST_SS_LIMIT)), + .base = read(E_GUEST_SS_BASE) + }); + + state.es.charge(Segment { + .sel = static_cast(read(E_GUEST_ES_SELECTOR)), + .ar = _ar_convert_to_genode(read(E_GUEST_ES_ACCESS_RIGHTS)), + .limit = static_cast(read(E_GUEST_ES_LIMIT)), + .base = read(E_GUEST_ES_BASE) + }); + + state.ds.charge(Segment { + .sel = static_cast(read(E_GUEST_DS_SELECTOR)), + .ar = _ar_convert_to_genode(read(E_GUEST_DS_ACCESS_RIGHTS)), + .limit = static_cast(read(E_GUEST_DS_LIMIT)), + .base = read(E_GUEST_DS_BASE) + }); + + state.fs.charge(Segment { + .sel = static_cast(read(E_GUEST_FS_SELECTOR)), + .ar = _ar_convert_to_genode(read(E_GUEST_FS_ACCESS_RIGHTS)), + .limit = static_cast(read(E_GUEST_FS_LIMIT)), + .base = read(E_GUEST_FS_BASE) + }); + + state.gs.charge(Segment { + .sel = static_cast(read(E_GUEST_GS_SELECTOR)), + .ar = _ar_convert_to_genode(read(E_GUEST_GS_ACCESS_RIGHTS)), + .limit = static_cast(read(E_GUEST_GS_LIMIT)), + .base = read(E_GUEST_GS_BASE) + }); + + state.tr.charge(Segment { + .sel = static_cast(read(E_GUEST_TR_SELECTOR)), + .ar = _ar_convert_to_genode(read(E_GUEST_TR_ACCESS_RIGHTS)), + .limit = static_cast(read(E_GUEST_TR_LIMIT)), + .base = read(E_GUEST_TR_BASE) + }); + + state.ldtr.charge(Segment { + .sel = static_cast(read(E_GUEST_LDTR_SELECTOR)), + .ar = _ar_convert_to_genode(read(E_GUEST_LDTR_ACCESS_RIGHTS)), + .limit = static_cast(read(E_GUEST_LDTR_LIMIT)), + .base = read(E_GUEST_LDTR_BASE) + }); + + state.gdtr.charge(Range { + .limit = static_cast(read(E_GUEST_GDTR_LIMIT)), + .base = read(E_GUEST_GDTR_BASE) + }); + + state.idtr.charge(Range { + .limit = static_cast(read(E_GUEST_IDTR_LIMIT)), + .base = read(E_GUEST_IDTR_BASE) + }); + + + state.sysenter_cs.charge(read(E_IA32_SYSENTER_CS)); + state.sysenter_sp.charge(read(E_GUEST_IA32_SYSENTER_ESP)); + state.sysenter_ip.charge(read(E_GUEST_IA32_SYSENTER_EIP)); + + state.qual_primary.charge(read(E_EXIT_QUALIFICATION)); + state.qual_secondary.charge(read(E_GUEST_PHYSICAL_ADDRESS)); + + /* Charging ctrl_primary and ctrl_secondary breaks Virtualbox 6 */ + + if (state.exit_reason == EXIT_PAUSED || state.exit_reason == VMX_EXIT_INVGUEST) { + state.inj_info.charge(static_cast(read(E_VM_ENTRY_INTERRUPT_INFO_FIELD))); + state.inj_error.charge(static_cast(read(E_VM_ENTRY_EXCEPTION_ERROR_CODE))); + + } else { + state.inj_info.charge(static_cast(read(E_IDT_VECTORING_INFORMATION_FIELD))); + state.inj_error.charge(static_cast(read(E_IDT_VECTORING_ERROR_CODE))); + } + + state.intr_state.charge( + static_cast(read(E_GUEST_INTERRUPTIBILITY_STATE))); + state.actv_state.charge( + static_cast(read(E_GUEST_ACTIVITY_STATE))); + + state.tsc.charge(Hw::Lapic::rdtsc()); + state.tsc_offset.charge(read(E_TSC_OFFSET)); + + state.efer.charge(read(E_GUEST_IA32_EFER)); + + state.pdpte_0.charge(read(E_GUEST_PDPTE0)); + state.pdpte_1.charge(read(E_GUEST_PDPTE1)); + state.pdpte_2.charge(read(E_GUEST_PDPTE2)); + state.pdpte_3.charge(read(E_GUEST_PDPTE3)); + + state.star.charge(guest_msr_store_area.star.get()); + state.lstar.charge(guest_msr_store_area.lstar.get()); + state.cstar.charge(guest_msr_store_area.cstar.get()); + state.fmask.charge(guest_msr_store_area.fmask.get()); + state.kernel_gs_base.charge(guest_msr_store_area.kernel_gs_base.get()); + + Virtual_apic_state *virtual_apic_state = + reinterpret_cast( + ((addr_t) vcpu_data.virt_area) + 2 * get_page_size()); + state.tpr.charge(virtual_apic_state->get_vtpr()); + state.tpr_threshold.charge( + static_cast(read(E_TPR_THRESHOLD))); +} + + +void Vmcs::read_vcpu_state(Genode::Vcpu_state &state) +{ + _load_pointer(); + + if (state.flags.charged()) { + write(E_GUEST_RFLAGS, state.flags.value()); + } + + if (state.sp.charged()) { + write(E_GUEST_RSP, state.sp.value()); + } + + if (state.ip.charged()) { + write(E_GUEST_RIP, state.ip.value()); + write(E_VM_ENTRY_INSTRUCTION_LENGTH, state.ip_len.value()); + } + + if (state.dr7.charged()) { + write(E_GUEST_DR7, state.dr7.value()); + } + + if (state.cr0.charged() || state.cr2.charged() || + state.cr3.charged() || state.cr4.charged()) { + write(E_GUEST_CR0, (state.cr0.value() & ~cr0_mask & cr0_fixed1) | cr0_fixed0); + write(E_CR0_READ_SHADOW, (state.cr0.value() & cr0_fixed1) | cr0_fixed0); + cr2 = state.cr2.value(); + write(E_GUEST_CR3, state.cr3.value()); + write(E_GUEST_CR4, (state.cr4.value() & cr4_fixed1) | cr4_fixed0); + write(E_CR4_READ_SHADOW, (state.cr4.value() & cr4_fixed1) | cr4_fixed0); + } + + if (state.cs.charged() || state.ss.charged()) { + write(E_GUEST_CS_SELECTOR, state.cs.value().sel); + write(E_GUEST_CS_ACCESS_RIGHTS, _ar_convert_to_intel(state.cs.value().ar)); + write(E_GUEST_CS_LIMIT, state.cs.value().limit); + write(E_GUEST_CS_BASE, state.cs.value().base); + + write(E_GUEST_SS_SELECTOR, state.ss.value().sel); + write(E_GUEST_SS_ACCESS_RIGHTS, _ar_convert_to_intel(state.ss.value().ar)); + write(E_GUEST_SS_LIMIT, state.ss.value().limit); + write(E_GUEST_SS_BASE, state.ss.value().base); + } + + if (state.es.charged() || state.ds.charged()) { + write(E_GUEST_ES_SELECTOR, state.es.value().sel); + write(E_GUEST_ES_ACCESS_RIGHTS, _ar_convert_to_intel(state.es.value().ar)); + write(E_GUEST_ES_LIMIT, state.es.value().limit); + write(E_GUEST_ES_BASE, state.es.value().base); + + write(E_GUEST_DS_SELECTOR, state.ds.value().sel); + write(E_GUEST_DS_ACCESS_RIGHTS, _ar_convert_to_intel(state.ds.value().ar)); + write(E_GUEST_DS_LIMIT, state.ds.value().limit); + write(E_GUEST_DS_BASE, state.ds.value().base); + } + + if (state.fs.charged() || state.gs.charged()) { + write(E_GUEST_FS_SELECTOR, state.fs.value().sel); + write(E_GUEST_FS_ACCESS_RIGHTS, _ar_convert_to_intel(state.fs.value().ar)); + write(E_GUEST_FS_LIMIT, state.fs.value().limit); + write(E_GUEST_FS_BASE, state.fs.value().base); + + write(E_GUEST_GS_SELECTOR, state.gs.value().sel); + write(E_GUEST_GS_ACCESS_RIGHTS, _ar_convert_to_intel(state.gs.value().ar)); + write(E_GUEST_GS_LIMIT, state.gs.value().limit); + write(E_GUEST_GS_BASE, state.gs.value().base); + } + + if (state.tr.charged()) { + write(E_GUEST_TR_SELECTOR, state.tr.value().sel); + write(E_GUEST_TR_ACCESS_RIGHTS, _ar_convert_to_intel(state.tr.value().ar)); + write(E_GUEST_TR_LIMIT, state.tr.value().limit); + write(E_GUEST_TR_BASE, state.tr.value().base); + } + + if (state.ldtr.charged()) { + write(E_GUEST_LDTR_SELECTOR, state.ldtr.value().sel); + write(E_GUEST_LDTR_ACCESS_RIGHTS, _ar_convert_to_intel(state.ldtr.value().ar)); + write(E_GUEST_LDTR_LIMIT, state.ldtr.value().limit); + write(E_GUEST_LDTR_BASE, state.ldtr.value().base); + } + + if (state.gdtr.charged()) { + write(E_GUEST_GDTR_LIMIT, state.gdtr.value().limit); + write(E_GUEST_GDTR_BASE, state.gdtr.value().base); + } + + if (state.idtr.charged()) { + write(E_GUEST_IDTR_LIMIT, state.idtr.value().limit); + write(E_GUEST_IDTR_BASE, state.idtr.value().base); + } + + if (state.sysenter_cs.charged() || state.sysenter_sp.charged() || + state.sysenter_ip.charged()) { + write(E_IA32_SYSENTER_CS, state.sysenter_cs.value()); + write(E_GUEST_IA32_SYSENTER_ESP, state.sysenter_sp.value()); + write(E_GUEST_IA32_SYSENTER_EIP, state.sysenter_ip.value()); + } + + if (state.ctrl_primary.charged() || state.ctrl_secondary.charged()) { + enforce_execution_controls(state.ctrl_primary.value(), + state.ctrl_secondary.value()); + } + + if (state.inj_info.charged() || state.inj_error.charged()) { + Genode::uint32_t pri_controls = static_cast (read(E_PRI_PROC_BASED_VM_EXEC_CTRL)); + Genode::uint32_t sec_controls = static_cast (read(E_SEC_PROC_BASED_VM_EXEC_CTRL)); + bool set_controls = false; + + if (state.inj_info.value() & 0x1000) { + if (!Primary_proc_based_execution_controls::Interrupt_window_exiting::get(pri_controls)) { + Primary_proc_based_execution_controls::Interrupt_window_exiting::set(pri_controls); + set_controls = true; + } + } else { + if (Primary_proc_based_execution_controls::Interrupt_window_exiting::get(pri_controls)) { + Primary_proc_based_execution_controls::Interrupt_window_exiting::clear(pri_controls); + set_controls = true; + } + } + + if (state.inj_info.value() & 0x2000) { + if (!Primary_proc_based_execution_controls::Nmi_window_exiting::get(pri_controls)) { + Primary_proc_based_execution_controls::Nmi_window_exiting::set(pri_controls); + set_controls = true; + } + } else { + if (Primary_proc_based_execution_controls::Nmi_window_exiting::get(pri_controls)) { + Primary_proc_based_execution_controls::Nmi_window_exiting::clear(pri_controls); + set_controls = true; + } + } + + if (set_controls) + enforce_execution_controls(pri_controls, sec_controls); + + write(E_VM_ENTRY_INTERRUPT_INFO_FIELD, + /* Filter out special signaling bits */ + (state.inj_info.value() & + (Genode::uint32_t) ~0x3000)); + + write(E_VM_ENTRY_EXCEPTION_ERROR_CODE, state.inj_error.value()); + } + + if (state.intr_state.charged()) { + write(E_GUEST_INTERRUPTIBILITY_STATE, state.intr_state.value()); + } + + if (state.actv_state.charged()) { + write(E_GUEST_ACTIVITY_STATE, state.actv_state.value()); + } + + if (state.tsc_offset.charged()) { + /* state.tsc not used by SVM */ + write(E_TSC_OFFSET, state.tsc_offset.value()); + } + + if (state.efer.charged()) { + auto efer = state.efer.value(); + write(E_GUEST_IA32_EFER, efer); + + Vm_entry_controls::access_t entry_controls = static_cast(read(E_VM_ENTRY_CONTROLS)); + if (Cpu::Ia32_efer::Lma::get(efer)) + Vm_entry_controls::Ia32e_mode_guest::set(entry_controls); + else + Vm_entry_controls::Ia32e_mode_guest::clear(entry_controls); + + write(E_VM_ENTRY_CONTROLS, entry_controls); + } + + if (state.pdpte_0.charged() || state.pdpte_1.charged() || + state.pdpte_1.charged() || state.pdpte_2.charged()) { + write(E_GUEST_PDPTE0, state.pdpte_0.value()); + write(E_GUEST_PDPTE1, state.pdpte_1.value()); + write(E_GUEST_PDPTE2, state.pdpte_2.value()); + write(E_GUEST_PDPTE3, state.pdpte_3.value()); + } + + if (state.star.charged() || state.lstar.charged() || + state.cstar.charged() || state.fmask.charged() || + state.kernel_gs_base.charged()) { + guest_msr_store_area.star.set(state.star.value()); + guest_msr_store_area.lstar.set(state.lstar.value()); + guest_msr_store_area.cstar.set(state.cstar.value()); + guest_msr_store_area.fmask.set(state.fmask.value()); + guest_msr_store_area.kernel_gs_base.set(state.kernel_gs_base.value()); + } + + Virtual_apic_state * virtual_apic_state = + reinterpret_cast(((addr_t) vcpu_data.virt_area) + + 2 * get_page_size()); + + if (state.tpr.charged()) { + virtual_apic_state->set_vtpr(state.tpr.value()); + write(E_TPR_THRESHOLD, state.tpr_threshold.value()); + } +} + +void Vmcs::switch_world(Core::Cpu::Context ®s) +{ + _load_pointer(); + + save_host_msrs(); + + Cpu::Cr2::write(cr2); + + regs.trapno = TRAP_VMEXIT; + asm volatile( + "fxrstor (%[fpu_context]);" + "mov %[regs], %%rsp;" + "popq %%r8;" + "popq %%r9;" + "popq %%r10;" + "popq %%r11;" + "popq %%r12;" + "popq %%r13;" + "popq %%r14;" + "popq %%r15;" + "popq %%rax;" + "popq %%rbx;" + "popq %%rcx;" + "popq %%rdx;" + "popq %%rdi;" + "popq %%rsi;" + "popq %%rbp;" + "vmresume;" + "vmlaunch;" + : + : [regs] "r"(®s.r8), + [fpu_context] "r"(regs.fpu_context()) + : "memory"); + /* + * Usually when exiting guest mode, VMX will jump to the address + * provided in E_HOST_RIP; in our case: _kernel_entry. + * + * Execution continuing after the vmlaunch instruction indicates an + * error in setting up VMX that should never happen. If we regularly + * return from this method, the vCPU thread will be removed from the + * scheduler. + * + * For error codes, see Intel SDM (September 2023) Vol. 3C + * 31.4 Vm Instruction Error Numbers + */ + error("VM: execution error: ", Genode::Hex(read(Vmcs::E_VM_INSTRUCTION_ERROR))); +} + +/* + * Store MSRs to the Host MSR Store Area so that VMX restores them on VM exit + * + * For details, see Vol. 3C of the Intel SDM (September 2023): + * 28.6 Loading MSRs + */ +void Vmcs::save_host_msrs() +{ + using Cpu = Hw::X86_64_cpu; + + host_msr_store_area.star.set(Cpu::Ia32_star::read()); + host_msr_store_area.lstar.set(Cpu::Ia32_lstar::read()); + host_msr_store_area.cstar.set(Cpu::Ia32_cstar::read()); + host_msr_store_area.fmask.set(Cpu::Ia32_fmask::read()); + host_msr_store_area.kernel_gs_base.set( + Cpu::Ia32_kernel_gs_base::read()); +} + + +void Vmcs::_load_pointer() +{ + if (current_vmcs[_cpu_id] == this) + return; + + current_vmcs[_cpu_id] = this; + + vmptrld(vcpu_data.phys_addr + get_page_size()); +} + + +uint64_t Vmcs::handle_vm_exit() +{ + cr2 = Cpu::Cr2::read(); + uint64_t exitcode = read(E_EXIT_REASON) & 0xFFFF; + + switch (exitcode) { + case VMX_EXIT_NMI: + /* + * XXX We might need to handle host NMIs encoded in + * the VM_EXIT_INTERRUPT_INFORMATION field, so let's + * issue a warning. + */ + Genode::warning("VMX NMI exit occured"); + break; + case VMX_EXIT_INTR: + exitcode = EXIT_PAUSED; + break; + default: + break; + } + + return exitcode; +} diff --git a/repos/base-hw/src/core/spec/x86_64/virtualization/platform_services.cc b/repos/base-hw/src/core/spec/x86_64/virtualization/platform_services.cc new file mode 100644 index 0000000000..094e10f65f --- /dev/null +++ b/repos/base-hw/src/core/spec/x86_64/virtualization/platform_services.cc @@ -0,0 +1,44 @@ +/* + * \brief Platform specific services for x86 + * \author Stefan Kalkowski + * \author Benjamin Lamowski + * \date 2012-10-26 + */ + +/* + * Copyright (C) 2012-2022 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* Genode includes */ +#include + +/* core includes */ +#include +#include +#include +#include +#include + + +/* + * Add x86 specific ioport and virtualization service + */ +void Core::platform_add_local_services(Rpc_entrypoint &ep, + Sliced_heap &sliced_heap, + Registry &local_services, + Trace::Source_registry &trace_sources) +{ + static Io_port_root io_port_root(*core_env().pd_session(), + platform().io_port_alloc(), sliced_heap); + + static Vm_root vm_root(ep, sliced_heap, core_env().ram_allocator(), + core_env().local_rm(), trace_sources); + + static Core_service vm_service(local_services, vm_root); + + static Core_service + io_port_ls(local_services, io_port_root); +} diff --git a/repos/base-hw/src/core/spec/x86_64/virtualization/svm.h b/repos/base-hw/src/core/spec/x86_64/virtualization/svm.h new file mode 100644 index 0000000000..565d558f52 --- /dev/null +++ b/repos/base-hw/src/core/spec/x86_64/virtualization/svm.h @@ -0,0 +1,349 @@ +/* + * \brief VMCB data structure + * \author Benjamin Lamowski + * \date 2022-12-21 + */ + +/* + * Copyright (C) 2022-2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _INCLUDE__SPEC__PC__SVM_H_ +#define _INCLUDE__SPEC__PC__SVM_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +using Genode::addr_t; +using Genode::size_t; +using Genode::uint8_t; +using Genode::uint32_t; +using Genode::uint64_t; +using Genode::Mmio; +using Genode::Vcpu_data; +using Genode::Vcpu_state; +using Genode::get_page_size; +using Genode::memset; + +namespace Kernel { class Cpu; } + +namespace Board +{ + struct Msrpm; + struct Iopm; + struct Vmcb; + struct Vmcb_buf; +} + + +struct alignas(get_page_size()) Board::Msrpm +{ + uint8_t pad[8192]; + + Msrpm(); +}; + +struct +alignas(get_page_size()) +Board::Iopm +{ + uint8_t pad[12288]; + + Iopm(); +}; + + +/* + * VMCB data structure + * See: AMD Manual Vol. 2, Appendix B Layout of VMCB + */ +struct Board::Vmcb_buf +: + public Mmio +{ + enum { + Asid_host = 0, + State_off = 1024, + }; + + + Vmcb_buf(addr_t vmcb_addr, uint32_t id); + + static addr_t dummy_msrpm(); + static addr_t dummy_iopm(); + + /* + * AMD Manual Vol. 2, Table B-1: VMCB Layout, Control Area + */ + struct Intercept_cr : Register<0x000, 32> { + struct Reads : Bitfield< 0,16> { }; + struct Writes : Bitfield<16,16> { }; + }; + + struct Intercept_dr : Register<0x004, 32> { + struct Reads : Bitfield< 0,16> { }; + struct Writes : Bitfield<16,16> { }; + }; + + struct Intercept_ex : Register<0x008, 32> { + struct Vectors : Bitfield<0,32> { }; + }; + + struct Intercept_misc1 : Register<0x00C, 32> { + struct Intr : Bitfield< 0, 1> { }; + struct Nmi : Bitfield< 1, 1> { }; + struct Smi : Bitfield< 2, 1> { }; + struct Init : Bitfield< 3, 1> { }; + struct Vintr : Bitfield< 4, 1> { }; + struct Cr0 : Bitfield< 5, 1> { }; + struct Read_Idtr : Bitfield< 6, 1> { }; + struct Read_Gdtr : Bitfield< 7, 1> { }; + struct Read_Ldtr : Bitfield< 8, 1> { }; + struct Read_Tr : Bitfield< 9, 1> { }; + struct Write_Idtr : Bitfield<10, 1> { }; + struct Write_Gdtr : Bitfield<11, 1> { }; + struct Write_Ldtr : Bitfield<12, 1> { }; + struct Write_Tr : Bitfield<13, 1> { }; + struct Rdtsc : Bitfield<14, 1> { }; + struct Rdpmc : Bitfield<15, 1> { }; + struct Pushf : Bitfield<16, 1> { }; + struct Popf : Bitfield<17, 1> { }; + struct Cpuid : Bitfield<18, 1> { }; + struct Rsm : Bitfield<19, 1> { }; + struct Iret : Bitfield<20, 1> { }; + struct Int : Bitfield<21, 1> { }; + struct Invd : Bitfield<22, 1> { }; + struct Pause : Bitfield<23, 1> { }; + struct Hlt : Bitfield<24, 1> { }; + struct Invlpg : Bitfield<25, 1> { }; + struct INvlpga : Bitfield<26, 1> { }; + struct Ioio_prot : Bitfield<27, 1> { }; + struct Msr_prot : Bitfield<28, 1> { }; + struct Task_switch : Bitfield<29, 1> { }; + struct Ferr_freeze : Bitfield<30, 1> { }; + struct Shutdown : Bitfield<31, 1> { }; + }; + + struct Intercept_misc2 : Register<0x010, 32> { + struct Vmrun : Bitfield< 0, 1> { }; + struct Vmcall : Bitfield< 1, 1> { }; + struct Vmload : Bitfield< 2, 1> { }; + struct Vmsave : Bitfield< 3, 1> { }; + struct Stgi : Bitfield< 4, 1> { }; + struct Clgi : Bitfield< 5, 1> { }; + struct Skinit : Bitfield< 6, 1> { }; + struct Rdtscp : Bitfield< 7, 1> { }; + struct Icebp : Bitfield< 8, 1> { }; + struct Wbinvd : Bitfield< 9, 1> { }; + struct Monitor : Bitfield<10, 1> { }; + struct Mwait_uncon : Bitfield<11, 1> { }; + struct Mwait_armed : Bitfield<12, 1> { }; + struct Xsetbv : Bitfield<13, 1> { }; + struct Rdpru : Bitfield<14, 1> { }; + struct Efer : Bitfield<15, 1> { }; + struct Cr : Bitfield<16,16> { }; + }; + + struct Intercept_misc3 : Register<0x014, 32> { + struct Invlpgb_all : Bitfield< 0, 1> { }; + struct Invlpgb_inv : Bitfield< 1, 1> { }; + struct Invpcid : Bitfield< 2, 1> { }; + struct Mcommit : Bitfield< 3, 1> { }; + struct Stgi : Bitfield< 4, 1> { }; + }; + + struct Pause_filter_thres : Register<0x03C,16> { }; + struct Pause_filter_count : Register<0x03E,16> { }; + struct Iopm_base_pa : Register<0x040,64> { }; + struct Msrpm_base_pa : Register<0x048,64> { }; + struct Tsc_offset : Register<0x050,64> { }; + + /* + * The following two registers are documented as one 64bit register in the + * manual but since this is rather tedious to work with, just split them + * into two. + */ + struct Guest_asid : Register<0x058,32> { }; + struct Tlb : Register<0x05C,32> { + struct Tlb_control : Bitfield< 0, 8> {}; + }; + + struct Int_control : Register<0x060, 64> { + struct V_tpr : Bitfield< 0, 8> { }; + struct V_irq : Bitfield< 8, 1> { }; + struct Vgif : Bitfield< 9, 1> { }; + struct V_intr_prio : Bitfield<16, 4> { }; + struct V_ign_tpr : Bitfield<20, 1> { }; + struct V_intr_mask : Bitfield<24, 1> { }; + struct Amd_virt_gif : Bitfield<25, 1> { }; + struct Avic_enable : Bitfield<31, 1> { }; + struct V_intr_vector : Bitfield<33, 8> { }; + }; + + struct Int_control_ext : Register<0x068, 64> { + struct Int_shadow : Bitfield< 0, 1> { }; + struct Guest_int_mask : Bitfield< 1, 1> { }; + }; + + struct Exitcode : Register<0x070,64> { }; + struct Exitinfo1 : Register<0x078,64> { }; + struct Exitinfo2 : Register<0x080,64> { }; + struct Exitintinfo : Register<0x088,64> { }; + + struct Npt_control : Register<0x090, 64> { + struct Np_enable : Bitfield< 0, 1> { }; + struct Enable_sev : Bitfield< 1, 1> { }; + struct Sev_enc_state : Bitfield< 2, 1> { }; + struct Guest_md_ex_tr : Bitfield< 3, 1> { }; + struct Sss_check_en : Bitfield< 4, 1> { }; + struct Virt_trans_enc : Bitfield< 5, 1> { }; + struct Enable_invlpgb : Bitfield< 7, 1> { }; + }; + + struct Avic : Register<0x098, 64> { + struct Avic_apic_bar : Bitfield< 0,52> { }; + }; + + struct Ghcb_gpe : Register<0x0A0,64> { }; + struct Eventinj : Register<0x0A8,64> { }; + struct N_cr3 : Register<0x0B0,64> { }; + + struct Virt_extra : Register<0x0B8, 64> { + struct Lbr_virt : Bitfield< 0, 1> { }; + struct Virt_vmload : Bitfield< 1, 1> { }; + }; + + struct Vmcb_clean : Register<0x0C0, 64> { + struct Clean_bits : Bitfield< 0,32> { }; + }; + + struct Nrip : Register<0x0C8,64> { }; + + /* + * This is a 128bit field in the documentation. + * Split it up into two parts for the time being. + */ + struct Fetch_part_1 : Register<0x0D0,64> { + struct Nr_bytes : Bitfield< 0, 8> { }; + struct Guest_inst_lo : Bitfield< 8,56> { }; + }; + struct Fetch_part_2 : Register<0x0D8,64> { + struct Guest_inst_hi : Bitfield< 0,64> { }; + }; + + struct Avic_1 : Register<0x0E0,64> { + struct Apic_page_ptr : Bitfield< 0,52> { }; + }; + + struct Avic_2 : Register<0x0F0,64> { + struct Avic_log_table : Bitfield<12,52> { }; + }; + + struct Avic_3 : Register<0x0F8,64> { + struct Avic_max_idx : Bitfield< 0, 8> { }; + struct Avic_phys_ptr : Bitfield<12,52> { }; + }; + + struct Vmsa : Register<0x108,64> { + struct Vmsa_ptr : Bitfield<12,52> { }; + }; + + + /* + * AMD Manual Vol. 2, Table B-2: VMCB Layout, State Save Area + */ + + /* + * Segments are 128bit in size and therefore cannot be represented with + * the current Register Framework. + */ + struct Segment : public Mmio<128> + { + using Mmio<128>::Mmio; + + struct Sel : Register<0x0,16> { }; + struct Ar : Register<0x2,16> { }; + struct Limit : Register<0x4,32> { }; + struct Base : Register<0x8,64> { }; + }; + + Segment es { range_at(State_off + 0x0) }; + Segment cs { range_at(State_off + 0x10) }; + Segment ss { range_at(State_off + 0x20) }; + Segment ds { range_at(State_off + 0x30) }; + Segment fs { range_at(State_off + 0x40) }; + Segment gs { range_at(State_off + 0x50) }; + Segment gdtr { range_at(State_off + 0x60) }; + Segment ldtr { range_at(State_off + 0x70) }; + Segment idtr { range_at(State_off + 0x80) }; + Segment tr { range_at(State_off + 0x90) }; + + struct Efer : Register { }; + struct Cr4 : Register { }; + struct Cr3 : Register { }; + struct Cr0 : Register { }; + struct Dr7 : Register { }; + struct Rflags : Register { }; + struct Rip : Register { }; + struct Rsp : Register { }; + struct Rax : Register { }; + struct Star : Register { }; + struct Lstar : Register { }; + struct Cstar : Register { }; + struct Sfmask : Register { }; + struct Kernel_gs_base : Register { }; + struct Sysenter_cs : Register { }; + struct Sysenter_esp : Register { }; + struct Sysenter_eip : Register { }; + struct Cr2 : Register { }; + struct G_pat : Register { }; +}; + + + +/* + * VMCB data structure + * See: AMD Manual Vol. 2, Appendix B Layout of VMCB + */ +struct Board::Vmcb +: + public Board::Virt_interface +{ + enum + { + Asid_host = 0, + State_off = 1024, + }; + + Vmcb_buf v; + addr_t root_vmcb_phys = { 0 }; + + Vmcb(Vcpu_data &vcpu_data, uint32_t id); + static Vmcb_buf &host_vmcb(size_t cpu_id); + void enforce_intercepts(uint32_t desired_primary = 0U, + uint32_t desired_secondary = 0U); + void initialize(Kernel::Cpu &cpu, + addr_t page_table_phys_addr, + Core::Cpu::Context &) override; + void write_vcpu_state(Vcpu_state &state) override; + void read_vcpu_state(Vcpu_state &state) override; + void switch_world(Core::Cpu::Context ®s) override; + Genode::uint64_t handle_vm_exit() override; + + Virt_type virt_type() override + { + return Virt_type::SVM; + } +}; +static_assert(sizeof(Board::Vmcb) <= get_page_size()); + +#endif /* _INCLUDE__SPEC__PC__SVM_H_ */ diff --git a/repos/base-hw/src/core/spec/x86_64/virtualization/virt_interface.h b/repos/base-hw/src/core/spec/x86_64/virtualization/virt_interface.h new file mode 100644 index 0000000000..af0536bb78 --- /dev/null +++ b/repos/base-hw/src/core/spec/x86_64/virtualization/virt_interface.h @@ -0,0 +1,56 @@ +/* + * \brief Virtualization interface + * \author Benjamin Lamowski + * \date 2024-02-15 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _INCLUDE__SPEC__PC__VIRT_INTERFACE_H_ +#define _INCLUDE__SPEC__PC__VIRT_INTERFACE_H_ + +#include +#include +#include + +using Genode::addr_t; +using Genode::Vcpu_state; + +namespace Kernel { + class Cpu; + class Vm; +}; + +namespace Board +{ +enum Virt_type { + SVM, + VMX +}; + +struct Virt_interface +{ + Genode::Vcpu_data &vcpu_data; + + virtual void initialize(Kernel::Cpu &cpu, + addr_t page_table_phys_addr, + Core::Cpu::Context ®s) = 0; + virtual void write_vcpu_state(Vcpu_state &state) = 0; + virtual void read_vcpu_state(Vcpu_state &state) = 0; + virtual void switch_world(Core::Cpu::Context ®s) = 0; + virtual Virt_type virt_type() = 0; + virtual Genode::uint64_t handle_vm_exit() = 0; + + Virt_interface(Genode::Vcpu_data &vcpu_data) : vcpu_data(vcpu_data) + { } + + virtual ~Virt_interface() = default; +}; +} /* namespace Board */ + +#endif /* _INCLUDE__SPEC__PC__VIRT_INTERFACE_H_ */ diff --git a/repos/base-hw/src/core/spec/x86_64/virtualization/vm_page_table.h b/repos/base-hw/src/core/spec/x86_64/virtualization/vm_page_table.h new file mode 100644 index 0000000000..96c60ef8f7 --- /dev/null +++ b/repos/base-hw/src/core/spec/x86_64/virtualization/vm_page_table.h @@ -0,0 +1,106 @@ +/* + * \brief VM page table abstraction between VMX and SVM for x86 + * \author Benjamin Lamowski + * \date 2024-04-23 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CORE__SPEC__PC__VIRTUALIZATION__VM_PAGE_TABLE_H_ +#define _CORE__SPEC__PC__VIRTUALIZATION__VM_PAGE_TABLE_H_ + +#include +#include +#include +#include + +namespace Board { + using namespace Genode; + + struct Vm_page_table + { + /* Both Ept and Hpt need to actually use this allocator */ + using Allocator = Genode::Page_table_allocator<1UL << SIZE_LOG2_4KB>; + + template + struct is_same { + static const bool value = false; + }; + + template + struct is_same { + static const bool value = true; + }; + + static_assert(is_same::value, + "Ept uses different allocator"); + static_assert(is_same::value, + "Hpt uses different allocator"); + + static constexpr size_t ALIGNM_LOG2 = Hw::SIZE_LOG2_4KB; + + enum Virt_type { + VIRT_TYPE_NONE, + VIRT_TYPE_VMX, + VIRT_TYPE_SVM + }; + + union { + Hw::Ept ept; + Hw::Hpt hpt; + }; + + void insert_translation(addr_t vo, + addr_t pa, + size_t size, + Page_flags const & flags, + Allocator & alloc) + { + if (virt_type() == VIRT_TYPE_VMX) + ept.insert_translation(vo, pa, size, flags, alloc); + else if (virt_type() == VIRT_TYPE_SVM) + hpt.insert_translation(vo, pa, size, flags, alloc); + } + + void remove_translation(addr_t vo, size_t size, Allocator & alloc) + { + if (virt_type() == VIRT_TYPE_VMX) + ept.remove_translation(vo, size, alloc); + else if (virt_type() == VIRT_TYPE_SVM) + hpt.remove_translation(vo, size, alloc); + } + + static Virt_type virt_type() { + static Virt_type virt_type { VIRT_TYPE_NONE }; + + if (virt_type == VIRT_TYPE_NONE) { + if (Hw::Virtualization_support::has_vmx()) + virt_type = VIRT_TYPE_VMX; + else if (Hw::Virtualization_support::has_svm()) + virt_type = VIRT_TYPE_SVM; + else + error("Failed to detect Virtualization technology"); + } + + return virt_type; + } + + Vm_page_table() + { + if (virt_type() == VIRT_TYPE_VMX) + Genode::construct_at(this); + else if (virt_type() == VIRT_TYPE_SVM) + Genode::construct_at(this); + } + }; + + using Vm_page_table_array = + Vm_page_table::Allocator::Array; +}; + +#endif /* _CORE__SPEC__PC__VIRTUALIZATION__VM_PAGE_TABLE_H_ */ diff --git a/repos/base-hw/src/core/spec/x86_64/virtualization/vm_session_component.cc b/repos/base-hw/src/core/spec/x86_64/virtualization/vm_session_component.cc new file mode 100644 index 0000000000..1265959696 --- /dev/null +++ b/repos/base-hw/src/core/spec/x86_64/virtualization/vm_session_component.cc @@ -0,0 +1,196 @@ +/* + * \brief VM session component for 'base-hw' + * \author Stefan Kalkowski + * \author Benjamin Lamowski + * \date 2015-02-17 + */ + +/* + * Copyright (C) 2015-2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* Genode includes */ +#include + +/* base internal includes */ +#include + +/* core includes */ +#include +#include +#include +#include +#include + +using namespace Core; + + +static Core_mem_allocator & cma() { + return static_cast(platform().core_mem_alloc()); } + + +void Vm_session_component::_attach(addr_t phys_addr, addr_t vm_addr, size_t size) +{ + using namespace Hw; + + Page_flags pflags { RW, EXEC, USER, NO_GLOBAL, RAM, CACHED }; + + try { + _table.insert_translation(vm_addr, phys_addr, size, pflags, + _table_array.alloc()); + return; + } catch(Hw::Out_of_tables &) { + Genode::error("Translation table needs to much RAM"); + } catch(...) { + Genode::error("Invalid mapping ", Genode::Hex(phys_addr), " -> ", + Genode::Hex(vm_addr), " (", size, ")"); + } +} + + +void Vm_session_component::_attach_vm_memory(Dataspace_component &dsc, + addr_t const vm_addr, + Attach_attr const attribute) +{ + _attach(dsc.phys_addr() + attribute.offset, vm_addr, attribute.size); +} + + +void Vm_session_component::attach_pic(addr_t ) +{ } + + +void Vm_session_component::_detach_vm_memory(addr_t vm_addr, size_t size) +{ + _table.remove_translation(vm_addr, size, _table_array.alloc()); +} + + +void * Vm_session_component::_alloc_table() +{ + /* get some aligned space for the translation table */ + return cma().alloc_aligned(sizeof(Board::Vm_page_table), + Board::Vm_page_table::ALIGNM_LOG2).convert( + [&] (void *table_ptr) { + return table_ptr; }, + + [&] (Range_allocator::Alloc_error) -> void * { + /* XXX handle individual error conditions */ + error("failed to allocate kernel object"); + throw Insufficient_ram_quota(); } + ); +} + + +using Vmid_allocator = Genode::Bit_allocator<256>; + +static Vmid_allocator &alloc() +{ + static Vmid_allocator * allocator = nullptr; + if (!allocator) { + allocator = unmanaged_singleton(); + + /* reserve VM ID 0 for the hypervisor */ + addr_t id = allocator->alloc(); + assert (id == 0); + } + return *allocator; +} + + +Genode::addr_t Vm_session_component::_alloc_vcpu_data(Genode::addr_t ds_addr) +{ + /* + * XXX these allocations currently leak memory on VM Session + * destruction. This cannot be easily fixed because the + * Core Mem Allocator does not implement free(). + * + * Normally we would use constrained_md_ram_alloc to make the allocation, + * but to get the physical address of the pages in virt_area, we need + * to use the Core Mem Allocator. + */ + + Vcpu_data * vcpu_data = (Vcpu_data *) cma() + .try_alloc(sizeof(Board::Vcpu_data)) + .convert( + [&](void *ptr) { return ptr; }, + [&](Range_allocator::Alloc_error) -> void * { + /* XXX handle individual error conditions */ + error("failed to allocate kernel object"); + throw Insufficient_ram_quota(); + }); + + vcpu_data->virt_area = cma() + .alloc_aligned(Vcpu_data::size(), 12) + .convert( + [&](void *ptr) { return ptr; }, + [&](Range_allocator::Alloc_error) -> void * { + /* XXX handle individual error conditions */ + error("failed to allocate kernel object"); + throw Insufficient_ram_quota(); + }); + + vcpu_data->vcpu_state = (Vcpu_state *) ds_addr; + vcpu_data->phys_addr = (addr_t)cma().phys_addr(vcpu_data->virt_area); + + return (Genode::addr_t) vcpu_data; +} + + +Vm_session_component::Vm_session_component(Rpc_entrypoint &ds_ep, + Resources resources, + Label const &, + Diag, + Ram_allocator &ram_alloc, + Region_map ®ion_map, + unsigned, + Trace::Source_registry &) +: + Ram_quota_guard(resources.ram_quota), + Cap_quota_guard(resources.cap_quota), + _ep(ds_ep), + _constrained_md_ram_alloc(ram_alloc, _ram_quota_guard(), _cap_quota_guard()), + _sliced_heap(_constrained_md_ram_alloc, region_map), + _region_map(region_map), + _table(*construct_at(_alloc_table())), + _table_array(*(new (cma()) Board::Vm_page_table_array([] (void * virt) { + return (addr_t)cma().phys_addr(virt);}))), + _id({(unsigned)alloc().alloc(), cma().phys_addr(&_table)}) +{ + /* configure managed VM area */ + _map.add_range(0UL, ~0UL); +} + + +Vm_session_component::~Vm_session_component() +{ + /* detach all regions */ + while (true) { + addr_t out_addr = 0; + + if (!_map.any_block_addr(&out_addr)) + break; + + detach_at(out_addr); + } + + /* free region in allocator */ + for (unsigned i = 0; i < _vcpu_id_alloc; i++) { + if (!_vcpus[i].constructed()) + continue; + + Vcpu & vcpu = *_vcpus[i]; + if (vcpu.ds_cap.valid()) { + _region_map.detach(vcpu.ds_addr); + _constrained_md_ram_alloc.free(vcpu.ds_cap); + } + } + + /* free guest-to-host page tables */ + destroy(platform().core_mem_alloc(), &_table); + destroy(platform().core_mem_alloc(), &_table_array); + alloc().free(_id.id); +} diff --git a/repos/base-hw/src/core/spec/x86_64/virtualization/vmx.h b/repos/base-hw/src/core/spec/x86_64/virtualization/vmx.h new file mode 100644 index 0000000000..01efa08fed --- /dev/null +++ b/repos/base-hw/src/core/spec/x86_64/virtualization/vmx.h @@ -0,0 +1,516 @@ +/* + * \brief VMX data structure + * \author Benjamin Lamowski + * \date 2023-09-26 + */ + +/* + * Copyright (C) 2023-2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _INCLUDE__SPEC__PC__VMX_H_ +#define _INCLUDE__SPEC__PC__VMX_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using Genode::addr_t; +using Genode::uint16_t; +using Genode::uint32_t; +using Genode::uint64_t; + +namespace Kernel { class Cpu; } + +namespace Board +{ + struct Vmcs; + struct Vmcs_buf; + struct Msr_store_area; + struct Virtual_apic_state; +} + +/* + * VMX exitcodes, incomplete list. + * + * For details, see Vol. 3C of the Intel SDM (September 2023): + * Table C-1. Basic Exit Reasons + */ +enum Vmx_exitcodes : uint32_t { + VMX_EXIT_NMI = 0, + VMX_EXIT_INTR = 1, + VMX_EXIT_INVGUEST = 33, +}; + + +/* + * MSR-store area + * + * For details, see Vol. 3C of the Intel SDM (September 2023): + * 25.7.2 VM-Exit Controls for MSRs + */ +struct +alignas(16) +Board::Msr_store_area +{ + struct Msr_entry + { + uint32_t msr_index = 0U; + uint32_t _reserved = 0U; + uint64_t msr_data = 0U; + + void set(uint64_t data) + { + msr_data = data; + } + + uint64_t get() + { + return msr_data; + } + } __attribute__((packed)); + + Msr_entry star { 0xC0000081 }; + Msr_entry lstar { 0xC0000082 }; + Msr_entry cstar { 0xC0000083 }; + Msr_entry fmask { 0xC0000084 }; + Msr_entry kernel_gs_base { 0xC0000102 }; + + static constexpr Core::size_t get_count() + { + return sizeof(Msr_store_area) / sizeof(Msr_entry); + } +}; + + +/* + * Physical VMCS buffer + */ +struct +alignas(Genode::get_page_size()) +Board::Vmcs_buf +{ + union { + uint32_t rev; + Genode::uint8_t pad[Genode::get_page_size()]; + }; + + Vmcs_buf(uint32_t rev); +}; + + +/* + * VMCS + * + * See Intel SDM (September 2023) Vol. 3C, section 24.2. + */ +struct +Board::Vmcs +: + public Board::Virt_interface +{ + static uint32_t system_rev; + static uint32_t pinbased_allowed_0; + static uint32_t pinbased_allowed_1; + static uint32_t vm_entry_allowed_0; + static uint32_t vm_entry_allowed_1; + static uint32_t pri_exit_allowed_0; + static uint32_t pri_exit_allowed_1; + static uint32_t pri_procbased_allowed_0; + static uint32_t pri_procbased_allowed_1; + static uint32_t sec_procbased_allowed_0; + static uint32_t sec_procbased_allowed_1; + static uint64_t cr0_fixed0; + static uint64_t cr0_fixed1; + static uint64_t cr0_mask; + static uint64_t cr4_fixed0; + static uint64_t cr4_fixed1; + static uint64_t cr4_mask; + static uint64_t vpid; + + Msr_store_area guest_msr_store_area { }; + /* XXX only needed per vCPU */ + Msr_store_area host_msr_store_area { }; + uint64_t cr2 { 0 }; + + Genode::size_t _cpu_id { }; + + addr_t msr_phys_addr(Msr_store_area *msr_ptr) + { + Genode::size_t offset = + (Genode::size_t)msr_ptr - (Genode::size_t)this; + return vcpu_data.phys_addr + offset; + } + + /* + * VMCS field encodings + * + * See Intel SDM (September 2023) Vol. 3D, appendix B. + */ + enum Field_encoding : uint64_t { + /* + * B.1 16-Bit Fields + */ + + /* B.1.2 16-Bit Guest-State Fields */ + E_GUEST_ES_SELECTOR = 0x00000800, + E_GUEST_CS_SELECTOR = 0x00000802, + E_GUEST_SS_SELECTOR = 0x00000804, + E_GUEST_DS_SELECTOR = 0x00000806, + E_GUEST_FS_SELECTOR = 0x00000808, + E_GUEST_GS_SELECTOR = 0x0000080A, + E_GUEST_LDTR_SELECTOR = 0x0000080C, + E_GUEST_TR_SELECTOR = 0x0000080E, + + /* B.1.3 16-Bit Host-State Fields */ + E_HOST_CS_SELECTOR = 0x00000C02, + E_HOST_FS_SELECTOR = 0x00000C08, + E_HOST_GS_SELECTOR = 0x00000C0A, + E_HOST_TR_SELECTOR = 0x00000C0C, + + + /* + * B.2 64-Bit Fields + */ + + /* B.2.1 64-Bit Control Fields */ + E_VM_EXIT_MSR_STORE_ADDRESS = 0x00002006, + E_VM_EXIT_MSR_LOAD_ADDRESS = 0x00002008, + E_VM_ENTRY_MSR_LOAD_ADDRESS = 0x0000200A, + E_TSC_OFFSET = 0x00002010, + E_VIRTUAL_APIC_ADDRESS = 0x00002012, + E_EPT_POINTER = 0x0000201A, + + /* B.2.2 64-Bit Read-Only Data Field */ + E_GUEST_PHYSICAL_ADDRESS = 0x00002400, + + /* B.2.3 64-Bit Guest-State Fields */ + E_VMCS_LINK_POINTER = 0x00002800, + E_GUEST_IA32_EFER = 0x00002806, + E_GUEST_PDPTE0 = 0x0000280A, + E_GUEST_PDPTE1 = 0x0000280C, + E_GUEST_PDPTE2 = 0x0000280E, + E_GUEST_PDPTE3 = 0x00002810, + + /* B.2.4 64-Bit Host-State Fields */ + E_HOST_IA32_EFER = 0x00002C02, + + + /* + * B.3 32-Bit Fields + */ + + /* B.3.1 32-Bit Control Fields */ + E_PIN_BASED_VM_EXECUTION_CTRL = 0x00004000, + E_PRI_PROC_BASED_VM_EXEC_CTRL = 0x00004002, + E_EXCEPTION_BITMAP = 0x00004004, + E_PAGE_FAULT_ERROR_CODE_MASK = 0x00004006, + E_PAGE_FAULT_ERROR_CODE_MATCH = 0x00004008, + E_CR3_TARGET_COUNT = 0x0000400A, + E_PRIMARY_VM_EXIT_CONTROLS = 0x0000400C, + E_VM_EXIT_MSR_STORE_COUNT = 0x0000400E, + E_VM_EXIT_MSR_LOAD_COUNT = 0x00004010, + E_VM_ENTRY_CONTROLS = 0x00004012, + E_VM_ENTRY_MSR_LOAD_COUNT = 0x00004014, + E_VM_ENTRY_INTERRUPT_INFO_FIELD = 0x00004016, + E_VM_ENTRY_EXCEPTION_ERROR_CODE = 0x00004018, + E_VM_ENTRY_INSTRUCTION_LENGTH = 0x0000401A, + E_TPR_THRESHOLD = 0x0000401C, + E_SEC_PROC_BASED_VM_EXEC_CTRL = 0x0000401E, + + /* B.3.2 32-Bit Read-Only Data Fields */ + E_VM_INSTRUCTION_ERROR = 0x00004400, + E_EXIT_REASON = 0x00004402, + E_IDT_VECTORING_INFORMATION_FIELD = 0x00004408, + E_IDT_VECTORING_ERROR_CODE = 0x0000440A, + E_VM_EXIT_INSTRUCTION_LENGTH = 0x0000440C, + + /* B.3.3 32-Bit Guest-State Fields */ + E_GUEST_ES_LIMIT = 0x00004800, + E_GUEST_CS_LIMIT = 0x00004802, + E_GUEST_SS_LIMIT = 0x00004804, + E_GUEST_DS_LIMIT = 0x00004806, + E_GUEST_FS_LIMIT = 0x00004808, + E_GUEST_GS_LIMIT = 0x0000480A, + E_GUEST_LDTR_LIMIT = 0x0000480C, + E_GUEST_TR_LIMIT = 0x0000480E, + E_GUEST_GDTR_LIMIT = 0x00004810, + E_GUEST_IDTR_LIMIT = 0x00004812, + E_GUEST_ES_ACCESS_RIGHTS = 0x00004814, + E_GUEST_CS_ACCESS_RIGHTS = 0x00004816, + E_GUEST_SS_ACCESS_RIGHTS = 0x00004818, + E_GUEST_DS_ACCESS_RIGHTS = 0x0000481A, + E_GUEST_FS_ACCESS_RIGHTS = 0x0000481C, + E_GUEST_GS_ACCESS_RIGHTS = 0x0000481E, + E_GUEST_LDTR_ACCESS_RIGHTS = 0x00004820, + E_GUEST_TR_ACCESS_RIGHTS = 0x00004822, + E_GUEST_INTERRUPTIBILITY_STATE = 0x00004824, + E_GUEST_ACTIVITY_STATE = 0x00004826, + E_IA32_SYSENTER_CS = 0x0000482A, + + /* B.3.3 32-Bit Host-State Field */ + E_HOST_IA32_SYSENTER_CS = 0x00004C00, + + + /* + * B.4 Natural-Width Fields + */ + + /* B.4.1 Natural-Width Control Fields */ + E_CR0_GUEST_HOST_MASK = 0x00006000, + E_CR4_GUEST_HOST_MASK = 0x00006002, + E_CR0_READ_SHADOW = 0x00006004, + E_CR4_READ_SHADOW = 0x00006006, + + /* B.4.2 Natural-Width Read-Only Data Fields */ + E_EXIT_QUALIFICATION = 0x00006400, + + /* B.4.3 Natural-Width Guest-State Fields */ + E_GUEST_CR0 = 0x00006800, + E_GUEST_CR3 = 0x00006802, + E_GUEST_CR4 = 0x00006804, + E_GUEST_ES_BASE = 0x00006806, + E_GUEST_CS_BASE = 0x00006808, + E_GUEST_SS_BASE = 0x0000680A, + E_GUEST_DS_BASE = 0x0000680C, + E_GUEST_FS_BASE = 0x0000680E, + E_GUEST_GS_BASE = 0x00006810, + E_GUEST_LDTR_BASE = 0x00006812, + E_GUEST_TR_BASE = 0x00006814, + E_GUEST_GDTR_BASE = 0x00006816, + E_GUEST_IDTR_BASE = 0x00006818, + E_GUEST_DR7 = 0x0000681A, + E_GUEST_RSP = 0x0000681C, + E_GUEST_RIP = 0x0000681E, + E_GUEST_RFLAGS = 0x00006820, + E_GUEST_IA32_SYSENTER_ESP = 0x00006824, + E_GUEST_IA32_SYSENTER_EIP = 0x00006826, + + /* B.4.4 Natural-Width Host-State Fields */ + E_HOST_CR0 = 0x00006C00, + E_HOST_CR3 = 0x00006C02, + E_HOST_CR4 = 0x00006C04, + E_HOST_TR_BASE = 0x00006C0A, + E_HOST_GDTR_BASE = 0x00006C0C, + E_HOST_IDTR_BASE = 0x00006C0E, + E_HOST_IA32_SYSENTER_ESP = 0x00006C10, + E_HOST_IA32_SYSENTER_EIP = 0x00006C12, + E_HOST_RSP = 0x00006C14, + E_HOST_RIP = 0x00006C16, + }; + + static void vmxon(addr_t phys_addr) + { + bool success = false; + asm volatile( + "vmxon %[vmcs];" + /* the command succeeded if CF = 0 and ZF = 0 */ + : "=@cca"(success) + : [vmcs] "m"(phys_addr) + : "cc"); + assert(success && "vmxon failed"); + } + + static void vmptrld(addr_t phys_addr) + { + bool success = false; + asm volatile( + "vmptrld %[vmcs];" + /* the command succeeded if CF = 0 and ZF = 0 */ + : "=@cca"(success) + : [vmcs] "m"(phys_addr) + : "cc"); + assert(success && "vmptrld failed"); + } + + static uint64_t read(uint32_t enc) + { + uint64_t val; + asm volatile( + "vmread %[enc], %[val];" + : [val] "=rm"(val) + : [enc] "rm"(static_cast(enc)) + : "cc"); + return val; + } + + static void vmclear(addr_t phys_addr) + { + bool success = false; + asm volatile( + "vmclear %[vmcs];" + /* the command succeeded if CF = 0 and ZF = 0 */ + : "=@cca"(success) + : [vmcs] "m"(phys_addr) + : "cc"); + assert(success && "vmclear failed"); + } + + static void write(uint32_t enc, uint64_t val) + { + /* Genode::raw("VMWRITE: ", Genode::Hex(enc), " val: ", Genode::Hex(val)); */ + bool success = false; + asm volatile( + "vmwrite %[val], %[enc];" + /* the command succeeded if CF = 0 and ZF = 0 */ + : "=@cca"(success) + : [enc]"rm"(static_cast(enc)), [val] "r"(val) + : "cc"); + assert(success && "vmwrite failed"); + } + + Vmcs(Genode::Vcpu_data &vcpu_data); + Virt_type virt_type() override + { + return Virt_type::VMX; + } + + static inline uint32_t _ar_convert_to_intel(uint16_t ar) { + return ((ar << 4) & 0x1F000) | (ar & 0xFF); + } + + static inline uint16_t _ar_convert_to_genode(uint64_t ar) { + return ((ar >> 4) & 0x1F00) | (ar & 0xFF); + } + + void initialize(Kernel::Cpu &cpu, addr_t page_table_phys, + Core::Cpu::Context ®s) override; + void write_vcpu_state(Genode::Vcpu_state &state) override; + void read_vcpu_state(Genode::Vcpu_state &state) override; + void switch_world(Core::Cpu::Context ®s) override; + uint64_t handle_vm_exit() override; + + void save_host_msrs(); + void prepare_vmcs(); + void setup_vmx_info(); + static void enforce_execution_controls(uint32_t desired_primary, + uint32_t desired_secondary); + void _load_pointer(); + void construct_host_vmcs(); +}; + + +/* + * Access controls + */ + +/* + * Pin-Based VM-Execution Controls + * + * For details, see Vol. 3C of the Intel SDM (September 2023): + * 25.6.1 Pin-Based VM-Execution Controls + */ + +/* 25-5. Definitions of Pin-Based VM-Execution Controls */ +struct Pin_based_execution_controls : Genode::Register<32> +{ + struct External_interrupt_exiting : Bitfield<0,1> { }; + struct Bit_1 : Bitfield<1,1> { }; + struct Bit_2 : Bitfield<2,1> { }; + struct Nmi_exiting : Bitfield<3,1> { }; + struct Bit_4 : Bitfield<4,1> { }; + struct Virtual_nmis : Bitfield<5,1> { }; +}; + +/* + * Primary VM-Exit Controls + * + * For details, see Vol. 3C of the Intel SDM (September 2023): + * Table 25-13. Definitions of Primary VM-Exit Controls + */ +struct Primary_vm_exit_controls : Genode::Register<32> +{ + struct Save_debug_controls : Bitfield< 2,1> { }; + struct Host_address_space_size : Bitfield< 9,1> { }; + struct Ack_interrupt_on_exit : Bitfield<15,1> { }; + struct Save_ia32_efer : Bitfield<20,1> { }; + struct Load_ia32_efer : Bitfield<21,1> { }; +}; + + + +/* + * VM-Entry Controls + * + * For details, see Vol. 3C of the Intel SDM (September 2023): + * Table 25-13. Definitions of Primary VM-Exit Controls + * 25.8.1 VM-Entry Controls + */ +struct Vm_entry_controls : Genode::Register<32> +{ + struct Load_debug_controls : Bitfield< 2,1> { }; + struct Ia32e_mode_guest : Bitfield< 9,1> { }; + struct Load_ia32_efer : Bitfield<15,1> { }; +}; + + +/* + * Processor-Based VM-Execution Controls + * + * For details, see Vol. 3C of the Intel SDM (September 2023): + * 25.6.2 Processor-Based VM-Execution Controls + */ + +/* Table 25-6. Definitions of Primary Processor-Based VM-Execution Controls */ +struct Primary_proc_based_execution_controls : Genode::Register<32> +{ + struct Interrupt_window_exiting : Bitfield< 2,1> { }; + struct Hlt_exiting : Bitfield< 7,1> { }; + struct Invlpg_exiting : Bitfield< 9,1> { }; + struct Cr3_load_exiting : Bitfield<15,1> { }; + struct Cr3_store_exiting : Bitfield<16,1> { }; + struct Use_tpr_shadow : Bitfield<21,1> { }; + struct Nmi_window_exiting : Bitfield<22,1> { }; + struct Unconditional_io_exiting : Bitfield<24,1> { }; + struct Use_io_bitmaps : Bitfield<25,1> { }; + struct Use_msr_bitmaps : Bitfield<28,1> { }; + struct Activate_secondary_controls : Bitfield<31,1> { }; +}; + +/* Table 25-7. Definitions of Secondary Processor-Based VM-Execution Controls */ +struct Secondary_proc_based_execution_controls : Genode::Register<32> +{ + struct Enable_ept : Bitfield< 1,1> { }; + struct Enable_vpid : Bitfield< 5,1> { }; + struct Unrestricted_guest : Bitfield< 7,1> { }; + struct Enable_vm_functi : Bitfield<13,1> { }; +}; + + +/* + * Virtual Apic State + * + * For details, see Vol. 3C of the Intel SDM (September 2023): + * 30.1 Virtual Apic State + */ +struct Board::Virtual_apic_state +{ + enum { + VTPR_OFFSET = 0x80, + }; + + Genode::uint8_t pad[4096]; + + uint32_t get_vtpr() + { + return static_cast(*(pad + VTPR_OFFSET)); + } + + void set_vtpr(uint32_t vtpr) + { + uint32_t *tpr = + reinterpret_cast(pad + VTPR_OFFSET); + *tpr = vtpr; + } +}; + +#endif /* _INCLUDE__SPEC__PC__VMX_H_ */ diff --git a/repos/base-hw/src/core/thread_start.cc b/repos/base-hw/src/core/thread_start.cc index 0246501d6c..9c811da98f 100644 --- a/repos/base-hw/src/core/thread_start.cc +++ b/repos/base-hw/src/core/thread_start.cc @@ -27,22 +27,22 @@ #include #include -using namespace Genode; +using namespace Core; namespace Hw { extern Untyped_capability _main_thread_cap; } -void Thread::start() +Thread::Start_result Thread::start() { /* start thread with stack pointer at the top of stack */ - if (native_thread().platform_thread->start((void *)&_thread_start, stack_top())) { - error("failed to start thread"); - return; - } + native_thread().platform_thread->start((void *)&_thread_start, stack_top()); - struct Trace_source : public Trace::Source::Info_accessor, - private Trace::Control, - private Trace::Source + if (_thread_cap.failed()) + return Start_result::DENIED; + + struct Trace_source : public Core::Trace::Source::Info_accessor, + private Core::Trace::Control, + private Core::Trace::Source { Genode::Thread &thread; @@ -61,10 +61,10 @@ void Thread::start() execution_time, thread.affinity() }; } - Trace_source(Trace::Source_registry ®istry, Genode::Thread &thread) + Trace_source(Core::Trace::Source_registry ®istry, Genode::Thread &thread) : - Trace::Control(), - Trace::Source(*this, *this), + Core::Trace::Control(), + Core::Trace::Source(*this, *this), thread(thread) { registry.insert(this); @@ -72,7 +72,9 @@ void Thread::start() }; /* create trace sources for core threads */ - new (platform().core_mem_alloc()) Trace_source(Trace::sources(), *this); + new (platform().core_mem_alloc()) Trace_source(Core::Trace::sources(), *this); + + return Start_result::OK; } @@ -92,9 +94,9 @@ void Thread::_init_platform_thread(size_t, Type type) } /* remap initial main-thread UTCB according to stack-area spec */ - Genode::map_local(Platform::core_main_thread_phys_utcb(), - (addr_t)&_stack->utcb(), - max(sizeof(Native_utcb) / get_page_size(), (size_t)1)); + map_local(Platform::core_main_thread_phys_utcb(), + (addr_t)&_stack->utcb(), + max(sizeof(Native_utcb) / get_page_size(), (size_t)1)); /* adjust initial object state in case of a main thread */ native_thread().cap = Hw::_main_thread_cap; diff --git a/repos/base-hw/src/core/util.h b/repos/base-hw/src/core/util.h index 78e1a3f4b4..d0d03136ea 100644 --- a/repos/base-hw/src/core/util.h +++ b/repos/base-hw/src/core/util.h @@ -15,9 +15,11 @@ #ifndef _CORE__UTIL_H_ #define _CORE__UTIL_H_ +/* core includes */ +#include #include -namespace Genode { +namespace Core { using Hw::get_page_mask; using Hw::trunc_page; @@ -41,8 +43,10 @@ namespace Genode { * as 4K and 4M, this function should select one of those smaller or * equal to the argument. */ - constexpr size_t constrain_map_size_log2(size_t size_log2) { - return (size_log2 < 20) ? 12 : 20; } + static constexpr Log2 kernel_constrained_map_size(Log2 size) + { + return { (size.log2 < 20) ? uint8_t(12) : uint8_t(20) }; + } } #endif /* _CORE__UTIL_H_ */ diff --git a/repos/base-hw/src/core/vm_session_component.cc b/repos/base-hw/src/core/vm_session_component.cc index 22449aee6a..a1f4b781f9 100644 --- a/repos/base-hw/src/core/vm_session_component.cc +++ b/repos/base-hw/src/core/vm_session_component.cc @@ -21,30 +21,29 @@ #include #include -using namespace Genode; +using namespace Core; size_t Vm_session_component::_ds_size() { - return align_addr(sizeof(Board::Vm_state), get_page_size_log2()); } + return align_addr(sizeof(Board::Vcpu_state), get_page_size_log2()); } void Vm_session_component::Vcpu::exception_handler(Signal_context_capability handler) { if (!handler.valid()) { - Genode::warning("invalid signal"); + warning("invalid signal"); return; } if (kobj.constructed()) { - Genode::warning("Cannot register vcpu handler twice"); + warning("Cannot register vcpu handler twice"); return; } unsigned const cpu = location.xpos(); - if (!kobj.create(cpu, ds_addr, Capability_space::capid(handler), id)) - Genode::warning("Cannot instantiate vm kernel object, ", - "invalid signal context?"); + if (!kobj.create(cpu, (void *)ds_addr, Capability_space::capid(handler), id)) + warning("Cannot instantiate vm kernel object, invalid signal context?"); } @@ -66,7 +65,18 @@ Capability Vm_session_component::create_vcpu(Thread_cap try { vcpu.ds_cap = _constrained_md_ram_alloc.alloc(_ds_size(), Cache::UNCACHED); - vcpu.ds_addr = _region_map.attach(vcpu.ds_cap); + + Region_map::Attr attr { }; + attr.writeable = true; + vcpu.ds_addr = _region_map.attach(vcpu.ds_cap, attr).convert( + [&] (Region_map::Range range) { return _alloc_vcpu_data(range.start); }, + [&] (Region_map::Attach_error) -> addr_t { + error("failed to attach VCPU data within core"); + if (vcpu.ds_cap.valid()) + _constrained_md_ram_alloc.free(vcpu.ds_cap); + _vcpus[_vcpu_id_alloc].destruct(); + return 0; + }); } catch (...) { if (vcpu.ds_cap.valid()) _constrained_md_ram_alloc.free(vcpu.ds_cap); diff --git a/repos/base-hw/src/core/vm_session_component.h b/repos/base-hw/src/core/vm_session_component.h index 09d7206706..2eea4e9282 100644 --- a/repos/base-hw/src/core/vm_session_component.h +++ b/repos/base-hw/src/core/vm_session_component.h @@ -24,18 +24,16 @@ /* base-hw includes */ #include -/* base-hw Core includes */ +/* core includes */ #include #include #include - -/* base Core includes */ #include -namespace Genode { class Vm_session_component; } +namespace Core { class Vm_session_component; } -class Genode::Vm_session_component +class Core::Vm_session_component : private Ram_quota_guard, private Cap_quota_guard, @@ -44,7 +42,7 @@ class Genode::Vm_session_component { private: - typedef Allocator_avl_tpl Avl_region; + using Avl_region = Allocator_avl_tpl; /* * Noncopyable @@ -57,9 +55,9 @@ class Genode::Vm_session_component Kernel::Vm::Identity &id; Rpc_entrypoint &ep; Ram_dataspace_capability ds_cap { }; - Region_map::Local_addr ds_addr { nullptr }; - Kernel_object kobj {}; - Affinity::Location location {}; + addr_t ds_addr { }; + Kernel_object kobj { }; + Affinity::Location location { }; Vcpu(Kernel::Vm::Identity &id, Rpc_entrypoint &ep) : id(id), ep(ep) { @@ -94,14 +92,15 @@ class Genode::Vm_session_component unsigned _vcpu_id_alloc { 0 }; static size_t _ds_size(); + static size_t _alloc_vcpu_data(Genode::addr_t ds_addr); - void * _alloc_table(); - void _attach(addr_t phys_addr, addr_t vm_addr, size_t size); + void *_alloc_table(); + void _attach(addr_t phys_addr, addr_t vm_addr, size_t size); /* helpers for vm_session_common.cc */ - void _attach_vm_memory(Dataspace_component &, addr_t, - Attach_attr); - void _detach_vm_memory(addr_t, size_t); + void _attach_vm_memory(Dataspace_component &, addr_t, Attach_attr); + void _detach_vm_memory(addr_t, size_t); + void _with_region(addr_t, auto const &); protected: @@ -119,12 +118,15 @@ class Genode::Vm_session_component Trace::Source_registry &); ~Vm_session_component(); + /********************************* ** Region_map_detach interface ** *********************************/ - void detach(Region_map::Local_addr) override; - void unmap_region(addr_t, size_t) override; + void detach_at (addr_t) override; + void unmap_region (addr_t, size_t) override; + void reserve_and_flush (addr_t) override; + /************************** ** Vm session interface ** diff --git a/repos/base-hw/src/include/base/internal/align_at.h b/repos/base-hw/src/include/base/internal/align_at.h index 9ae3dd6943..cf837bf1ac 100644 --- a/repos/base-hw/src/include/base/internal/align_at.h +++ b/repos/base-hw/src/include/base/internal/align_at.h @@ -39,8 +39,7 @@ class Genode::Align_at public: - template - Align_at(ARGS &&... args) + Align_at(auto &&... args) : _obj(*construct_at(_start_addr(), args...)) { } ~Align_at() { _obj.~T(); } diff --git a/repos/base-hw/src/include/base/internal/cache.h b/repos/base-hw/src/include/base/internal/cache.h new file mode 100644 index 0000000000..488be58ee7 --- /dev/null +++ b/repos/base-hw/src/include/base/internal/cache.h @@ -0,0 +1,53 @@ +/* + * \brief Cache maintainance utilities + * \author Stefan Kalkowski + * \date 2022-12-16 + */ + +/* + * Copyright (C) 2022 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _INCLUDE__BASE__INTERNAL__CACHE_H_ +#define _INCLUDE__BASE__INTERNAL__CACHE_H_ + +#include +#include +#include + +static inline void for_each_page(Genode::addr_t addr, + Genode::size_t size, + auto const &fn) +{ + using namespace Genode; + + while (size) { + addr_t next_page = align_addr(addr+1, get_page_size_log2()); + size_t s = min(size, next_page - addr); + touch_read(reinterpret_cast(addr)); + fn(addr, s); + addr += s; + size -= s; + } +} + + +static inline void for_each_cache_line(Genode::addr_t addr, + Genode::size_t size, + auto const &fn) +{ + using namespace Genode; + + static size_t cache_line_size = Kernel::cache_line_size(); + + /* align the start address to catch all related cache lines */ + addr_t start = addr & ~(cache_line_size-1); + addr_t const end = addr + size; + for (; start < end; start += cache_line_size) + fn(start); +} + +#endif /* _INCLUDE__BASE__INTERNAL__CACHE_H_ */ diff --git a/repos/base-hw/src/include/base/internal/native_env.h b/repos/base-hw/src/include/base/internal/native_env.h index fb2802498a..bf1a849081 100644 --- a/repos/base-hw/src/include/base/internal/native_env.h +++ b/repos/base-hw/src/include/base/internal/native_env.h @@ -14,12 +14,16 @@ #ifndef _INCLUDE__BASE__INTERNAL__NATIVE_ENV_H_ #define _INCLUDE__BASE__INTERNAL__NATIVE_ENV_H_ +#include + namespace Genode { /** * Upgrade quota of the PD session's capability slab allocator */ void upgrade_capability_slab(); + + size_t avail_capability_slab(); }; #endif /* _INCLUDE__BASE__INTERNAL__NATIVE_ENV_H_ */ diff --git a/repos/base-hw/src/include/base/internal/native_thread.h b/repos/base-hw/src/include/base/internal/native_thread.h index c2a1e7a4d1..fa412db38e 100644 --- a/repos/base-hw/src/include/base/internal/native_thread.h +++ b/repos/base-hw/src/include/base/internal/native_thread.h @@ -17,15 +17,15 @@ #include #include -namespace Genode { - struct Native_thread; - class Platform_thread; -} +namespace Genode { struct Native_thread; } + + +namespace Core { class Platform_thread; } struct Genode::Native_thread { - Platform_thread *platform_thread; + Core::Platform_thread *platform_thread; Native_capability cap; }; diff --git a/repos/base-hw/src/include/hw/boot_info.h b/repos/base-hw/src/include/hw/boot_info.h index d7c1c50ebb..32edb68adb 100644 --- a/repos/base-hw/src/include/hw/boot_info.h +++ b/repos/base-hw/src/include/hw/boot_info.h @@ -22,8 +22,8 @@ namespace Hw { template struct Boot_info; } template struct Hw::Boot_info { - using Mapping_pool = Genode::Array; - using Kernel_irqs = Genode::Array; + using Mapping_pool = Genode::Array; + using Kernel_irqs = Genode::Array; addr_t const table; addr_t const table_allocator; diff --git a/repos/base-hw/src/include/hw/mapping.h b/repos/base-hw/src/include/hw/mapping.h index f8b89ddb77..4903850e37 100644 --- a/repos/base-hw/src/include/hw/mapping.h +++ b/repos/base-hw/src/include/hw/mapping.h @@ -15,9 +15,19 @@ #define _SRC__LIB__HW__MAPPING_H_ #include -#include +#include + +namespace Hw { + using Genode::Page_flags; + using Genode::RO; + using Genode::NO_EXEC; + using Genode::KERN; + using Genode::NO_GLOBAL; + using Genode::RAM; + + class Mapping; +} -namespace Hw { class Mapping; } class Hw::Mapping diff --git a/repos/base-hw/src/include/hw/memory_map.h b/repos/base-hw/src/include/hw/memory_map.h index de4454e0e1..02f702f0b7 100644 --- a/repos/base-hw/src/include/hw/memory_map.h +++ b/repos/base-hw/src/include/hw/memory_map.h @@ -28,6 +28,7 @@ namespace Hw { Memory_region const core_page_tables(); Memory_region const core_mmio(); Memory_region const core_heap(); + Memory_region const cpu_local_memory(); Memory_region const system_exception_vector(); Memory_region const hypervisor_exception_vector(); Memory_region const hypervisor_stack(); @@ -41,12 +42,11 @@ struct Hw::Mmio_space : Hw::Memory_region_array { using Hw::Memory_region_array::Memory_region_array; - template - void for_each_mapping(FUNC f) const + void for_each_mapping(auto const &fn) const { addr_t virt_base = Mm::core_mmio().base; auto lambda = [&] (unsigned, Memory_region const & r) { - f(Mapping { r.base, virt_base, r.size, PAGE_FLAGS_KERN_IO }); + fn(Mapping { r.base, virt_base, r.size, Genode::PAGE_FLAGS_KERN_IO }); virt_base += r.size + get_page_size(); }; for_each(lambda); diff --git a/repos/base-hw/src/include/hw/spec/arm/cortex_a9.h b/repos/base-hw/src/include/hw/spec/arm/cortex_a9.h index dd2dbd3356..be9099f8c6 100644 --- a/repos/base-hw/src/include/hw/spec/arm/cortex_a9.h +++ b/repos/base-hw/src/include/hw/spec/arm/cortex_a9.h @@ -30,9 +30,9 @@ struct Hw::Cortex_a9_mmio IRQ_CONTROLLER_CPU_BASE = BASE + 0x100, IRQ_CONTROLLER_CPU_SIZE = 0x100, - PRIVATE_TIMER_MMIO_BASE = BASE + 0x600, - PRIVATE_TIMER_MMIO_SIZE = 0x10, - PRIVATE_TIMER_IRQ = 29, + GLOBAL_TIMER_MMIO_BASE = BASE + 0x200, + GLOBAL_TIMER_MMIO_SIZE = 0x18, + GLOBAL_TIMER_IRQ = 27, }; }; diff --git a/repos/base-hw/src/include/hw/spec/arm/cpu.h b/repos/base-hw/src/include/hw/spec/arm/cpu.h index 404ddc814b..ec02cbdbd9 100644 --- a/repos/base-hw/src/include/hw/spec/arm/cpu.h +++ b/repos/base-hw/src/include/hw/spec/arm/cpu.h @@ -16,7 +16,10 @@ #include -namespace Hw { struct Arm_cpu; } +namespace Hw { struct Arm_cpu; struct Suspend_type; } + + +struct Hw::Suspend_type { }; struct Hw::Arm_cpu diff --git a/repos/base-hw/src/include/hw/spec/arm/gicv2.h b/repos/base-hw/src/include/hw/spec/arm/gicv2.h index c3edfc1a13..c4d67fb2ff 100644 --- a/repos/base-hw/src/include/hw/spec/arm/gicv2.h +++ b/repos/base-hw/src/include/hw/spec/arm/gicv2.h @@ -27,7 +27,7 @@ class Hw::Gicv2 /** * Distributor of the ARM generic interrupt controller */ - struct Distributor : Genode::Mmio + struct Distributor : Genode::Mmio<0xf04> { static constexpr unsigned nr_of_irq = 1024; @@ -99,7 +99,7 @@ class Hw::Gicv2 }; }; - Distributor(Genode::addr_t const base) : Genode::Mmio(base) { } + Distributor(Genode::addr_t const base) : Mmio({(char *)base, Mmio::SIZE}) { } /** * Return minimum IRQ priority @@ -125,7 +125,7 @@ class Hw::Gicv2 /** * CPU interface of the ARM generic interrupt controller */ - struct Cpu_interface : Genode::Mmio + struct Cpu_interface : Genode::Mmio<0x14> { /** * Control register @@ -162,7 +162,7 @@ class Hw::Gicv2 struct Eoir : Register<0x10, 32, true> { struct Irq_id : Bitfield<0,10> { }; }; - Cpu_interface(Genode::addr_t const base) : Genode::Mmio(base) { } + Cpu_interface(Genode::addr_t const base) : Mmio({(char *)base, Mmio::SIZE}) { } }; diff --git a/repos/base-hw/src/include/hw/spec/arm/gicv3.h b/repos/base-hw/src/include/hw/spec/arm/gicv3.h index b367b7ca6d..2f3d0cea64 100644 --- a/repos/base-hw/src/include/hw/spec/arm/gicv3.h +++ b/repos/base-hw/src/include/hw/spec/arm/gicv3.h @@ -42,7 +42,7 @@ class Hw::Pic static constexpr unsigned min_spi = 32; static constexpr unsigned spurious_id = 1023; - struct Distributor : Genode::Mmio + struct Distributor : Genode::Mmio<0x7fe0> { static constexpr unsigned nr_of_irq = 1024; @@ -103,19 +103,17 @@ class Hw::Pic unsigned max_irq() { return 32 * (read() + 1) - 1; } - Distributor(Genode::addr_t const base) : Genode::Mmio(base) - { } + using Mmio::Mmio; }; - struct Redistributor : Genode::Mmio + struct Redistributor : Genode::Mmio<0x4> { struct Ctlr : Register<0x0, 32> { struct Uwp : Bitfield<31, 1> { }; }; - Redistributor(Genode::addr_t const base) : Genode::Mmio(base) - { } + using Mmio::Mmio; /* wait for upstream writes */ void wait_for_uwp() @@ -126,7 +124,7 @@ class Hw::Pic } }; - struct Redistributor_sgi_ppi : Genode::Mmio + struct Redistributor_sgi_ppi : Genode::Mmio<0xc08> { struct Igroupr0 : Register<0x80, 32> { }; @@ -143,8 +141,7 @@ class Hw::Pic struct Icfgr1 : Register<0xc04, 32> { }; - Redistributor_sgi_ppi(Genode::addr_t const base) : Genode::Mmio(base) - { } + using Mmio::Mmio; }; struct Cpu_interface diff --git a/repos/base-hw/src/include/hw/spec/arm/imx53_qsb_board.h b/repos/base-hw/src/include/hw/spec/arm/imx53_qsb_board.h deleted file mode 100644 index 785cdf8012..0000000000 --- a/repos/base-hw/src/include/hw/spec/arm/imx53_qsb_board.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * \brief i.MX53 Quickstart board definitions - * \author Stefan Kalkowski - * \date 2019-05-15 - */ - -/* - * Copyright (C) 2019 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _SRC__INCLUDE__HW__SPEC__IMX53_QSB_BOARD_H_ -#define _SRC__INCLUDE__HW__SPEC__IMX53_QSB_BOARD_H_ - -#include -#include -#include - -namespace Hw::Imx53_qsb_board { - - using namespace Imx53_qsb; - using Serial = Genode::Imx_uart; - - enum { - UART_BASE = UART_1_MMIO_BASE, - UART_CLOCK = 0, /* ignored value */ - }; -} - -#endif /* _SRC__INCLUDE__HW__SPEC__IMX53_QSB_BOARD_H_ */ diff --git a/repos/base-hw/src/include/hw/spec/arm/imx6q_sabrelite_board.h b/repos/base-hw/src/include/hw/spec/arm/imx6q_sabrelite_board.h deleted file mode 100644 index a45d059c1e..0000000000 --- a/repos/base-hw/src/include/hw/spec/arm/imx6q_sabrelite_board.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * \brief i.MX6Quad Sabrelite specific board definitions - * \author Stefan Kalkowski - * \date 2019-05-16 - */ - -/* - * Copyright (C) 2019 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _SRC__INCLUDE__HW__SPEC__ARM__IMX6Q_SABRELITE_BOARD_H_ -#define _SRC__INCLUDE__HW__SPEC__ARM__IMX6Q_SABRELITE_BOARD_H_ - -#include -#include -#include -#include -#include - -namespace Hw::Imx6q_sabrelite_board { - - using namespace Imx6q_sabrelite; - - using Cpu_mmio = Hw::Cortex_a9_mmio; - using Serial = Genode::Imx_uart; - - enum { - UART_BASE = UART_2_MMIO_BASE, - UART_SIZE = UART_2_MMIO_SIZE, - UART_CLOCK = 0, /* dummy value, not used */ - }; -} - -#endif /* _SRC__INCLUDE__HW__SPEC__ARM__IMX6Q_SABRELITE_BOARD_H_ */ diff --git a/repos/base-hw/src/include/hw/spec/arm/imx7d_sabre_board.h b/repos/base-hw/src/include/hw/spec/arm/imx7d_sabre_board.h deleted file mode 100644 index 8646c45163..0000000000 --- a/repos/base-hw/src/include/hw/spec/arm/imx7d_sabre_board.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * \brief Imx7 Sabrelite specific board definitions - * \author Stefan Kalkowski - * \date 2018-11-07 - */ - -/* - * Copyright (C) 2018 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _SRC__INCLUDE__HW__SPEC__ARM__IMX7_SABRELITE_BOARD_H_ -#define _SRC__INCLUDE__HW__SPEC__ARM__IMX7_SABRELITE_BOARD_H_ - -#include -#include -#include -#include - -namespace Hw::Imx7d_sabre_board { - - using namespace Imx7d_sabre; - - using Cpu_mmio = Hw::Cortex_a15_mmio; - using Serial = Genode::Imx_uart; - - enum { - UART_BASE = UART_1_MMIO_BASE, - UART_CLOCK = 0, /* unsued value */ - }; -} - -#endif /* _SRC__INCLUDE__HW__SPEC__ARM__IMX7_SABRELITE_BOARD_H_ */ diff --git a/repos/base-hw/src/include/hw/spec/arm/imx_tzic.h b/repos/base-hw/src/include/hw/spec/arm/imx_tzic.h deleted file mode 100644 index 77c1a3d947..0000000000 --- a/repos/base-hw/src/include/hw/spec/arm/imx_tzic.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * \brief Freescale's TrustZone aware interrupt controller - * \author Stefan Kalkowski - * \date 2012-10-24 - */ - -/* - * Copyright (C) 2012-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _SRC__LIB__HW__SPEC__ARM__IMX_TZIC_H_ -#define _SRC__LIB__HW__SPEC__ARM__IMX_TZIC_H_ - -#include - -namespace Hw { class Pic; } - - -class Hw::Pic : public Genode::Mmio -{ - public: - - enum { NR_OF_IRQ = 109, }; - - protected: - - /** - * Software Interrupt Trigger Register - */ - struct Swint : Register<0xf00, 32> { - struct Intid : Bitfield<0,10> { }; }; - - /** - * Interrupt control register - */ - struct Intctrl : Register<0, 32> - { - struct Enable : Bitfield<0,1> { }; - struct Nsen : Bitfield<16,1> { }; - struct Nsen_mask : Bitfield<31,1> { }; - }; - - /** - * Priority mask register - */ - struct Priomask : Register<0xc, 32> { - struct Mask : Bitfield<0,8> { }; }; - - /** - * Interrupt security registers - */ - struct Intsec : Register_array<0x80, 32, NR_OF_IRQ, 1> { - struct Nonsecure : Bitfield<0, 1> { }; }; - - /** - * Interrupt set enable registers - */ - struct Enset : Register_array<0x100, 32, NR_OF_IRQ, 1, true> { - struct Set_enable : Bitfield<0, 1> { }; }; - - /** - * Interrupt clear enable registers - */ - struct Enclear : Register_array<0x180, 32, NR_OF_IRQ, 1, true> { - struct Clear_enable : Bitfield<0, 1> { }; }; - - /** - * Interrupt priority level registers - */ - struct Priority : Register_array<0x400, 32, NR_OF_IRQ, 8> { }; - - /** - * Highest interrupt pending registers - */ - struct Hipndr : Register_array<0xd80, 32, NR_OF_IRQ, 1, true> { - struct Pending : Bitfield<0, 1> { }; }; - - /** - * Validate request number 'i' - */ - bool _valid(unsigned const i) const { return i < NR_OF_IRQ; } - - public: - - enum { IPI = 0xffff }; - - Pic(); - - /** - * Receive a pending request number 'i' - */ - bool take_request(unsigned & i) - { - for (unsigned j = 0; j < NR_OF_IRQ; j++) { - if (!read(j)) { continue; } - i = j; - return true; - } - return false; - } - - void finish_request() { } - - void irq_mode(unsigned, unsigned, unsigned) { } - - /** - * Unmask interrupt 'i' - */ - void unmask(unsigned const i, unsigned) { - if (_valid(i)) { write(1, i); } } - - /** - * Mask interrupt 'i' - */ - void mask(unsigned const i) { - if (_valid(i)) { write(1, i); } } - - /* - * Trigger interrupt 'i' from software if possible - */ - void trigger(unsigned const i) { - write(Swint::Intid::bits(i)); } - - bool secure(unsigned i) { - return !read(i); } - - static constexpr bool fast_interrupts() { return true; } -}; - -#endif /* _SRC__LIB__HW__SPEC__ARM__IMX_TZIC_H_ */ diff --git a/repos/base-hw/src/include/hw/spec/arm/lpae.h b/repos/base-hw/src/include/hw/spec/arm/lpae.h index d898e37404..60b5826066 100644 --- a/repos/base-hw/src/include/hw/spec/arm/lpae.h +++ b/repos/base-hw/src/include/hw/spec/arm/lpae.h @@ -16,10 +16,11 @@ #include #include -#include +#include #include namespace Hw { + using Genode::Page_flags; enum { SIZE_LOG2_4KB = 12, @@ -206,7 +207,7 @@ class Hw::Long_translation_table static typename Descriptor::access_t create(Page_flags const &f) { - if (f.type == Hw::DEVICE) + if (f.type == Genode::DEVICE) return Attribute_index::bits(DEVICE); switch (f.cacheable) { @@ -387,7 +388,8 @@ class Hw::Level_3_translation_table : using Block_descriptor = typename Stage_trait::Type; if (!Descriptor::valid(desc)) return; - phys = Block_descriptor::Output_address::masked(desc); + phys = + (addr_t)Block_descriptor::Output_address::masked(desc); typename Block_descriptor::access_t ap = Block_descriptor::Access_permission::get(desc); found = ap == Block_descriptor::Access_permission::PRIVILEGED_RW || @@ -477,8 +479,13 @@ class Hw::Level_x_translation_table : [[fallthrough]]; case Descriptor::TABLE: /* table already available */ { - /* use allocator to retrieve virt address of table */ - E & table = alloc.virt_addr(Nt::masked(desc)); + /** + * Use allocator to retrieve virt address of table + * (we do not have physical memory above 4G on 32bit + * yet, therefore we can downcast here) + */ + E & table = + alloc.virt_addr((addr_t)Nt::masked(desc)); table.insert_translation(vo - (vo & Base::BLOCK_MASK), pa, size, flags, alloc); break; @@ -510,8 +517,12 @@ class Hw::Level_x_translation_table : switch (Descriptor::type(desc)) { case Descriptor::TABLE: { - /* use allocator to retrieve virt address of table */ - E & table = alloc.virt_addr(Nt::masked(desc)); + /** + * Use allocator to retrieve virt address of table + * (we do not have physical memory above 4G on 32bit + * yet, therefore we can downcast here) + */ + E & table = alloc.virt_addr((addr_t)Nt::masked(desc)); table.remove_translation(vo - (vo & Base::BLOCK_MASK), size, alloc); if (!table.empty()) break; @@ -544,7 +555,8 @@ class Hw::Level_x_translation_table : switch (Descriptor::type(desc)) { case Descriptor::BLOCK: { - phys = Block_descriptor::Output_address::masked(desc); + /* downcast: no phys memory above 4G on 32bit yet */ + phys = (addr_t)Block_descriptor::Output_address::masked(desc); typename Block_descriptor::access_t ap = Block_descriptor::Access_permission::get(desc); found = ap == Block_descriptor::Access_permission::PRIVILEGED_RW || @@ -553,8 +565,12 @@ class Hw::Level_x_translation_table : }; case Descriptor::TABLE: { - /* use allocator to retrieve virt address of table */ - E & table = alloc.virt_addr(Nt::masked(desc)); + /* + * Use allocator to retrieve virt address of table + * (we do not have physical memory above 4G on 32bit + * yet, therefore we can downcast here) + */ + E & table = alloc.virt_addr((addr_t)Nt::masked(desc)); found = table.lookup_rw_translation(vo - (vo & Base::BLOCK_MASK), phys, alloc); return; diff --git a/repos/base-hw/src/include/hw/spec/arm/nit6_solox_board.h b/repos/base-hw/src/include/hw/spec/arm/nit6_solox_board.h deleted file mode 100644 index 3f20ca7074..0000000000 --- a/repos/base-hw/src/include/hw/spec/arm/nit6_solox_board.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * \brief Nit6 SOLOX specific board definitions - * \author Stefan Kalkowski - * \date 2019-05-16 - */ - -/* - * Copyright (C) 2019 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _SRC__INCLUDE__HW__SPEC__ARM__NIT6_SOLOX_BOARD_H_ -#define _SRC__INCLUDE__HW__SPEC__ARM__NIT6_SOLOX_BOARD_H_ - -#include -#include -#include -#include -#include - -namespace Hw::Nit6_solox_board { - - using namespace Nit6_solox; - - using Cpu_mmio = Hw::Cortex_a9_mmio; - using Serial = Genode::Imx_uart; - - enum { - UART_BASE = UART_1_MMIO_BASE, - UART_SIZE = UART_1_MMIO_SIZE, - UART_CLOCK = 0, /* dummy value, not used */ - }; -} - -#endif /* _SRC__INCLUDE__HW__SPEC__ARM__NIT6_SOLOX_BOARD_H_ */ diff --git a/repos/base-hw/src/include/hw/spec/arm/page_table.h b/repos/base-hw/src/include/hw/spec/arm/page_table.h index 3d66e031a3..dfda058bb7 100644 --- a/repos/base-hw/src/include/hw/spec/arm/page_table.h +++ b/repos/base-hw/src/include/hw/spec/arm/page_table.h @@ -15,13 +15,17 @@ #ifndef _SRC__LIB__HW__SPEC__ARM__PAGE_TABLE_H_ #define _SRC__LIB__HW__SPEC__ARM__PAGE_TABLE_H_ +#include #include #include -#include #include #include -namespace Hw { class Page_table; } +namespace Hw { + using namespace Genode; + + class Page_table; +} class Hw::Page_table diff --git a/repos/base-hw/src/include/hw/spec/arm/pbxa9_board.h b/repos/base-hw/src/include/hw/spec/arm/pbxa9_board.h index 0a9b71d4f8..6a3a376094 100644 --- a/repos/base-hw/src/include/hw/spec/arm/pbxa9_board.h +++ b/repos/base-hw/src/include/hw/spec/arm/pbxa9_board.h @@ -32,6 +32,8 @@ namespace Hw::Pbxa9_board { UART_BASE = PL011_0_MMIO_BASE, UART_CLOCK = PL011_0_CLOCK, }; + + static constexpr Genode::size_t NR_OF_CPUS = 1; } #endif /* _SRC__INCLUDE__HW__SPEC__ARM__PBXA9_BOARD_H_ */ diff --git a/repos/base-hw/src/include/hw/spec/arm/pl310.h b/repos/base-hw/src/include/hw/spec/arm/pl310.h index 38b8769388..7c14367c95 100644 --- a/repos/base-hw/src/include/hw/spec/arm/pl310.h +++ b/repos/base-hw/src/include/hw/spec/arm/pl310.h @@ -22,7 +22,7 @@ namespace Hw { struct Pl310; } -class Hw::Pl310 : public Genode::Mmio +class Hw::Pl310 : public Genode::Mmio<0xf64> { protected: @@ -104,7 +104,7 @@ class Hw::Pl310 : public Genode::Mmio public: - Pl310(Genode::addr_t const base) : Mmio(base) { } + Pl310(Genode::addr_t const base) : Mmio({(char *)base, Mmio::SIZE}) { } void enable() {} void disable() {} diff --git a/repos/base-hw/src/include/hw/spec/arm/usb_armory_board.h b/repos/base-hw/src/include/hw/spec/arm/usb_armory_board.h deleted file mode 100644 index 7ccd8e0adb..0000000000 --- a/repos/base-hw/src/include/hw/spec/arm/usb_armory_board.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * \brief USB armory board definitions - * \author Stefan Kalkowski - * \date 2019-05-15 - */ - -/* - * Copyright (C) 2019 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _SRC__INCLUDE__HW__SPEC__ARM__USB_ARMORY_BOARD_H_ -#define _SRC__INCLUDE__HW__SPEC__ARM__USB_ARMORY_BOARD_H_ - -#include -#include -#include - -namespace Hw::Usb_armory_board { - - using namespace Usb_armory; - - using Serial = Genode::Imx_uart; - - enum { - UART_BASE = UART_1_MMIO_BASE, - UART_CLOCK = 0, /* ignored value */ - }; -} - -#endif /* _SRC__INCLUDE__HW__SPEC__ARM__USB_ARMORY_BOARD_H_ */ diff --git a/repos/base-hw/src/include/hw/spec/arm/wand_quad_board.h b/repos/base-hw/src/include/hw/spec/arm/wand_quad_board.h deleted file mode 100644 index 23d5b681d6..0000000000 --- a/repos/base-hw/src/include/hw/spec/arm/wand_quad_board.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * \brief Wandboard Quad specific definitions - * \author Stefan Kalkowski - * \date 2019-05-16 - */ - -/* - * Copyright (C) 2019 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _SRC__INCLUDE__HW__SPEC__ARM__WAND_QUAD_BOARD_H_ -#define _SRC__INCLUDE__HW__SPEC__ARM__WAND_QUAD_BOARD_H_ - -#include -#include -#include -#include -#include - -namespace Hw::Wand_quad_board { - - using namespace Wand_quad; - - using Cpu_mmio = Hw::Cortex_a9_mmio; - using Serial = Genode::Imx_uart; - - enum { - UART_BASE = UART_1_MMIO_BASE, - UART_SIZE = UART_1_MMIO_SIZE, - UART_CLOCK = 0, /* dummy value, not used */ - }; -} - -#endif /* _SRC__INCLUDE__HW__SPEC__ARM__WAND_QUAD_BOARD_H_ */ diff --git a/repos/base-hw/src/include/hw/spec/arm_64/cpu.h b/repos/base-hw/src/include/hw/spec/arm_64/cpu.h index a3599a8dfd..3ec28b0369 100644 --- a/repos/base-hw/src/include/hw/spec/arm_64/cpu.h +++ b/repos/base-hw/src/include/hw/spec/arm_64/cpu.h @@ -31,7 +31,10 @@ }; -namespace Hw { struct Arm_64_cpu; } +namespace Hw { struct Arm_64_cpu; struct Suspend_type; } + + +struct Hw::Suspend_type { }; struct Hw::Arm_64_cpu @@ -76,11 +79,13 @@ struct Hw::Arm_64_cpu struct Ec : Bitfield<26, 6> { enum Exception { - SVC = 0b010101, - INST_ABORT_LOW_LEVEL = 0b100000, - INST_ABORT_SAME_LEVEL = 0b100001, - DATA_ABORT_LOW_LEVEL = 0b100100, - DATA_ABORT_SAME_LEVEL = 0b100101, + SVC = 0b010101, + INST_ABORT_LOW_LEVEL = 0b100000, + INST_ABORT_SAME_LEVEL = 0b100001, + DATA_ABORT_LOW_LEVEL = 0b100100, + DATA_ABORT_SAME_LEVEL = 0b100101, + SOFTWARE_STEP_LOW_LEVEL = 0b110010, + BRK = 0b111100, }; }; @@ -141,6 +146,11 @@ struct Hw::Arm_64_cpu SYSTEM_REGISTER(64, Mair_el1, mair_el1); SYSTEM_REGISTER(64, Mair_el2, mair_el2); + struct Mdscr : Genode::Register<64> + { + struct Ss : Bitfield<0, 1> {}; + }; + SYSTEM_REGISTER(64, Mpidr, mpidr_el1, struct Aff0 : Bitfield<0, 8> {}; struct Aff1 : Bitfield<8, 8> {}; @@ -168,6 +178,7 @@ struct Hw::Arm_64_cpu struct I : Bitfield<12, 1> { }; struct Uct : Bitfield<15, 1> { }; struct Wxn : Bitfield<19, 1> { }; + struct Uci : Bitfield<26, 1> { }; }; SYSTEM_REGISTER(64, Sctlr_el1, sctlr_el1); @@ -175,12 +186,13 @@ struct Hw::Arm_64_cpu struct Spsr : Genode::Register<64> { - struct Sp : Bitfield<0, 1> {}; - struct El : Bitfield<2, 2> {}; - struct F : Bitfield<6, 1> {}; - struct I : Bitfield<7, 1> {}; - struct A : Bitfield<8, 1> {}; - struct D : Bitfield<9, 1> {}; + struct Sp : Bitfield<0, 1> {}; + struct El : Bitfield<2, 2> {}; + struct F : Bitfield<6, 1> {}; + struct I : Bitfield<7, 1> {}; + struct A : Bitfield<8, 1> {}; + struct D : Bitfield<9, 1> {}; + struct Ss : Bitfield<21, 1> {}; }; SYSTEM_REGISTER(64, Spsr_el2, spsr_el2); diff --git a/repos/base-hw/src/include/hw/spec/arm_64/memory_map.h b/repos/base-hw/src/include/hw/spec/arm_64/memory_map.h index e6ec5afda1..ad944b8c9e 100644 --- a/repos/base-hw/src/include/hw/spec/arm_64/memory_map.h +++ b/repos/base-hw/src/include/hw/spec/arm_64/memory_map.h @@ -19,8 +19,7 @@ namespace Hw { namespace Mm { - template - Genode::addr_t el2_addr(T t) + Genode::addr_t el2_addr(auto t) { static constexpr Genode::addr_t OFF = 0xffffff8000000000UL; return (Genode::addr_t)t - OFF; diff --git a/repos/base-hw/src/include/hw/spec/riscv/cpu.h b/repos/base-hw/src/include/hw/spec/riscv/cpu.h index 49970a1d2f..73f6390dd9 100644 --- a/repos/base-hw/src/include/hw/spec/riscv/cpu.h +++ b/repos/base-hw/src/include/hw/spec/riscv/cpu.h @@ -16,7 +16,10 @@ #include -namespace Hw { struct Riscv_cpu; } +namespace Hw { struct Riscv_cpu; struct Suspend_type; } + + +struct Hw::Suspend_type { }; struct Hw::Riscv_cpu diff --git a/repos/base-hw/src/include/hw/spec/riscv/page_table.h b/repos/base-hw/src/include/hw/spec/riscv/page_table.h index d95504b5c7..fa92026d8c 100644 --- a/repos/base-hw/src/include/hw/spec/riscv/page_table.h +++ b/repos/base-hw/src/include/hw/spec/riscv/page_table.h @@ -15,7 +15,7 @@ #define _SRC__LIB__HW__SPEC__RISCV__PAGE_TABLE_H_ #include -#include +#include #include #include #include @@ -73,7 +73,7 @@ struct Sv39::Descriptor : Register<64> struct Ppn : Bitfield<10, 38> { }; /* physical address 10 bit aligned */ struct Base : Bitfield<12, 38> { }; /* physical address page aligned */ - static access_t permission_bits(Hw::Page_flags const &f) + static access_t permission_bits(Genode::Page_flags const &f) { access_t rights = 0; R::set(rights, 1); @@ -125,7 +125,7 @@ struct Sv39::Table_descriptor : Descriptor struct Sv39::Block_descriptor : Descriptor { - static access_t create(Hw::Page_flags const &f, addr_t const pa) + static access_t create(Genode::Page_flags const &f, addr_t const pa) { access_t base = Base::get(pa); access_t desc = 0; @@ -184,8 +184,7 @@ class Sv39::Level_x_translation_table return align_addr(region, (unsigned)alignment) / (1UL << alignment); } - template - void _range_op(addr_t vo, addr_t pa, size_t size, FUNC &&func) + void _range_op(addr_t vo, addr_t pa, size_t size, auto const &fn) { /* sanity check vo bits 38 to 63 must be equal */ addr_t sanity = vo >> 38; @@ -202,7 +201,7 @@ class Sv39::Level_x_translation_table addr_t end = (vo + BLOCK_SIZE) & BLOCK_MASK; size_t sz = min(size, end-vo); - func(vo, pa, sz, _entries[i]); + fn(vo, pa, sz, _entries[i]); /* flush cached table entry address */ _translation_added((addr_t)&_entries[i], sz); @@ -219,16 +218,16 @@ class Sv39::Level_x_translation_table template struct Insert_func { - Hw::Page_flags const & flags; + Genode::Page_flags const & flags; Allocator & alloc; - Insert_func(Hw::Page_flags const & flags, Allocator & alloc) + Insert_func(Genode::Page_flags const & flags, Allocator & alloc) : flags(flags), alloc(alloc) { } void operator () (addr_t const vo, addr_t const pa, size_t const size, - typename Descriptor::access_t &desc) + typename Descriptor::access_t &desc) const { using Td = Table_descriptor; @@ -280,7 +279,7 @@ class Sv39::Level_x_translation_table void operator () (addr_t const vo, addr_t const /* pa */, size_t const size, - typename Descriptor::access_t &desc) + typename Descriptor::access_t &desc) const { using Td = Table_descriptor; @@ -333,7 +332,7 @@ class Sv39::Level_x_translation_table * \param alloc level allocator */ void insert_translation(addr_t vo, addr_t pa, size_t size, - Hw::Page_flags const & flags, + Genode::Page_flags const & flags, Allocator & alloc ) { _range_op(vo, pa, size, Insert_func(flags, alloc)); @@ -367,15 +366,15 @@ namespace Sv39 { template <> template <> struct Level_3_translation_table::Insert_func { - Hw::Page_flags const & flags; + Genode::Page_flags const & flags; - Insert_func(Hw::Page_flags const & flags, Allocator &) + Insert_func(Genode::Page_flags const & flags, Allocator &) : flags(flags) { } void operator () (addr_t const vo, addr_t const pa, size_t const size, - Descriptor::access_t &desc) + Descriptor::access_t &desc) const { if ((vo & ~BLOCK_MASK) || (pa & ~BLOCK_MASK) || size < BLOCK_SIZE) { @@ -401,7 +400,7 @@ namespace Sv39 { void operator () (addr_t /* vo */, addr_t /* pa */, size_t /* size */, - Descriptor::access_t &desc) { + Descriptor::access_t &desc) const { desc = 0; } }; } diff --git a/repos/base-hw/src/include/hw/spec/riscv/sbi.h b/repos/base-hw/src/include/hw/spec/riscv/sbi.h index 1e839b3533..deac2b92d7 100644 --- a/repos/base-hw/src/include/hw/spec/riscv/sbi.h +++ b/repos/base-hw/src/include/hw/spec/riscv/sbi.h @@ -47,6 +47,8 @@ struct Hw::Riscv_uart { Sbi::console_put_char(c); } + + void init() { } }; #endif /* _SRC__LIB__HW__SPEC__RISCV__SBI_H_ */ diff --git a/repos/base-hw/src/include/hw/spec/x86_64/acpi.h b/repos/base-hw/src/include/hw/spec/x86_64/acpi.h index 42c188c332..fc261db406 100644 --- a/repos/base-hw/src/include/hw/spec/x86_64/acpi.h +++ b/repos/base-hw/src/include/hw/spec/x86_64/acpi.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2018 Genode Labs GmbH + * Copyright (C) 2018-2022 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -20,15 +20,12 @@ namespace Hw { struct Acpi_generic; struct Apic_madt; + struct Acpi_fadt; + struct Acpi_facs; - template - void for_each_rsdt_entry(Hw::Acpi_generic &, FUNC); - - template - void for_each_xsdt_entry(Hw::Acpi_generic &, FUNC); - - template - void for_each_apic_struct(Acpi_generic &, FUNC); + void for_each_rsdt_entry (Hw::Acpi_generic &, auto const &); + void for_each_xsdt_entry (Hw::Acpi_generic &, auto const &); + void for_each_apic_struct(Acpi_generic &, auto const &); } @@ -57,34 +54,336 @@ struct Hw::Apic_madt Apic_madt *next() const { return reinterpret_cast((Genode::uint8_t *)this + length); } - struct Ioapic : Genode::Mmio + struct Ioapic : Genode::Mmio<0xc> { struct Id : Register <0x02, 8> { }; struct Paddr : Register <0x04, 32> { }; struct Gsi_base : Register <0x08, 32> { }; - Ioapic(Apic_madt const * a) : Mmio(reinterpret_cast(a)) { } + Ioapic(Apic_madt const * a) : Mmio({(char *)a, Mmio::SIZE}) { } }; - struct Lapic : Genode::Mmio + struct Lapic : Genode::Mmio<0x8> { - struct Flags : Register <0x04, 32> { enum { VALID = 1 }; }; + struct Apic_id : Register<0x3, 8> {}; + struct Flags : Register<0x4, 32> + { + enum { VALID = 1 }; + }; - Lapic(Apic_madt const * a) : Mmio(reinterpret_cast(a)) { } + Lapic(Apic_madt const * a) : Mmio({(char *)a, Mmio::SIZE}) { } bool valid() { return read() & Flags::VALID; }; + Genode::uint8_t id() { return read(); } }; } __attribute__((packed)); -template -void Hw::for_each_rsdt_entry(Hw::Acpi_generic &rsdt, FUNC fn) +/* ACPI spec 5.2.9 and ACPI GAS 5.2.3.2 */ +struct Hw::Acpi_fadt : Genode::Mmio<276> +{ + enum Addressspace { IO = 0x1 }; + + enum { FW_OFFSET_EXT = 0x84, SLEEP_CONTROL_REG = 236 }; + + struct Size : Register < 0x04, 32> { }; + struct Fw_ctrl : Register < 0x24, 32> { }; + struct Fw_ctrl_ext : Register { }; + + struct Smi_cmd : Register<0x30, 32> { }; + struct Acpi_enable : Register<0x34, 8> { }; + + struct Pm1a_cnt_blk : Register < 64, 32> { + struct Slp_typ : Bitfield < 10, 3> { }; + struct Slp_ena : Bitfield < 13, 1> { }; + }; + struct Pm1b_cnt_blk : Register < 68, 32> { + struct Slp_typ : Bitfield < 10, 3> { }; + struct Slp_ena : Bitfield < 13, 1> { }; + }; + + struct Gpe0_blk : Register < 80, 32> { }; + struct Gpe1_blk : Register < 84, 32> { }; + + struct Gpe0_blk_len : Register < 92, 8> { }; + struct Gpe1_blk_len : Register < 93, 8> { }; + + struct Pm1_cnt_len : Register < 89, 8> { }; + + struct Pm1a_cnt_blk_ext : Register < 172, 32> { + struct Addressspace : Bitfield < 0, 8> { }; + struct Width : Bitfield < 8, 8> { }; + }; + struct Pm1a_cnt_blk_ext_addr : Register < 172 + 4, 64> { }; + + struct Pm1b_cnt_blk_ext : Register < 184, 32> { + struct Addressspace : Bitfield < 0, 8> { }; + struct Width : Bitfield < 8, 8> { }; + }; + struct Pm1b_cnt_blk_ext_addr : Register < 184 + 4, 64> { }; + + struct Gpe0_blk_ext : Register < 220, 32> { + struct Addressspace : Bitfield < 0, 8> { }; + struct Width : Bitfield < 8, 8> { }; + }; + struct Gpe0_blk_ext_addr : Register < 220 + 4, 64> { }; + + struct Gpe1_blk_ext : Register < 232, 32> { + struct Addressspace : Bitfield < 0, 8> { }; + struct Width : Bitfield < 8, 8> { }; + }; + struct Gpe1_blk_ext_addr : Register < 232 + 4, 64> { }; + + /** + * Read from I/O port + */ + Genode::uint8_t inb(Genode::uint16_t port) + { + Genode::uint8_t res; + asm volatile ("inb %w1, %0" : "=a"(res) : "Nd"(port)); + return res; + } + + Genode::uint16_t inw(Genode::uint16_t port) + { + Genode::uint16_t res; + asm volatile ("inw %w1, %0" : "=a"(res) : "Nd"(port)); + return res; + } + + Genode::uint32_t inl(Genode::uint16_t port) + { + Genode::uint32_t res; + asm volatile ("inl %w1, %0" : "=a"(res) : "Nd"(port)); + return res; + } + + /** + * Write to I/O port + */ + inline void outb(Genode::uint16_t port, Genode::uint8_t val) + { + asm volatile ("outb %0, %w1" : : "a"(val), "Nd"(port)); + } + + inline void outw(Genode::uint16_t port, Genode::uint16_t val) + { + asm volatile ("outw %0, %w1" : : "a"(val), "Nd"(port)); + } + + inline void outl(Genode::uint16_t port, Genode::uint32_t val) + { + asm volatile ("outl %0, %w1" : : "a"(val), "Nd"(port)); + } + + Acpi_fadt(Acpi_generic const * a) : Mmio({(char *)a, Mmio::SIZE}) { } + + void takeover_acpi() + { + if (!read() || !read()) + return; + + asm volatile ("out %0, %w1" :: "a" (read()), + "Nd" (read())); + } + + addr_t facs() const + { + addr_t facs { }; + + if (read() >= FW_OFFSET_EXT + 8) + facs = read(); + + if (!facs) + facs = read(); + + return facs; + } + + void clear_gpe0_status() + { + auto constexpr half_register = true; + + return _write(~0ULL, + half_register); + } + + void clear_gpe1_status() + { + auto constexpr half_register = true; + + return _write(~0ULL, + half_register); + } + + unsigned read_cnt_blk() + { + auto const pm1_a = _read(); + auto const pm1_b = _read(); + return pm1_a | pm1_b; + } + + void write_cnt_blk(unsigned value_a, unsigned value_b) + { + _write(value_a); + _write(value_b); + } + + void suspend(Genode::uint8_t typ_slp_a, Genode::uint8_t typ_slp_b) + { + auto cnt = read_cnt_blk(); + auto value_a = cnt, value_b = cnt; + + Pm1a_cnt_blk::Slp_typ::set(value_a, typ_slp_a); + Pm1a_cnt_blk::Slp_ena::set(value_a, 1); + + Pm1b_cnt_blk::Slp_typ::set(value_b, typ_slp_b); + Pm1b_cnt_blk::Slp_ena::set(value_b, 1); + + write_cnt_blk(value_a, value_b); + } + + template + unsigned _access(bool hw_read, T value, bool half_register = false, + bool half_offset = false) + { + unsigned long long raw_io_addr = 0ull; + unsigned width_bits = 0u; + + auto const register_len = read(); + auto const reg_size = read(); + + if (reg_size >= SLEEP_CONTROL_REG && read() != 0ull) { + if (register_len) + width_bits = register_len * 8; + else { + width_bits = read(); + } + + auto const as = read(); + if (as != Addressspace::IO) { + Genode::error("unsupported address space access method ", as); + return 0; + } + + raw_io_addr = read(); + } else if (read() != 0 && register_len != 0) { + width_bits = register_len * 8; + raw_io_addr = read(); + } + + if (!width_bits || !raw_io_addr) + return 0u; + + /* I/O address has to be 16 bit */ + if (raw_io_addr >= (1ull << 16) || width_bits >= (1ull << 16)) { + Genode::error("too large I/O address ", raw_io_addr, " ", width_bits); + return 0u; + } + + Genode::uint16_t io_addr = Genode::uint16_t(raw_io_addr); + + if (half_register) + width_bits /= 2; + + if (half_offset) + io_addr += Genode::uint16_t(width_bits) / 2 / 8; + + if (hw_read) { + switch (width_bits) { + case 8: + return inb(io_addr); + case 16: + return inw(io_addr); + case 32: + return inl(io_addr); + default: + Genode::error("unsupported width for I/O IN : ", width_bits); + } + } else { + switch (width_bits) { + case 8: + outb(io_addr, Genode::uint8_t(value)); + break; + case 16: + outw(io_addr, Genode::uint16_t(value)); + break; + case 32: + outl(io_addr, Genode::uint32_t(value)); + break; + case 64: + outl(io_addr, Genode::uint32_t(value)); + if (sizeof(value) == 8) + outl(io_addr + 4, Genode::uint32_t(value >> 32)); + break; + default: + Genode::error("unsupported width for I/O OUT : ", width_bits); + } + } + return 0u; + } + + template + unsigned _read(bool half_register = false, bool half_offset = false) + { + enum { READ = true }; + unsigned value = 0; + + return _access(READ, value, half_register, half_offset); + } + + template + void _write(T value, bool half_register = false, bool half_offset = false) + { + enum { WRITE = false }; + + _access(WRITE, value, half_register, half_offset); + } +}; + + +struct Hw::Acpi_facs : Genode::Mmio<64> +{ + struct Length : Register < 0x04, 32> { }; + struct Fw_wake_vector : Register < 0x0c, 32> { }; + struct Fw_wake_vector_ext : Register < 0x18, 64> { }; + + void wakeup_vector(addr_t const entry) + { + auto len = read(); + if (len >= 0x0c + 4) + write(unsigned(entry)); + + if (len >= 0x18 + 8) + write(0); + } + + Acpi_facs(addr_t const mmio) : Mmio({(char *)mmio, Mmio::SIZE}) { } +}; + + +void Hw::for_each_rsdt_entry(Hw::Acpi_generic &rsdt, auto const &fn) { if (Genode::memcmp(rsdt.signature, "RSDT", 4)) return; - typedef Genode::uint32_t entry_t; + using entry_t = Genode::uint32_t; unsigned const table_size = rsdt.size; unsigned const entry_count = (unsigned)((table_size - sizeof(rsdt)) / sizeof(entry_t)); @@ -95,13 +394,12 @@ void Hw::for_each_rsdt_entry(Hw::Acpi_generic &rsdt, FUNC fn) } -template -void Hw::for_each_xsdt_entry(Hw::Acpi_generic &xsdt, FUNC fn) +void Hw::for_each_xsdt_entry(Hw::Acpi_generic &xsdt, auto const &fn) { if (Genode::memcmp(xsdt.signature, "XSDT", 4)) return; - typedef Genode::uint64_t entry_t; + using entry_t = Genode::uint64_t; unsigned const table_size = xsdt.size; unsigned const entry_count = (unsigned)((table_size - sizeof(xsdt)) / sizeof(entry_t)); @@ -112,8 +410,7 @@ void Hw::for_each_xsdt_entry(Hw::Acpi_generic &xsdt, FUNC fn) } -template -void Hw::for_each_apic_struct(Hw::Acpi_generic &apic_madt, FUNC fn) +void Hw::for_each_apic_struct(Hw::Acpi_generic &apic_madt, auto const &fn) { if (Genode::memcmp(apic_madt.signature, "APIC", 4)) return; diff --git a/repos/base-hw/src/include/hw/spec/x86_64/apic.h b/repos/base-hw/src/include/hw/spec/x86_64/apic.h new file mode 100644 index 0000000000..db1586047a --- /dev/null +++ b/repos/base-hw/src/include/hw/spec/x86_64/apic.h @@ -0,0 +1,64 @@ +/* + * \brief APIC definitions + * \author Stefan Kalkowski + * \date 2024-04-25 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _SRC__INCLUDE__HW__SPEC__X86_64__APIC_H_ +#define _SRC__INCLUDE__HW__SPEC__X86_64__APIC_H_ + +namespace Hw { class Local_apic; } + +#include + +struct Hw::Local_apic : Genode::Mmio +{ + struct Id : Register<0x020, 32> { }; + struct EOI : Register<0x0b0, 32, true> { }; + struct Svr : Register<0x0f0, 32> + { + struct APIC_enable : Bitfield<8, 1> { }; + }; + + /* + * ISR register, see Intel SDM Vol. 3A, section 10.8.4. + * + * Each of the 8 32-bit ISR values is followed by 12 bytes of padding. + */ + struct Isr : Register_array<0x100, 32, 8 * 4, 32> { }; + + /* + * Interrupt control register + */ + struct Icr_low : Register<0x300, 32, true> + { + struct Vector : Bitfield< 0, 8> { }; + struct Delivery_mode : Bitfield< 8, 3> + { + enum Mode { INIT = 5, SIPI = 6 }; + }; + + struct Delivery_status : Bitfield<12, 1> { }; + struct Level_assert : Bitfield<14, 1> { }; + struct Dest_shorthand : Bitfield<18, 2> + { + enum { ALL_OTHERS = 3 }; + }; + }; + + struct Icr_high : Register<0x310, 32, true> + { + struct Destination : Bitfield<24, 8> { }; + }; + + Local_apic(addr_t const addr) : Mmio({(char*)addr, Mmio::SIZE}) {} +}; + +#endif /* _SRC__INCLUDE__HW__SPEC__X86_64__APIC_H_ */ diff --git a/repos/base-hw/src/include/hw/spec/x86_64/cpu.h b/repos/base-hw/src/include/hw/spec/x86_64/cpu.h index 68cf5b8e5b..324f37af67 100644 --- a/repos/base-hw/src/include/hw/spec/x86_64/cpu.h +++ b/repos/base-hw/src/include/hw/spec/x86_64/cpu.h @@ -1,11 +1,12 @@ /* * \brief x86_64 CPU definitions * \author Stefan Kalkowski + * \author Benjamin Lamowski * \date 2017-04-07 */ /* - * Copyright (C) 2017 Genode Labs GmbH + * Copyright (C) 2017-2024 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -16,7 +17,19 @@ #include -namespace Hw { struct X86_64_cpu; } +namespace Hw { struct X86_64_cpu; struct Suspend_type; } + + +/* + * The intended sleep state S0 ... S5. The values are read out by an + * ACPI AML component and are of type TYP_SLPx as described in the + * ACPI specification, e.g. TYP_SLPa and TYP_SLPb. The values differ + * between different PC systems/boards. + */ +struct Hw::Suspend_type { + Genode::uint8_t typ_a; + Genode::uint8_t typ_b; +}; struct Hw::X86_64_cpu @@ -92,9 +105,243 @@ struct Hw::X86_64_cpu }; ); + X86_64_MSR_REGISTER(Amd_vm_syscvg, 0xC0010010, + struct Nested_paging : Bitfield< 0, 1> { }; /* Enable nested paging */ + struct Sev : Bitfield< 1, 1> { }; /* Enable Secure Encrypted Virtualization */ + struct Enc_state : Bitfield< 2, 1> { }; /* Enable Encrypted State for Secure Encrypted Virtualization */ + ); + + X86_64_MSR_REGISTER(Amd_vm_cr, 0xC0010114, + struct Svmdis : Bitfield< 4, 1> { }; /* SVM disabled */ + ); + + /* AMD host save physical address */ + X86_64_MSR_REGISTER(Amd_vm_hsavepa, 0xC0010117); + + X86_64_MSR_REGISTER(Platform_id, 0x17, + struct Bus_ratio : Bitfield<8, 5> { }; /* Bus ratio on Core 2, see SDM 19.7.3 */ + ); + + X86_64_MSR_REGISTER(Platform_info, 0xCE, + struct Ratio : Bitfield< 8, 8> { }; /* Maximum Non-Turbo Ratio (R/O) */ + ); + + X86_64_MSR_REGISTER(Fsb_freq, 0xCD, + struct Speed : Bitfield< 0, 3> { }; /* Scaleable Bus Speed (R/O) */ + ); + + X86_64_MSR_REGISTER(Ia32_efer, 0xC0000080, + struct Lme : Bitfield< 8, 1> { }; /* Long Mode Enable */ + struct Lma : Bitfield<10, 1> { }; /* Long Mode Active */ + struct Svme : Bitfield<12, 1> { }; /* Secure Virtual Machine Enable */ + ); + + /* Map of BASE Address of FS */ + X86_64_MSR_REGISTER(Ia32_fs_base, 0xC0000100); + + /* Map of BASE Address of GS */ + X86_64_MSR_REGISTER(Ia32_gs_base, 0xC0000101); + + /* System Call Target Address */ + X86_64_MSR_REGISTER(Ia32_star, 0xC0000081); + + /* IA-32e Mode System Call Target Address */ + X86_64_MSR_REGISTER(Ia32_lstar, 0xC0000082); + + /* IA-32e Mode System Call Target Address */ + X86_64_MSR_REGISTER(Ia32_cstar, 0xC0000083); + + /* System Call Flag Mask */ + X86_64_MSR_REGISTER(Ia32_fmask, 0xC0000084); + + /* Swap Target of BASE Address of GS */ + X86_64_MSR_REGISTER(Ia32_kernel_gs_base, 0xC0000102); + + /* See Vol. 4, Table 2-2 of the Intel SDM */ + X86_64_MSR_REGISTER(Ia32_feature_control, 0x3A, + struct Lock : Bitfield< 0, 0> { }; /* VMX Lock */ + struct Vmx_no_smx : Bitfield< 2, 2> { }; /* Enable VMX outside SMX */ + ); + + /* + * Auxiliary TSC register + * For details, see Vol. 3B of the Intel SDM (September 2023): + * 18.17.2 IA32_TSC_AUX Register and RDTSCP Support + */ + X86_64_MSR_REGISTER(Ia32_tsc_aux, 0xc0000103); + + /* + * Reporting Register of Basic VMX Capabilities + * For details, see Vol. 3D of the Intel SDM (September 2023): + * A.1 Basic VMX Information + */ + X86_64_MSR_REGISTER(Ia32_vmx_basic, 0x480, + struct Rev : Bitfield< 0,31> { }; /* VMCS revision */ + struct Clear_controls : Bitfield<55, 1> { }; /* VMCS controls may be cleared, see A.2 */ + ); + + /* + * Capability Reporting Register of Pin-Based VM-Execution Controls + * For details, see Vol. 3D of the Intel SDM (September 2023): + * A.3.1 Pin-Based VM-Execution Controls + */ + X86_64_MSR_REGISTER(Ia32_vmx_pinbased_ctls, 0x481, + struct Allowed_0_settings : Bitfield< 0,32> { }; /* allowed 0-settings */ + struct Allowed_1_settings : Bitfield<32,32> { }; /* allowed 1-settings */ + ); + + /* + * Capability Reporting Register of Pin-Based VM-Execution Flex Controls + * For details, see Vol. 3D of the Intel SDM (September 2023): + * A.3.1 Pin-Based VM-Execution Controls + */ + X86_64_MSR_REGISTER(Ia32_vmx_true_pinbased_ctls, 0x48D, + struct Allowed_0_settings : Bitfield< 0,32> { }; /* allowed 0-settings */ + struct Allowed_1_settings : Bitfield<32,32> { }; /* allowed 1-settings */ + ); + + /* + * Capability Reporting Register of Primary Processor-Based VM-Execution Controls + * For details, see Vol. 3D of the Intel SDM (September 2023): + * A.3.2 Primary Processor-Based VM-Execution Controls + */ + X86_64_MSR_REGISTER(Ia32_vmx_procbased_ctls, 0x482, + struct Allowed_0_settings : Bitfield< 0,32> { }; /* allowed 0-settings */ + struct Allowed_1_settings : Bitfield<32,32> { }; /* allowed 1-settings */ + ); + + /* + * Capability Reporting Register of Primary Processor-Based VM-Execution Flex Controls + * For details, see Vol. 3D of the Intel SDM (September 2023): + * A.3.2 Primary Processor-Based VM-Execution Controls + */ + X86_64_MSR_REGISTER(Ia32_vmx_true_procbased_ctls, 0x48E, + struct Allowed_0_settings : Bitfield< 0,32> { }; /* allowed 0-settings */ + struct Allowed_1_settings : Bitfield<32,32> { }; /* allowed 1-settings */ + ); + + /* + * Capability Reporting Register of Primary VM-Exit Controls + * For details, see Vol. 3D of the Intel SDM (September 2023): + * A.4.1 Primary VM-Exit Controls + */ + X86_64_MSR_REGISTER(Ia32_vmx_exit_ctls, 0x483, + struct Allowed_0_settings : Bitfield< 0,32> { }; /* allowed 0-settings */ + struct Allowed_1_settings : Bitfield<32,32> { }; /* allowed 1-settings */ + ); + + /* + * Capability Reporting Register of VM-Exit Flex Controls + * For details, see Vol. 3D of the Intel SDM (September 2023): + * A.4.1 Primary VM-Exit Controls + */ + X86_64_MSR_REGISTER(Ia32_vmx_true_exit_ctls, 0x48F, + struct Allowed_0_settings : Bitfield< 0,32> { }; /* allowed 0-settings */ + struct Allowed_1_settings : Bitfield<32,32> { }; /* allowed 1-settings */ + ); + + /* + * Capability Reporting Register of VM-Entry Controls + * For details, see Vol. 3D of the Intel SDM (September 2023): + * A.5 VM-Entry Controls + */ + X86_64_MSR_REGISTER(Ia32_vmx_entry_ctls, 0x484, + struct Allowed_0_settings : Bitfield< 0,32> { }; /* allowed 0-settings */ + struct Allowed_1_settings : Bitfield<32,32> { }; /* allowed 1-settings */ + ); + + /* + * Capability Reporting Register of VM-Entry Flex Controls + * For details, see Vol. 3D of the Intel SDM (September 2023): + * A.5 VM-Entry Controls + */ + X86_64_MSR_REGISTER(Ia32_vmx_true_entry_ctls, 0x490, + struct Allowed_0_settings : Bitfield< 0,32> { }; /* allowed 0-settings */ + struct Allowed_1_settings : Bitfield<32,32> { }; /* allowed 1-settings */ + ); + + /* + * Capability Reporting Register of Secondary Processor-Based VM-Execution Controls + * For details, see Vol. 3D of the Intel SDM (September 2023): + * A.3.3 Secondary Processor-Based VM-Execution Controls + */ + X86_64_MSR_REGISTER(Ia32_vmx_procbased_ctls2, 0x48B, + struct Allowed_0_settings : Bitfield< 0,32> { }; /* allowed 0-settings */ + struct Allowed_1_settings : Bitfield<32,32> { }; /* allowed 1-settings */ + ); + + /* + * Capability Reporting Register of CR0 Bits Fixed to 0 + * [sic] in fact, bits reported here need to be 1 + * For details, see Vol. 3D of the Intel SDM (September 2023): + * A.7 VMX-Fixed Bits in CR0 + */ + X86_64_MSR_REGISTER(Ia32_vmx_cr0_fixed0, 0x486); + + /* + * Capability Reporting Register of CR0 Bits Fixed to 1 + * [sic] in fact, bits *NOT* reported here need to be 0 + * For details, see Vol. 3D of the Intel SDM (September 2023): + * A.7 VMX-Fixed Bits in CR0 + */ + X86_64_MSR_REGISTER(Ia32_vmx_cr0_fixed1, 0x487); + + /* + * Capability Reporting Register of CR5 Bits Fixed to 0 + * [sic] in fact, bits reported here need to be 1 + * For details, see Vol. 3D of the Intel SDM (September 2023): + * A.8 VMX-Fixed Bits in CR4 + */ + X86_64_MSR_REGISTER(Ia32_vmx_cr4_fixed0, 0x488); + + /* + * Capability Reporting Register of CR4 Bits Fixed to 1 + * [sic] in fact, bits *NOT* reported here need to be 0 + * For details, see Vol. 3D of the Intel SDM (September 2023): + * A.8 VMX-Fixed Bits in CR4 + */ + X86_64_MSR_REGISTER(Ia32_vmx_cr4_fixed1, 0x489); + + + X86_64_CPUID_REGISTER(Cpuid_0_eax, 0, eax); + X86_64_CPUID_REGISTER(Cpuid_0_ebx, 0, ebx); + X86_64_CPUID_REGISTER(Cpuid_0_ecx, 0, ecx); + X86_64_CPUID_REGISTER(Cpuid_0_edx, 0, edx); + + X86_64_CPUID_REGISTER(Cpuid_1_eax, 1, eax); + + X86_64_CPUID_REGISTER(Cpuid_1_ebx, 1, ebx, + struct Apic_id : Bitfield<24, 8> { }; + ); + + X86_64_CPUID_REGISTER(Cpuid_1_ecx, 1, ecx, + struct Vmx : Bitfield< 5, 1> { }; + struct Tsc_deadline : Bitfield<24, 1> { }; + ); + X86_64_CPUID_REGISTER(Cpuid_1_edx, 1, edx, struct Pat : Bitfield<16, 1> { }; ); + + X86_64_CPUID_REGISTER(Cpuid_15_eax, 15, eax); + X86_64_CPUID_REGISTER(Cpuid_15_ebx, 15, ebx); + X86_64_CPUID_REGISTER(Cpuid_15_ecx, 15, ecx); + + X86_64_CPUID_REGISTER(Cpuid_16_eax, 16, ecx); + + X86_64_CPUID_REGISTER(Cpuid_8000000A_edx, 0x8000000A, edx, + struct Np : Bitfield<0, 1> { }; /* Nested paging */ + ); + + X86_64_CPUID_REGISTER(Cpuid_80000007_eax, 0x80000007, eax, + struct Invariant_tsc : Bitfield<2, 1> { }; /* Invariant TSC */ + ); + + X86_64_CPUID_REGISTER(Cpuid_80000001_ecx, 0x80000001, ecx, + struct Svm : Bitfield<2, 1> { }; + ); + + Suspend_type suspend; }; #endif /* _SRC__LIB__HW__SPEC__X86_64__CPU_H_ */ diff --git a/repos/base-hw/src/include/hw/spec/x86_64/page_table.h b/repos/base-hw/src/include/hw/spec/x86_64/page_table.h index 81d194d5e6..acc4911d8b 100644 --- a/repos/base-hw/src/include/hw/spec/x86_64/page_table.h +++ b/repos/base-hw/src/include/hw/spec/x86_64/page_table.h @@ -16,13 +16,14 @@ #include #include -#include +#include #include #include #include #include namespace Hw { + using namespace Genode; /** * IA-32e paging translates 48-bit linear addresses to 52-bit physical @@ -142,7 +143,7 @@ class Hw::Level_4_translation_table void operator () (addr_t const vo, addr_t const pa, size_t const size, - Descriptor::access_t &desc) + Descriptor::access_t &desc) const { if ((vo & ~PAGE_MASK) || (pa & ~PAGE_MASK) || size < PAGE_SIZE) @@ -164,12 +165,11 @@ class Hw::Level_4_translation_table struct Remove_func { void operator () (addr_t /* vo */, addr_t /* pa */, size_t /* size */, - Descriptor::access_t &desc) + Descriptor::access_t &desc) const { desc = 0; } }; - template - void _range_op(addr_t vo, addr_t pa, size_t size, FUNC &&func) + void _range_op(addr_t vo, addr_t pa, size_t size, auto const &fn) { for (size_t i = vo >> PAGE_SIZE_LOG2; size > 0; i = vo >> PAGE_SIZE_LOG2) { @@ -177,7 +177,7 @@ class Hw::Level_4_translation_table addr_t end = (vo + PAGE_SIZE) & PAGE_MASK; size_t sz = Genode::min(size, end-vo); - func(vo, pa, sz, _entries[i]); + fn(vo, pa, sz, _entries[i]); /* check whether we wrap */ if (end < vo) return; @@ -351,7 +351,7 @@ class Hw::Page_directory void operator () (addr_t const vo, addr_t const pa, size_t const size, - typename Descriptor::access_t &desc) + typename Descriptor::access_t &desc) const { using Td = Table_descriptor; using access_t = typename Descriptor::access_t; @@ -396,7 +396,7 @@ class Hw::Page_directory void operator () (addr_t const vo, addr_t /* pa */, size_t const size, - typename Base_descriptor::access_t &desc) + typename Base_descriptor::access_t &desc) const { if (Base_descriptor::present(desc)) { if (Base_descriptor::maps_page(desc)) { @@ -417,8 +417,7 @@ class Hw::Page_directory } }; - template - void _range_op(addr_t vo, addr_t pa, size_t size, FUNC &&func) + void _range_op(addr_t vo, addr_t pa, size_t size, auto const &fn) { for (size_t i = vo >> PAGE_SIZE_LOG2; size > 0; i = vo >> PAGE_SIZE_LOG2) @@ -427,7 +426,7 @@ class Hw::Page_directory addr_t end = (vo + PAGE_SIZE) & PAGE_MASK; size_t sz = Genode::min(size, end-vo); - func(vo, pa, sz, _entries[i]); + fn(vo, pa, sz, _entries[i]); /* check whether we wrap */ if (end < vo) return; @@ -552,7 +551,7 @@ class Hw::Pml4_table void operator () (addr_t const vo, addr_t const pa, size_t const size, - Descriptor::access_t &desc) + Descriptor::access_t &desc) const { /* we need to use a next level table */ if (!Descriptor::present(desc)) { @@ -576,7 +575,7 @@ class Hw::Pml4_table void operator () (addr_t const vo, addr_t /* pa */, size_t const size, - Descriptor::access_t &desc) + Descriptor::access_t &desc) const { if (Descriptor::present(desc)) { /* use allocator to retrieve virt address of table */ @@ -591,8 +590,7 @@ class Hw::Pml4_table } }; - template - void _range_op(addr_t vo, addr_t pa, size_t size, FUNC &&func) + void _range_op(addr_t vo, addr_t pa, size_t size, auto const &fn) { for (size_t i = (vo & SIZE_MASK) >> PAGE_SIZE_LOG2; size > 0; i = (vo & SIZE_MASK) >> PAGE_SIZE_LOG2) { @@ -600,7 +598,7 @@ class Hw::Pml4_table addr_t end = (vo + PAGE_SIZE) & PAGE_MASK; size_t sz = Genode::min(size, end-vo); - func(vo, pa, sz, _entries[i]); + fn(vo, pa, sz, _entries[i]); /* check whether we wrap */ if (end < vo) return; diff --git a/repos/base-hw/src/include/hw/spec/x86_64/pc_board.h b/repos/base-hw/src/include/hw/spec/x86_64/pc_board.h index f450f93f11..be21f64a89 100644 --- a/repos/base-hw/src/include/hw/spec/x86_64/pc_board.h +++ b/repos/base-hw/src/include/hw/spec/x86_64/pc_board.h @@ -23,6 +23,12 @@ namespace Hw::Pc_board { struct Boot_info; struct Serial; enum Dummies { UART_BASE, UART_CLOCK }; + + /** + * The constant 'NR_OF_CPUS' defines the _maximum_ of cpus currently + * supported on x86. The actual number is detected at booting. + */ + static constexpr Genode::size_t NR_OF_CPUS = 256; } @@ -37,6 +43,7 @@ struct Hw::Pc_board::Boot_info Acpi_rsdp acpi_rsdp { }; Framebuffer framebuffer { }; Genode::addr_t efi_system_table { 0 }; + Genode::addr_t acpi_fadt { 0 }; Boot_info() {} Boot_info(Acpi_rsdp const &acpi_rsdp, diff --git a/repos/base-hw/src/include/hw/spec/x86_64/register_macros.h b/repos/base-hw/src/include/hw/spec/x86_64/register_macros.h index ba93e85be7..3720bb8f49 100644 --- a/repos/base-hw/src/include/hw/spec/x86_64/register_macros.h +++ b/repos/base-hw/src/include/hw/spec/x86_64/register_macros.h @@ -51,7 +51,7 @@ }; #define X86_64_CPUID_REGISTER(name, id, reg, ...) \ - struct name : Genode::Register<64> \ + struct name : Genode::Register<32> \ { \ static access_t read() \ { \ diff --git a/repos/base-hw/src/include/hw/spec/x86_64/x86_64.h b/repos/base-hw/src/include/hw/spec/x86_64/x86_64.h index 19f4a399e9..c3a53eacb9 100644 --- a/repos/base-hw/src/include/hw/spec/x86_64/x86_64.h +++ b/repos/base-hw/src/include/hw/spec/x86_64/x86_64.h @@ -1,11 +1,12 @@ /* * \brief Definitions common to all x86_64 CPUs * \author Stefan Kalkowski + * \author Benjamin Lamowski * \date 2017-04-10 */ /* - * Copyright (C) 2017 Genode Labs GmbH + * Copyright (C) 2017-2024 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -14,10 +15,16 @@ #ifndef _SRC__LIB__HW__SPEC__X86_64__X86_64_H_ #define _SRC__LIB__HW__SPEC__X86_64__X86_64_H_ +#include #include #include -namespace Hw { struct Cpu_memory_map; } +namespace Hw { + struct Cpu_memory_map; + struct Virtualization_support; + class Vendor; + class Lapic; +} struct Hw::Cpu_memory_map @@ -25,6 +32,7 @@ struct Hw::Cpu_memory_map enum { MMIO_IOAPIC_BASE = 0xfec00000, MMIO_IOAPIC_SIZE = 0x1000, + LAPIC_SIZE = 0xe34, }; static Genode::addr_t lapic_phys_base() @@ -35,4 +43,282 @@ struct Hw::Cpu_memory_map } }; +class Hw::Vendor +{ +private: + static constexpr char const *const vendor_string[] = { + "GenuineIntel", + "AuthenticAMD", + "KVMKVMKVM", + "Microsoft Hv", + "VMwareVMware", + "XenVMMXenVMM" + "Unknown", + }; + +public: + enum Vendor_id { + INTEL, + AMD, + KVM, + MICROSOFT, + VMWARE, + XEN, + UNKNOWN, + }; + + static Vendor_id get_vendor_id() + { + using Cpu = Hw::X86_64_cpu; + using Genode::uint32_t; + + uint32_t ebx = static_cast(Cpu::Cpuid_0_ebx::read()); + uint32_t ecx = static_cast(Cpu::Cpuid_0_ecx::read()); + uint32_t edx = static_cast(Cpu::Cpuid_0_edx::read()); + + Genode::size_t v; + for (v = 0; v <= Vendor_id::UNKNOWN; ++v) + if (*reinterpret_cast(vendor_string[v] + + 0) == ebx && + *reinterpret_cast(vendor_string[v] + + 4) == edx && + *reinterpret_cast(vendor_string[v] + + 8) == ecx) + break; + + return Vendor_id(v); + } + + static unsigned get_family() + { + using Cpu = Hw::X86_64_cpu; + + Cpu::Cpuid_1_eax::access_t eax = Cpu::Cpuid_1_eax::read(); + return ((eax >> 8 & 0xf) + (eax >> 20 & 0xff)) & 0xff; + } + + static unsigned get_model() + { + using Cpu = Hw::X86_64_cpu; + + Cpu::Cpuid_1_eax::access_t eax = Cpu::Cpuid_1_eax::read(); + return ((eax >> 4 & 0xf) + (eax >> 12 & 0xf0)) & 0xff; + } +}; + + +class Hw::Lapic +{ + private: + static bool _has_tsc_dl() + { + using Cpu = Hw::X86_64_cpu; + + Cpu::Cpuid_1_ecx::access_t ecx = Cpu::Cpuid_1_ecx::read(); + return (bool)Cpu::Cpuid_1_ecx::Tsc_deadline::get(ecx); + } + + /* + * Adapted from Christian Prochaska's and Alexander Boettcher's + * implementation for Nova. + * + * For details, see Vol. 3B of the Intel SDM (September 2023): + * 20.7.3 Determining the Processor Base Frequency + */ + static unsigned _read_tsc_freq() + { + using Cpu = Hw::X86_64_cpu; + + if (Vendor::get_vendor_id() != Vendor::INTEL) + return 0; + + unsigned const model = Vendor::get_model(); + unsigned const family = Vendor::get_family(); + + enum + { + Cpu_id_clock = 0x15, + Cpu_id_base_freq = 0x16 + }; + + Cpu::Cpuid_0_eax::access_t eax_0 = Cpu::Cpuid_0_eax::read(); + + /* + * If CPUID leaf 15 is available, return the frequency reported there. + */ + if (eax_0 >= Cpu_id_clock) { + Cpu::Cpuid_15_eax::access_t eax_15 = Cpu::Cpuid_15_eax::read(); + Cpu::Cpuid_15_ebx::access_t ebx_15 = Cpu::Cpuid_15_ebx::read(); + Cpu::Cpuid_15_ecx::access_t ecx_15 = Cpu::Cpuid_15_ecx::read(); + + if (eax_15 && ebx_15) { + if (ecx_15) + return static_cast( + ((Genode::uint64_t)(ecx_15) * ebx_15) / eax_15 / 1000 + ); + + if (family == 6) { + if (model == 0x5c) /* Goldmont */ + return static_cast((19200ull * ebx_15) / eax_15); + if (model == 0x55) /* Xeon */ + return static_cast((25000ull * ebx_15) / eax_15); + } + + if (family >= 6) + return static_cast((24000ull * ebx_15) / eax_15); + } + } + + + /* + * Specific methods for family 6 models + */ + if (family == 6) { + unsigned freq_tsc = 0U; + + if (model == 0x2a || + model == 0x2d || /* Sandy Bridge */ + model >= 0x3a) /* Ivy Bridge and later */ + { + Cpu::Platform_info::access_t platform_info = Cpu::Platform_info::read(); + Genode::uint64_t ratio = Cpu::Platform_info::Ratio::get(platform_info); + freq_tsc = static_cast(ratio * 100000); + } else if (model == 0x1a || + model == 0x1e || + model == 0x1f || + model == 0x2e || /* Nehalem */ + model == 0x25 || + model == 0x2c || + model == 0x2f) /* Xeon Westmere */ + { + Cpu::Platform_info::access_t platform_info = Cpu::Platform_info::read(); + Genode::uint64_t ratio = Cpu::Platform_info::Ratio::get(platform_info); + freq_tsc = static_cast(ratio * 133330); + } else if (model == 0x17 || model == 0xf) { /* Core 2 */ + Cpu::Fsb_freq::access_t fsb_freq = Cpu::Fsb_freq::read(); + Genode::uint64_t freq_bus = Cpu::Fsb_freq::Speed::get(fsb_freq); + + switch (freq_bus) { + case 0b101: freq_bus = 100000; break; + case 0b001: freq_bus = 133330; break; + case 0b011: freq_bus = 166670; break; + case 0b010: freq_bus = 200000; break; + case 0b000: freq_bus = 266670; break; + case 0b100: freq_bus = 333330; break; + case 0b110: freq_bus = 400000; break; + default: freq_bus = 0; break; + } + + Cpu::Platform_id::access_t platform_id = Cpu::Platform_id::read(); + Genode::uint64_t ratio = Cpu::Platform_id::Bus_ratio::get(platform_id); + + freq_tsc = static_cast(freq_bus * ratio); + } + + if (!freq_tsc) + Genode::warning("TSC: family 6 Intel platform info reports bus frequency of 0"); + else + return freq_tsc; + } + + + /* + * Finally, using Processor Frequency Information for a rough estimate + */ + if (eax_0 >= Cpu_id_base_freq) { + Cpu::Cpuid_16_eax::access_t base_mhz = Cpu::Cpuid_16_eax::read(); + + if (base_mhz) { + Genode::warning("TSC: using processor base frequency: ", base_mhz, " MHz"); + return base_mhz * 1000; + } else { + Genode::warning("TSC: CPUID reported processor base frequency of 0"); + } + } + + return 0; + } + + static unsigned _measure_tsc_freq() + { + const unsigned Tsc_fixed_value = 2400; + + Genode::warning("TSC: calibration not yet implemented, using fixed value of ", Tsc_fixed_value, " MHz"); + /* TODO: implement TSC calibration on AMD */ + return Tsc_fixed_value * 1000; + } + + public: + static Genode::uint64_t rdtsc() + { + Genode::uint32_t low, high; + asm volatile("rdtsc" : "=a"(low), "=d"(high)); + return (Genode::uint64_t)(high) << 32 | low; + } + + static bool invariant_tsc() + { + using Cpu = Hw::X86_64_cpu; + + Cpu::Cpuid_80000007_eax::access_t eax = + Cpu::Cpuid_80000007_eax::read(); + return Cpu::Cpuid_80000007_eax::Invariant_tsc::get(eax); + } + + static unsigned tsc_freq() + { + unsigned freq = _read_tsc_freq(); + if (freq) + return freq; + else + return _measure_tsc_freq(); + } +}; + +struct Hw::Virtualization_support +{ + using Cpu = Hw::X86_64_cpu; + static bool has_svm() + { + /* + * Check for vendor because the CPUID bit checked for SVM is reserved + * on Intel. + */ + if (Hw::Vendor::get_vendor_id() != Hw::Vendor::AMD) + return false; + + Hw::X86_64_cpu::Cpuid_80000001_ecx::access_t cpuid_svm = + Hw::X86_64_cpu::Cpuid_80000001_ecx::read(); + + if (Hw::X86_64_cpu::Cpuid_80000001_ecx::Svm::get(cpuid_svm) != 0) { + Hw::X86_64_cpu::Amd_vm_cr::access_t amd_vm_cr = + Hw::X86_64_cpu::Amd_vm_cr::read(); + + if (Hw::X86_64_cpu::Amd_vm_cr::Svmdis::get(amd_vm_cr) == 0) + return true; + } + + return false; + } + + static bool has_vmx() + { + if (Hw::Vendor::get_vendor_id() != Hw::Vendor::INTEL) + return false; + + Cpu::Cpuid_1_ecx::access_t ecx = Cpu::Cpuid_1_ecx::read(); + if (!Cpu::Cpuid_1_ecx::Vmx::get(ecx)) + return false; + + /* Check if VMX feature is off and locked */ + Cpu::Ia32_feature_control::access_t feature_control = + Cpu::Ia32_feature_control::read(); + if (!Cpu::Ia32_feature_control::Vmx_no_smx::get(feature_control) && + Cpu::Ia32_feature_control::Lock::get(feature_control)) + return false; + + return true; + } +}; + #endif /* _SRC__LIB__HW__SPEC__X86_64__X86_64_H_ */ diff --git a/repos/base-hw/src/lib/base/arm/cache.cc b/repos/base-hw/src/lib/base/arm/cache.cc new file mode 100644 index 0000000000..40a25c419e --- /dev/null +++ b/repos/base-hw/src/lib/base/arm/cache.cc @@ -0,0 +1,41 @@ +/* + * \brief Implementation of cache operations for ARM + * \author Stefan Kalkowski + * \date 2022-12-16 + */ + +/* + * Copyright (C) 2022 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#include + +#include +#include + +using namespace Genode; + + +void Genode::cache_coherent(addr_t addr, size_t size) +{ + for_each_page(addr, size, [] (addr_t addr, size_t size) { + Kernel::cache_coherent_region(addr, size); }); +} + + +void Genode::cache_clean_invalidate_data(addr_t addr, size_t size) +{ + for_each_page(addr, size, [] (addr_t addr, size_t size) { + Kernel::cache_clean_invalidate_data_region(addr, size); }); +} + + +void Genode::cache_invalidate_data(addr_t addr, size_t size) +{ + for_each_page(addr, size, [] (addr_t addr, size_t size) { + Kernel::cache_invalidate_data_region(addr, size); }); +} + diff --git a/repos/base-hw/src/lib/base/arm_64/cache.cc b/repos/base-hw/src/lib/base/arm_64/cache.cc new file mode 100644 index 0000000000..337bd00019 --- /dev/null +++ b/repos/base-hw/src/lib/base/arm_64/cache.cc @@ -0,0 +1,57 @@ +/* + * \brief Implementation of the cache maintainance on ARMv8 + * \author Stefan Kalkowski + * \date 2022-12-16 + */ + +/* + * Copyright (C) 2022 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#include + +#include +#include +#include + +using namespace Genode; + +void Genode::cache_coherent(addr_t addr, size_t size) +{ + Genode::memory_barrier(); + + for_each_page(addr, size, [] (addr_t addr, size_t size) { + for_each_cache_line(addr, size, [&] (addr_t addr) { + asm volatile("dc cvau, %0" :: "r" (addr)); + asm volatile("dsb ish"); + asm volatile("ic ivau, %0" :: "r" (addr)); + asm volatile("dsb ish"); + asm volatile("isb"); + }); + }); +} + + +void Genode::cache_clean_invalidate_data(addr_t addr, size_t size) +{ + Genode::memory_barrier(); + + for_each_page(addr, size, [&] (addr_t addr, size_t size) { + + for_each_cache_line(addr, size, [&] (addr_t addr) { + asm volatile("dc civac, %0" :: "r" (addr)); }); + }); + + asm volatile("dsb sy"); + asm volatile("isb"); +} + + +void Genode::cache_invalidate_data(addr_t addr, size_t size) +{ + for_each_page(addr, size, [] (addr_t addr, size_t size) { + Kernel::cache_invalidate_data_region(addr, size); }); +} diff --git a/repos/base-hw/src/lib/base/cache.cc b/repos/base-hw/src/lib/base/cache.cc deleted file mode 100644 index b2b1b61160..0000000000 --- a/repos/base-hw/src/lib/base/cache.cc +++ /dev/null @@ -1,62 +0,0 @@ -/* - * \brief Implementation of the cache operations - * \author Christian Prochaska - * \date 2014-05-13 - */ - -/* - * Copyright (C) 2014-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#include - -#include -#include -#include -#include - -using namespace Genode; - - -template -static void for_cachelines(addr_t addr, size_t size, FN const & fn) -{ - /** - * The kernel accepts the cache maintainance calls for one designated - * page only. Otherwise, it just ignores the call to limit the time being - * uninteruppptible in the kernel. Therefore, we have to loop if more than - * one page is affected by the given region. - */ - while (size) { - addr_t next_page = align_addr(addr+1, get_page_size_log2()); - size_t s = min(size, next_page - addr); - touch_read(reinterpret_cast(addr)); - fn(addr, s); - addr += s; - size -= s; - } -} - - -void Genode::cache_coherent(addr_t addr, size_t size) -{ - for_cachelines(addr, size, [] (addr_t addr, size_t size) { - Kernel::cache_coherent_region(addr, size); }); -} - - -void Genode::cache_clean_invalidate_data(addr_t addr, size_t size) -{ - for_cachelines(addr, size, [] (addr_t addr, size_t size) { - Kernel::cache_clean_invalidate_data_region(addr, size); }); -} - - -void Genode::cache_invalidate_data(addr_t addr, size_t size) -{ - for_cachelines(addr, size, [] (addr_t addr, size_t size) { - Kernel::cache_invalidate_data_region(addr, size); }); -} diff --git a/repos/base-hw/src/lib/base/capability_slab.cc b/repos/base-hw/src/lib/base/capability_slab.cc new file mode 100644 index 0000000000..5231d73c83 --- /dev/null +++ b/repos/base-hw/src/lib/base/capability_slab.cc @@ -0,0 +1,70 @@ +/* + * \brief Capability slab management + * \author Norman Feske + * \date 2023-06-20 + */ + +/* + * Copyright (C) 2023 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#include +#include +#include +#include + +using namespace Genode; + + +static Parent *parent_ptr; +static Pd_session::Native_pd *native_pd_ptr; + + +void Genode::init_cap_slab(Pd_session &pd, Parent &parent) +{ + static Hw_native_pd_client native_pd(pd.native_pd()); + + parent_ptr = &parent; + native_pd_ptr = &native_pd; +} + + +size_t Genode::avail_capability_slab() +{ + return native_pd_ptr ? native_pd_ptr->avail_cap_slab() : 0UL; +} + + +void Genode::upgrade_capability_slab() +{ + if (!native_pd_ptr || !parent_ptr) { + error("missing call of 'init_cap_slab'"); + return; + } + + auto request_resources_from_parent = [&] (Ram_quota ram, Cap_quota caps) + { + /* + * The call of 'resource_request' is handled synchronously by + * 'Expanding_parent_client'. + */ + String<100> const args("ram_quota=", ram, ", cap_quota=", caps); + parent_ptr->resource_request(args.string()); + }; + + retry( + [&] { + retry( + [&] { + native_pd_ptr->upgrade_cap_slab(); }, + [&] { + request_resources_from_parent(Ram_quota{8192}, Cap_quota{0}); + }); + }, + [&] { + request_resources_from_parent(Ram_quota{0}, Cap_quota{2}); + }); +} diff --git a/repos/base-hw/src/lib/base/env_deprecated.cc b/repos/base-hw/src/lib/base/env_deprecated.cc deleted file mode 100644 index 964beeb5f6..0000000000 --- a/repos/base-hw/src/lib/base/env_deprecated.cc +++ /dev/null @@ -1,88 +0,0 @@ -/* - * \brief Environment initialization - * \author Norman Feske - * \author Christian Helmuth - * \date 2006-07-27 - */ - -/* - * Copyright (C) 2006-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#include -#include -#include -#include -#include - -#include - -namespace Genode { - - /* - * Request pointer to static environment of the Genode application - */ - Env_deprecated *env_deprecated() - { - /* - * By placing the environment as static object here, we ensure that its - * constructor gets called when this function is used the first time. - */ - static Genode::Platform_env _env; - return &_env; - } -} - - -using Native_pd_capability = Genode::Capability; -static Native_pd_capability native_pd_cap; - - -void Genode::init_parent_resource_requests(Genode::Env & env) -{ - /** - * Catch up asynchronous resource request and notification - * mechanism construction of the expanding parent environment - */ - using Parent = Expanding_parent_client; - static_cast(&env.parent())->init_fallback_signal_handling(); - native_pd_cap = env.pd().native_pd(); -} - - -void Genode::upgrade_capability_slab() -{ - if (!native_pd_cap.valid()) { - Genode::error("Cannot upgrade capability slab " - "not initialized appropriatedly"); - return; - } - - auto request_resources_from_parent = [&] (Ram_quota ram, Cap_quota caps) - { - /* - * The call of 'resource_request' is handled synchronously by - * 'Expanding_parent_client'. - */ - String<100> const args("ram_quota=", ram, ", cap_quota=", caps); - internal_env().parent().resource_request(args.string()); - }; - - retry( - [&] () { - retry( - [&] () { - Genode::Hw_native_pd_client pd(native_pd_cap); - pd.upgrade_cap_slab(); - }, - [&] () { - request_resources_from_parent(Ram_quota{8192}, Cap_quota{0}); - }); - }, - [&] () { - request_resources_from_parent(Ram_quota{0}, Cap_quota{2}); - }); -} diff --git a/repos/base-hw/src/lib/base/ipc.cc b/repos/base-hw/src/lib/base/ipc.cc index 4990f6eccc..0bd382cb04 100644 --- a/repos/base-hw/src/lib/base/ipc.cc +++ b/repos/base-hw/src/lib/base/ipc.cc @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -106,7 +107,7 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst, switch (Kernel::send_request_msg(Capability_space::capid(dst), (unsigned)rcv_caps)) { - case -1: throw Blocking_canceled(); + case -1: sleep_forever(); case -2: upgrade_capability_slab(); break; default: done = true; break; } @@ -152,7 +153,7 @@ Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &, } switch (ret) { - case -1: throw Blocking_canceled(); + case -1: sleep_forever(); case -2: upgrade_capability_slab(); break; default: done = true; break; } diff --git a/repos/base-hw/src/lib/base/signal_receiver.cc b/repos/base-hw/src/lib/base/signal_receiver.cc index 94660af344..e9c920efa7 100644 --- a/repos/base-hw/src/lib/base/signal_receiver.cc +++ b/repos/base-hw/src/lib/base/signal_receiver.cc @@ -17,6 +17,7 @@ #include #include #include +#include /* base-internal includes */ #include @@ -28,11 +29,11 @@ using namespace Genode; -static Pd_session *_pd_ptr; -static Pd_session &pd() +static Env *_env_ptr; +static Env &env() { - if (_pd_ptr) - return *_pd_ptr; + if (_env_ptr) + return *_env_ptr; class Missing_init_signal_thread { }; throw Missing_init_signal_thread(); @@ -43,27 +44,36 @@ static Pd_session &pd() * On base-hw, we don't use a signal thread. We mereely save the PD session * pointer of the passed 'env' argument. */ -void Genode::init_signal_thread(Env &env) { _pd_ptr = &env.pd(); } -void Genode::destroy_signal_thread() { } +void Genode::init_signal_thread(Env &env) { _env_ptr = &env; } -Signal_receiver::Signal_receiver() +void Genode::init_signal_receiver(Pd_session &, Parent &) { } + + +Signal_receiver::Signal_receiver() : _pd(env().pd()) { for (;;) { Ram_quota ram_upgrade { 0 }; Cap_quota cap_upgrade { 0 }; - try { - _cap = pd().alloc_signal_source(); - break; - } - catch (Out_of_ram) { ram_upgrade = Ram_quota { 2*1024*sizeof(long) }; } - catch (Out_of_caps) { cap_upgrade = Cap_quota { 4 }; } + using Error = Pd_session::Signal_source_error; - internal_env().upgrade(Parent::Env::pd(), - String<100>("ram_quota=", ram_upgrade, ", " - "cap_quota=", cap_upgrade).string()); + env().pd().signal_source().with_result( + [&] (Capability cap) { _cap = cap; }, + [&] (Error e) { + switch (e) { + case Error::OUT_OF_RAM: ram_upgrade = { 2*1024*sizeof(long) }; break; + case Error::OUT_OF_CAPS: cap_upgrade = { 4 }; break; + } + }); + + if (_cap.valid()) + break; + + env().upgrade(Parent::Env::pd(), + String<100>("ram_quota=", ram_upgrade, ", " + "cap_quota=", cap_upgrade).string()); } } @@ -71,11 +81,11 @@ Signal_receiver::Signal_receiver() void Signal_receiver::_platform_destructor() { /* release server resources of receiver */ - pd().free_signal_source(_cap); + env().pd().free_signal_source(_cap); } -void Signal_receiver::_platform_begin_dissolve(Signal_context * const c) +void Signal_receiver::_platform_begin_dissolve(Signal_context &context) { /** * Mark the Signal_context as already pending to prevent the receiver @@ -83,43 +93,67 @@ void Signal_receiver::_platform_begin_dissolve(Signal_context * const c) * processing */ { - Mutex::Guard context_guard(c->_mutex); - c->_pending = true; - c->_curr_signal = Signal::Data(nullptr, 0); + Mutex::Guard context_guard(context._mutex); + context._pending = true; + context._curr_signal = Signal::Data(); } - Kernel::kill_signal_context(Capability_space::capid(c->_cap)); + Kernel::kill_signal_context(Capability_space::capid(context._cap)); } -void Signal_receiver::_platform_finish_dissolve(Signal_context *) { } +void Signal_receiver::_platform_finish_dissolve(Signal_context &) { } -Signal_context_capability Signal_receiver::manage(Signal_context * const c) +Signal_context_capability Signal_receiver::manage(Signal_context &context) { /* ensure that the context isn't managed already */ Mutex::Guard contexts_guard(_contexts_mutex); - Mutex::Guard context_guard(c->_mutex); - if (c->_receiver) - throw Context_already_in_use(); + Mutex::Guard context_guard(context._mutex); + + if (context._receiver) { + error("ill-attempt to manage an already managed signal context"); + return context._cap; + } + + Signal_receiver &this_receiver = *this; for (;;) { Ram_quota ram_upgrade { 0 }; Cap_quota cap_upgrade { 0 }; - try { - /* use signal context as imprint */ - c->_cap = pd().alloc_context(_cap, (unsigned long)c); - c->_receiver = this; - _contexts.insert_as_tail(c); - return c->_cap; - } - catch (Out_of_ram) { ram_upgrade = Ram_quota { 1024*sizeof(long) }; } - catch (Out_of_caps) { cap_upgrade = Cap_quota { 4 }; } + using Error = Pd_session::Alloc_context_error; - internal_env().upgrade(Parent::Env::pd(), - String<100>("ram_quota=", ram_upgrade, ", " - "cap_quota=", cap_upgrade).string()); + /* use pointer to signal context as imprint */ + Pd_session::Imprint const imprint { addr_t(&context) }; + + _pd.alloc_context(_cap, imprint).with_result( + [&] (Capability cap) { + context._cap = cap; + context._receiver = &this_receiver; + _contexts.insert_as_tail(&context); + }, + [&] (Error e) { + switch (e) { + case Error::OUT_OF_RAM: + ram_upgrade = Ram_quota { 1024*sizeof(long) }; + break; + case Error::OUT_OF_CAPS: + cap_upgrade = Cap_quota { 4 }; + break; + case Error::INVALID_SIGNAL_SOURCE: + error("ill-attempt to create context for invalid signal source"); + sleep_forever(); + break; + } + }); + + if (context._cap.valid()) + return context._cap; + + env().upgrade(Parent::Env::pd(), + String<100>("ram_quota=", ram_upgrade, ", " + "cap_quota=", cap_upgrade).string()); } } @@ -144,7 +178,7 @@ void Signal_receiver::block_for_signal() if (!context->_pending) { /* update signal context */ Mutex::Guard context_guard(context->_mutex); - unsigned const num = context->_curr_signal.num + data->num; + unsigned const num = data->num; context->_pending = true; context->_curr_signal = Signal::Data(context, num); } @@ -166,7 +200,7 @@ Signal Signal_receiver::pending_signal() _contexts.head(context._next); context._pending = false; result = context._curr_signal; - context._curr_signal = Signal::Data(0, 0); + context._curr_signal = Signal::Data(); Trace::Signal_received trace_event(context, result.num); return true; diff --git a/repos/base-hw/src/lib/base/thread_bootstrap.cc b/repos/base-hw/src/lib/base/thread_bootstrap.cc index 0a7692c7ad..77e6dd0303 100644 --- a/repos/base-hw/src/lib/base/thread_bootstrap.cc +++ b/repos/base-hw/src/lib/base/thread_bootstrap.cc @@ -18,6 +18,7 @@ #include /* base-internal includes */ +#include #include #include #include @@ -35,9 +36,8 @@ namespace Hw { ** Startup library support ** *****************************/ -void prepare_init_main_thread() +void Genode::prepare_init_main_thread() { - using namespace Genode; using namespace Hw; /* diff --git a/repos/base-hw/src/lib/base/thread_start.cc b/repos/base-hw/src/lib/base/thread_start.cc index 83dc1033dc..4416750504 100644 --- a/repos/base-hw/src/lib/base/thread_start.cc +++ b/repos/base-hw/src/lib/base/thread_start.cc @@ -18,11 +18,11 @@ #include #include #include -#include /* base-internal includes */ #include #include +#include #include using namespace Genode; @@ -33,6 +33,20 @@ namespace Hw { } +static Capability pd_session_cap(Capability pd_cap = { }) +{ + static Capability cap = pd_cap; /* defined once by 'init_thread_start' */ + return cap; +} + + +static Thread_capability main_thread_cap(Thread_capability main_cap = { }) +{ + static Thread_capability cap = main_cap; + return cap; +} + + /************ ** Thread ** ************/ @@ -45,8 +59,8 @@ void Thread::_init_platform_thread(size_t weight, Type type) /* create server object */ addr_t const utcb = (addr_t)&_stack->utcb(); - _thread_cap = _cpu_session->create_thread(env_deprecated()->pd_session_cap(), - name(), _affinity, + + _thread_cap = _cpu_session->create_thread(pd_session_cap(), name(), _affinity, Weight(weight), utcb); return; } @@ -54,14 +68,18 @@ void Thread::_init_platform_thread(size_t weight, Type type) size_t const utcb_size = sizeof(Native_utcb); addr_t const stack_area = stack_area_virtual_base(); addr_t const utcb_new = (addr_t)&_stack->utcb() - stack_area; - Region_map * const rm = env_stack_area_region_map; /* remap initial main-thread UTCB according to stack-area spec */ - try { rm->attach_at(Hw::_main_thread_utcb_ds, utcb_new, utcb_size); } - catch(...) { - error("failed to re-map UTCB"); - while (1) ; - } + if (env_stack_area_region_map->attach(Hw::_main_thread_utcb_ds, { + .size = utcb_size, + .offset = { }, + .use_at = true, + .at = utcb_new, + .executable = { }, + .writeable = true + }).failed()) + error("failed to attach UTCB to local address space"); + /* adjust initial object state in case of a main thread */ native_thread().cap = Hw::_main_thread_cap; _thread_cap = main_thread_cap(); @@ -70,10 +88,14 @@ void Thread::_init_platform_thread(size_t weight, Type type) void Thread::_deinit_platform_thread() { - if (!_cpu_session) - _cpu_session = env_deprecated()->cpu_session(); + if (!_cpu_session) { + error("Thread::_cpu_session unexpectedly not defined"); + return; + } - _cpu_session->kill_thread(_thread_cap); + _thread_cap.with_result( + [&] (Thread_capability cap) { _cpu_session->kill_thread(cap); }, + [&] (Cpu_session::Create_thread_error) { }); /* detach userland stack */ size_t const size = sizeof(_stack->utcb()); @@ -83,19 +105,49 @@ void Thread::_deinit_platform_thread() } -void Thread::start() +Thread::Start_result Thread::start() { - /* attach userland stack */ - try { - Dataspace_capability ds = Cpu_thread_client(_thread_cap).utcb(); - size_t const size = sizeof(_stack->utcb()); - addr_t dst = Stack_allocator::addr_to_base(_stack) + - stack_virtual_size() - size - stack_area_virtual_base(); - env_stack_area_region_map->attach_at(ds, dst, size); - } catch (...) { - error("failed to attach userland stack"); - sleep_forever(); - } - /* start thread with its initial IP and aligned SP */ - Cpu_thread_client(_thread_cap).start((addr_t)_thread_start, _stack->top()); + while (avail_capability_slab() < 5) + upgrade_capability_slab(); + + return _thread_cap.convert( + [&] (Thread_capability cap) { + Cpu_thread_client cpu_thread(cap); + + /* attach UTCB at top of stack */ + size_t const size = sizeof(_stack->utcb()); + return env_stack_area_region_map->attach(cpu_thread.utcb(), { + .size = size, + .offset = { }, + .use_at = true, + .at = Stack_allocator::addr_to_base(_stack) + + stack_virtual_size() - size - stack_area_virtual_base(), + .executable = { }, + .writeable = true + }).convert( + [&] (Region_map::Range) { + /* start execution with initial IP and aligned SP */ + cpu_thread.start((addr_t)_thread_start, _stack->top()); + return Start_result::OK; + }, + [&] (Region_map::Attach_error) { + error("failed to attach userland stack"); + return Start_result::DENIED; + } + ); + }, + [&] (Cpu_session::Create_thread_error) { return Start_result::DENIED; } + ); +} + + +void Genode::init_thread_start(Capability pd_cap) +{ + pd_session_cap(pd_cap); +} + + +void Genode::init_thread_bootstrap(Cpu_session &, Thread_capability main_cap) +{ + main_thread_cap(main_cap); } diff --git a/repos/base-hw/src/lib/base/vm.cc b/repos/base-hw/src/lib/base/vm.cc index 009efdf158..e519056b77 100644 --- a/repos/base-hw/src/lib/base/vm.cc +++ b/repos/base-hw/src/lib/base/vm.cc @@ -1,5 +1,5 @@ /* - * \brief Client-side VM session interface + * \brief Client-side VM session interface (base-hw generic) * \author Alexander Boettcher * \date 2018-08-27 */ @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -26,6 +27,7 @@ using namespace Genode; using Exit_config = Vm_connection::Exit_config; +using Call_with_state = Vm_connection::Call_with_state; /**************************** @@ -38,39 +40,57 @@ struct Hw_vcpu : Rpc_client, Noncopyable Attached_dataspace _state; Native_capability _kernel_vcpu { }; + void *_ep_handler { nullptr }; Capability _create_vcpu(Vm_connection &, Vcpu_handler_base &); + Vcpu_state & _local_state() + { + return *_state.local_addr(); + } + public: + const Hw_vcpu& operator=(const Hw_vcpu &) = delete; + Hw_vcpu(const Hw_vcpu&) = delete; + Hw_vcpu(Env &, Vm_connection &, Vcpu_handler_base &); - void run() { - Kernel::run_vm(Capability_space::capid(_kernel_vcpu)); } - void pause() { - Kernel::pause_vm(Capability_space::capid(_kernel_vcpu)); } - - Vcpu_state & state() { return *_state.local_addr(); } + void with_state(Call_with_state &); }; Hw_vcpu::Hw_vcpu(Env &env, Vm_connection &vm, Vcpu_handler_base &handler) : Rpc_client(_create_vcpu(vm, handler)), - _state(env.rm(), vm.with_upgrade([&] () { return call(); })) + _state(env.rm(), vm.with_upgrade([&] { return call(); })) { + _ep_handler = reinterpret_cast(&handler.rpc_ep()); call(handler.signal_cap()); _kernel_vcpu = call(); } +void Hw_vcpu::with_state(Call_with_state &cw) +{ + if (Thread::myself() != _ep_handler) { + error("vCPU state requested outside of vcpu_handler EP"); + sleep_forever(); + } + Kernel::pause_vm(Capability_space::capid(_kernel_vcpu)); + + if (cw.call_with_state(_local_state())) + Kernel::run_vm(Capability_space::capid(_kernel_vcpu)); +} + + Capability Hw_vcpu::_create_vcpu(Vm_connection &vm, Vcpu_handler_base &handler) { Thread &tep { *reinterpret_cast(&handler.rpc_ep()) }; - return vm.with_upgrade([&] () { + return vm.with_upgrade([&] { return vm.call(tep.cap()); }); } @@ -79,9 +99,7 @@ Capability Hw_vcpu::_create_vcpu(Vm_connection &vm, ** vCPU API ** **************/ -void Vm_connection::Vcpu::run() { static_cast(_native_vcpu).run(); } -void Vm_connection::Vcpu::pause() { static_cast(_native_vcpu).pause(); } -Vcpu_state & Vm_connection::Vcpu::state() { return static_cast(_native_vcpu).state(); } +void Vm_connection::Vcpu::_with_state(Call_with_state &cw) { static_cast(_native_vcpu).with_state(cw); } Vm_connection::Vcpu::Vcpu(Vm_connection &vm, Allocator &alloc, diff --git a/repos/base-hw/src/lib/base/x86_64/vm.cc b/repos/base-hw/src/lib/base/x86_64/vm.cc new file mode 100644 index 0000000000..eb20d519af --- /dev/null +++ b/repos/base-hw/src/lib/base/x86_64/vm.cc @@ -0,0 +1,121 @@ +/* + * \brief Client-side VM session interface (x86_64 specific) + * \author Alexander Boettcher + * \author Benjamin Lamowski + * \date 2018-08-27 + */ + +/* + * Copyright (C) 2018-2023 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +using namespace Genode; + +using Exit_config = Vm_connection::Exit_config; +using Call_with_state = Vm_connection::Call_with_state; + + +/**************************** + ** hw vCPU implementation ** + ****************************/ + +struct Hw_vcpu : Rpc_client, Noncopyable +{ + private: + + Attached_dataspace _state; + Native_capability _kernel_vcpu { }; + Vcpu_handler_base & _vcpu_handler; + unsigned _id { 0 }; + void *_ep_handler { nullptr }; + + void _run(); + Vcpu_state & _local_state() { return *_state.local_addr(); } + Capability _create_vcpu(Vm_connection &, + Vcpu_handler_base &); + + public: + + const Hw_vcpu& operator=(const Hw_vcpu &) = delete; + Hw_vcpu(const Hw_vcpu&) = delete; + + Hw_vcpu(Env &, Vm_connection &, Vcpu_handler_base &); + + void with_state(Call_with_state &); + +}; + + +Hw_vcpu::Hw_vcpu(Env &env, Vm_connection &vm, Vcpu_handler_base &handler) +: + Rpc_client(_create_vcpu(vm, handler)), + _state(env.rm(), vm.with_upgrade([&] { return call(); })), + _vcpu_handler(handler) +{ + static unsigned counter = 0; + call(handler.signal_cap()); + _kernel_vcpu = call(); + _id = counter++; + _ep_handler = reinterpret_cast(&handler.rpc_ep()); + _run(); +} + + +void Hw_vcpu::_run() +{ + Kernel::run_vm(Capability_space::capid(_kernel_vcpu)); +} + + +void Hw_vcpu::with_state(Call_with_state &cw) +{ + if (Thread::myself() != _ep_handler) { + error("vCPU state requested outside of vcpu_handler EP"); + sleep_forever(); + } + Kernel::pause_vm(Capability_space::capid(_kernel_vcpu)); + + if(cw.call_with_state(_local_state())) + _run(); +} + + +Capability Hw_vcpu::_create_vcpu(Vm_connection &vm, + Vcpu_handler_base &handler) +{ + Thread &tep { *reinterpret_cast(&handler.rpc_ep()) }; + + return vm.with_upgrade([&] { + return vm.call(tep.cap()); }); +} + + +/************** + ** vCPU API ** + **************/ + +void Vm_connection::Vcpu::_with_state(Call_with_state &cw) { static_cast(_native_vcpu).with_state(cw); } + + +Vm_connection::Vcpu::Vcpu(Vm_connection &vm, Allocator &alloc, + Vcpu_handler_base &handler, Exit_config const &) +: + _native_vcpu(*new (alloc) Hw_vcpu(vm._env, vm, handler)) +{ } diff --git a/repos/base-hw/src/lib/hw/spec/32bit/memory_consts.s b/repos/base-hw/src/lib/hw/spec/32bit/memory_consts.s new file mode 100644 index 0000000000..c4ff961917 --- /dev/null +++ b/repos/base-hw/src/lib/hw/spec/32bit/memory_consts.s @@ -0,0 +1,30 @@ +/* + * \brief Kernel/Bootstrap constants shared in between C++/Assembler + * \author Stefan Kalkowski + * \date 2024-07-02 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +##include + +#namespace Hw { +# namespace Mm { + +HW_MM_KERNEL_START = 0x80000000 +HW_MM_KERNEL_STACK_SIZE = 0x10000 + +HW_MM_CPU_LOCAL_MEMORY_AREA_START = 0xd0000000 +HW_MM_CPU_LOCAL_MEMORY_AREA_SIZE = 0x10000000 +HW_MM_CPU_LOCAL_MEMORY_SLOT_SIZE = 0x100000 +HW_MM_CPU_LOCAL_MEMORY_SLOT_STACK_OFFSET = 0x0 +HW_MM_CPU_LOCAL_MEMORY_SLOT_OBJECT_OFFSET = 0x20000 +HW_MM_CPU_LOCAL_MEMORY_SLOT_OBJECT_SIZE = 0x2000 + +# } +#} diff --git a/repos/base-hw/src/lib/hw/spec/32bit/memory_map.cc b/repos/base-hw/src/lib/hw/spec/32bit/memory_map.cc index f1482762fb..62ab59d7a6 100644 --- a/repos/base-hw/src/lib/hw/spec/32bit/memory_map.cc +++ b/repos/base-hw/src/lib/hw/spec/32bit/memory_map.cc @@ -14,6 +14,7 @@ /* base-internal includes */ #include +#include #include using Hw::Memory_region; @@ -22,7 +23,6 @@ using Genode::Native_utcb; static constexpr addr_t USER_START = Genode::user_utcb_main_thread() + sizeof(Native_utcb); -static constexpr addr_t KERNEL_START = 0x80000000UL; Memory_region const Hw::Mm::user() { return Memory_region(USER_START, KERNEL_START - USER_START); } @@ -36,8 +36,12 @@ Memory_region const Hw::Mm::core_stack_area() { Memory_region const Hw::Mm::core_page_tables() { return Memory_region(0xc0000000UL, 0x10000000UL); } +Memory_region const Hw::Mm::cpu_local_memory() { + return Memory_region(CPU_LOCAL_MEMORY_AREA_START, + CPU_LOCAL_MEMORY_AREA_SIZE); } + Memory_region const Hw::Mm::core_mmio() { - return Memory_region(0xd0000000UL, 0x10000000UL); } + return Memory_region(0xf0000000UL, 0xf000000UL); } Memory_region const Hw::Mm::system_exception_vector() { return Memory_region(0xfff00000UL, 0x1000UL); } diff --git a/repos/base-hw/src/lib/hw/spec/64bit/memory_consts.s b/repos/base-hw/src/lib/hw/spec/64bit/memory_consts.s new file mode 100644 index 0000000000..f4dc117e2f --- /dev/null +++ b/repos/base-hw/src/lib/hw/spec/64bit/memory_consts.s @@ -0,0 +1,30 @@ +/* + * \brief Kernel/Bootstrap constants shared in between C++/Assembler + * \author Stefan Kalkowski + * \date 2024-07-02 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +##include + +#namespace Hw { +# namespace Mm { + +HW_MM_KERNEL_START = 0xffffffc000000000 +HW_MM_KERNEL_STACK_SIZE = 0x10000 + +HW_MM_CPU_LOCAL_MEMORY_AREA_START = 0xffffffe070000000 +HW_MM_CPU_LOCAL_MEMORY_AREA_SIZE = 0x10000000 +HW_MM_CPU_LOCAL_MEMORY_SLOT_SIZE = 0x100000 +HW_MM_CPU_LOCAL_MEMORY_SLOT_STACK_OFFSET = 0x0 +HW_MM_CPU_LOCAL_MEMORY_SLOT_OBJECT_OFFSET = 0x20000 +HW_MM_CPU_LOCAL_MEMORY_SLOT_OBJECT_SIZE = 0x2000 + +# } +#} diff --git a/repos/base-hw/src/lib/hw/spec/64bit/memory_map.cc b/repos/base-hw/src/lib/hw/spec/64bit/memory_map.cc index 2c77ec90d5..1046edbaa4 100644 --- a/repos/base-hw/src/lib/hw/spec/64bit/memory_map.cc +++ b/repos/base-hw/src/lib/hw/spec/64bit/memory_map.cc @@ -14,16 +14,16 @@ /* base-internal includes */ #include +#include #include using Hw::Memory_region; using Genode::addr_t; using Genode::Native_utcb; -static constexpr addr_t USER_START = Genode::user_utcb_main_thread() - + sizeof(Native_utcb); -static constexpr addr_t USER_END = (1ULL << (39 - 1)); -static constexpr addr_t KERNEL_START = 0xffffffc000000000UL; +static constexpr addr_t USER_START = Genode::user_utcb_main_thread() + + sizeof(Native_utcb); +static constexpr addr_t USER_END = (1ULL << (39 - 1)); Memory_region const Hw::Mm::user() { @@ -53,5 +53,9 @@ Memory_region const Hw::Mm::hypervisor_exception_vector() { Memory_region const Hw::Mm::hypervisor_stack() { return Memory_region(0xffffffe060000000UL, 0x10000UL); } +Memory_region const Hw::Mm::cpu_local_memory() { + return Memory_region(CPU_LOCAL_MEMORY_AREA_START, + CPU_LOCAL_MEMORY_AREA_SIZE); } + Memory_region const Hw::Mm::supervisor_exception_vector() { return Memory_region(KERNEL_START, 0x1000UL); } diff --git a/repos/base-hw/src/test/cpu_quota/include/sync_session/connection.h b/repos/base-hw/src/test/cpu_quota/include/sync_session/connection.h index 725f6eec2d..049530a455 100644 --- a/repos/base-hw/src/test/cpu_quota/include/sync_session/connection.h +++ b/repos/base-hw/src/test/cpu_quota/include/sync_session/connection.h @@ -29,7 +29,7 @@ struct Sync::Connection : public Genode::Connection, { explicit Connection(Genode::Env &env) : - Genode::Connection(env, session(env.parent(), "ram_quota=4K")), + Genode::Connection(env, Label(), Ram_quota { 4*1024 }, Args()), Genode::Rpc_client(cap()) { } diff --git a/repos/base-hw/src/test/cpu_quota/main.cc b/repos/base-hw/src/test/cpu_quota/main.cc index 7dc81e1e3d..24523c69eb 100644 --- a/repos/base-hw/src/test/cpu_quota/main.cc +++ b/repos/base-hw/src/test/cpu_quota/main.cc @@ -30,9 +30,9 @@ struct Single_signal Signal_context_capability cap; Signal_transmitter transmitter; - Single_signal() : cap(receiver.manage(&context)), transmitter(cap) { } + Single_signal() : cap(receiver.manage(context)), transmitter(cap) { } - ~Single_signal() { receiver.dissolve(&context); } + ~Single_signal() { receiver.dissolve(context); } void receive() { receiver.wait_for_signal(); } void submit() { transmitter.submit(); } }; @@ -77,7 +77,7 @@ class Counter : public Thread _start_measurement.receive(); _stage = MEASUREMENT; _synchronizer.synchronize(); - while (_stage == MEASUREMENT) { value++; } + while (_stage == MEASUREMENT) { value = value + 1; } } _value = value; _start_destruction.submit(); diff --git a/repos/base-hw/src/test/cpu_scheduler/main.cc b/repos/base-hw/src/test/cpu_scheduler/main.cc new file mode 100644 index 0000000000..1eba863af6 --- /dev/null +++ b/repos/base-hw/src/test/cpu_scheduler/main.cc @@ -0,0 +1,912 @@ +/* + * \brief Test CPU-scheduler implementation of the kernel + * \author Martin Stein + * \author Stefan Kalkowski + * \date 2014-09-30 + */ + +/* + * Copyright (C) 2014-2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* Genode includes */ +#include +#include + +/* core includes */ +#include + +using namespace Genode; +using namespace Kernel; + +namespace Scheduler_test { + + class Context; + class Scheduler; + class Main; + + using Share_list = List>; + static Context &cast(Kernel::Scheduler::Context &c); + + static Context const &cast(Kernel::Scheduler::Context const &c); +} + + +class Scheduler_test::Context : public Kernel::Scheduler::Context +{ + private: + + using Priority = Kernel::Scheduler::Priority; + using Label = String<32>; + + Label const _label; + + public: + + Context(Priority const prio, + unsigned const quota, + Label const &label) + : + Kernel::Scheduler::Context { prio, quota }, + _label { label } + { } + + Label const &label() const { return _label; } +}; + + +struct Scheduler_test::Scheduler : Kernel::Scheduler +{ + void _each_prio_until(auto const &fn) const + { + for (unsigned p = Priority::max(); p != Priority::min()-1; p--) + if (fn(p)) + return; + } + + void print(Output &output) const; + + using Kernel::Scheduler::Scheduler; +}; + + +class Scheduler_test::Main +{ + private: + + enum { MAX_NR_OF_SHARES = 10 }; + enum { IDLE_SHARE_ID = 0 }; + enum { INVALID_SHARE_ID = MAX_NR_OF_SHARES }; + + Env &_env; + Context _idle_context { 0, 0, (unsigned)IDLE_SHARE_ID }; + Constructible _contexts[MAX_NR_OF_SHARES] { }; + time_t _current_time { 0 }; + Scheduler _scheduler; + + unsigned _id_of_context(Context const &c) const + { + if (&c == &_idle_context) { + + return IDLE_SHARE_ID; + } + unsigned result { INVALID_SHARE_ID }; + for (unsigned id { 1 }; id < sizeof(_contexts)/sizeof(_contexts[0]); + id++) { + + if (_contexts[id].constructed() && + (&*_contexts[id] == &c)) { + + result = id; + } + } + if (result == INVALID_SHARE_ID) { + + error("failed to determine ID of c"); + _env.parent().exit(-1); + } + return result; + } + + Context &_context(unsigned const id) + { + if (id == IDLE_SHARE_ID) { + + return _idle_context; + } + if (id >= sizeof(_contexts)/sizeof(_contexts[0])) { + + error("failed to determine share by ID"); + _env.parent().exit(-1); + } + return *_contexts[id]; + } + + void _construct_context(unsigned const id, + unsigned const line_nr) + { + if (id == IDLE_SHARE_ID || + id >= sizeof(_contexts)/sizeof(_contexts[0])) { + + error("failed to construct share in line ", line_nr); + _env.parent().exit(-1); + } + if (_contexts[id].constructed()) { + + error("failed to construct share in line ", line_nr); + _env.parent().exit(-1); + } + unsigned prio { 0 }; + unsigned quota { 0 }; + switch (id) { + case 1: prio = 2; quota = 230; break; + case 2: prio = 0; quota = 170; break; + case 3: prio = 3; quota = 110; break; + case 4: prio = 1; quota = 90; break; + case 5: prio = 3; quota = 120; break; + case 6: prio = 3; quota = 0; break; + case 7: prio = 2; quota = 180; break; + case 8: prio = 2; quota = 100; break; + case 9: prio = 2; quota = 0; break; + default: + + error("failed to construct share in line ", line_nr); + _env.parent().exit(-1); + break; + } + _contexts[id].construct(prio, quota, id); + _scheduler.insert(*_contexts[id]); + } + + void _destroy_context(unsigned const id, + unsigned const line_nr) + { + if (id == IDLE_SHARE_ID || + id >= sizeof(_contexts)/sizeof(_contexts[0])) { + + error("failed to destroy share in line ", line_nr); + _env.parent().exit(-1); + } + if (!_contexts[id].constructed()) { + + error("failed to destroy share in line ", line_nr); + _env.parent().exit(-1); + } + _scheduler.remove(_context(id)); + _contexts[id].destruct(); + } + + void _update_current_and_check(unsigned const consumed_time, + unsigned const expected_round_time, + unsigned const expected_current_id, + unsigned const expected_current_time_left, + unsigned const line_nr) + { + _current_time += consumed_time; + _scheduler.update(_current_time); + unsigned const round_time { + _scheduler._super_period_length - _scheduler._super_period_left }; + + if (round_time != expected_round_time) { + + error("wrong time ", round_time, " in line ", line_nr); + _env.parent().exit(-1); + } + Context ¤t { cast(_scheduler.current()) }; + unsigned const current_time_left { _scheduler.current_time_left() }; + if (¤t != &_context(expected_current_id)) { + + error("wrong share ", _id_of_context(current), " in line ", + line_nr); + + _env.parent().exit(-1); + } + if (current_time_left != expected_current_time_left) { + + error("wrong quota ", current_time_left, " in line ", line_nr); + _env.parent().exit(-1); + } + } + + void _set_context_ready_and_check(unsigned const share_id, + bool const expect_current_outdated, + unsigned const line_nr) + { + _scheduler.ready(_context(share_id)); + if (_scheduler.need_to_schedule() != expect_current_outdated) { + + error("wrong check result ", + _scheduler.need_to_schedule(), " in line ", line_nr); + + _env.parent().exit(-1); + } + } + + public: + + Main(Env &env); +}; + + +/************************* + ** Utilities functions ** + *************************/ + +static Scheduler_test::Context & +Scheduler_test::cast(Kernel::Scheduler::Context &share) +{ + return *static_cast(&share); +} + + +static Scheduler_test::Context const & +Scheduler_test::cast(Kernel::Scheduler::Context const &share) +{ + return *static_cast(&share); +} + + +/*************************************** + ** Scheduler_test::Scheduler ** + ***************************************/ + +void Scheduler_test::Scheduler::print(Output &output) const +{ + using Genode::print; + + print(output, "(\n"); + print(output, " quota: ", _super_period_left, "/", _super_period_length, ", "); + print(output, "slack: ", _slack_quota, ", "); + print(output, "need to schedule: ", need_to_schedule() ? "true" : "false", ", "); + print(output, "last_time: ", _last_time); + + if (_current != nullptr) { + + print(output, "\n current: ( "); + if (need_to_schedule()) { + print(output, "\033[31m"); + } else { + print(output, "\033[32m"); + } + print(output, "id: ", cast(*_current).label(), ", "); + print(output, "quota: ", _current_quantum, ", "); + print(output, "\033[0m"); + print(output, "priotized: ", (_current && _current->_priotized_time_left) ? "true" : "false", ", "); + print(output, "yields: ", _state == YIELD ? "true" : "false", " "); + print(output, ")"); + } + bool prios_empty { true }; + _each_prio_until([&] (Priority const prio) { + if (prios_empty && (_rpl[prio.value].head() || _upl[prio.value].head())) + prios_empty = false; + return false; + }); + if (!prios_empty) { + + _each_prio_until([&] (Priority const prio) { + + unsigned const p = prio.value; + if (_rpl[p].head() || _upl[p].head()) { + + print(output, "\n prio ", p, ": ("); + if (_rpl[p].head()) { + + print(output, " ready: "); + bool first { true }; + _rpl[p].for_each([&] (Kernel::Scheduler::Context const &c) { + + if (&c == _current && _current->_priotized_time_left) { + if (need_to_schedule()) { + print(output, "\033[31m"); + } else { + print(output, "\033[32m"); + } + } + print( + output, first ? "" : ", ", cast(c).label() , "-", + c._priotized_time_left, "/", c._quota); + + if (&c == _current && _current->_priotized_time_left) { + print(output, "\033[0m"); + } + first = false; + }); + } + if (_upl[p].head()) { + + print(output, " unready: "); + bool first { true }; + _upl[p].for_each([&] (Kernel::Scheduler::Context const &c) { + + print(output, first ? "" : ", ", cast(c).label() , "-", + c._priotized_time_left, "/", c._quota); + + first = false; + }); + } + print(output, " )"); + } + return false; + }); + } + if (_slack_list.head()) { + + print(output, "\n slacks: "); + bool first { true }; + _slack_list.for_each([&] (Kernel::Scheduler::Context const &c) { + + if (&c == _current && !_current->_priotized_time_left) { + if (need_to_schedule()) { + print(output, "\033[31m"); + } else { + print(output, "\033[32m"); + } + } + print( + output, first ? "" : ", ", cast(c).label() , "-", + c._slack_time_left); + + first = false; + + if (&c == _current && !_current->_priotized_time_left) { + print(output, "\033[0m"); + } + }); + print(output, "\n"); + } + print(output, ")"); +} + + +/****************************** + ** Scheduler_test::Main ** + ******************************/ + +Scheduler_test::Main::Main(Env &env) +: + _env { env }, + _scheduler { _idle_context, 1000, 100 } +{ + /******************** + ** Round #1: Idle ** + ********************/ + + _update_current_and_check( 10, 10, 0, 100, __LINE__); + _update_current_and_check( 90, 100, 0, 100, __LINE__); + _update_current_and_check(120, 200, 0, 100, __LINE__); + _update_current_and_check(130, 300, 0, 100, __LINE__); + _update_current_and_check(140, 400, 0, 100, __LINE__); + _update_current_and_check(150, 500, 0, 100, __LINE__); + _update_current_and_check(160, 600, 0, 100, __LINE__); + _update_current_and_check(170, 700, 0, 100, __LINE__); + _update_current_and_check(180, 800, 0, 100, __LINE__); + _update_current_and_check(190, 900, 0, 100, __LINE__); + _update_current_and_check(200, 0, 0, 100, __LINE__); + + + /****************************************** + ** Round #2: One prioritized, one slack ** + *****************************************/ + + _construct_context(1, __LINE__); + _update_current_and_check(111, 100, 0, 100, __LINE__); + + _scheduler.ready(_context(1)); + _update_current_and_check(123, 200, 1, 230, __LINE__); + + _scheduler.unready(_context(1)); + _update_current_and_check(200, 400, 0, 100, __LINE__); + + _scheduler.ready(_context(1)); + _update_current_and_check( 10, 410, 1, 30, __LINE__); + _update_current_and_check(100, 440, 1, 100, __LINE__); + _update_current_and_check(200, 540, 1, 100, __LINE__); + + _scheduler.unready(_context(1)); + _update_current_and_check(200, 640, 0, 100, __LINE__); + _update_current_and_check(200, 740, 0, 100, __LINE__); + + _scheduler.ready(_context(1)); + _update_current_and_check( 10, 750, 1, 100, __LINE__); + _update_current_and_check( 50, 800, 1, 50, __LINE__); + _update_current_and_check( 20, 820, 1, 30, __LINE__); + _update_current_and_check(100, 850, 1, 100, __LINE__); + _update_current_and_check(200, 950, 1, 50, __LINE__); + _update_current_and_check(200, 0, 1, 230, __LINE__); + + + /****************************************** + ** Round #3: One priotized per priority ** + ******************************************/ + + _construct_context(2, __LINE__); + _scheduler.ready(_context(2)); + _update_current_and_check( 50, 50, 1, 180, __LINE__); + + _scheduler.unready(_context(1)); + _update_current_and_check( 70, 120, 2, 170, __LINE__); + + _scheduler.ready(_context(1)); + _scheduler.unready(_context(2)); + _update_current_and_check(110, 230, 1, 110, __LINE__); + _update_current_and_check( 90, 320, 1, 20, __LINE__); + + _scheduler.ready(_context(2)); + _scheduler.unready(_context(1)); + _update_current_and_check( 10, 330, 2, 60, __LINE__); + + _construct_context(3, __LINE__); + _update_current_and_check( 40, 370, 2, 20, __LINE__); + + _scheduler.ready(_context(3)); + _update_current_and_check( 10, 380, 3, 110, __LINE__); + _update_current_and_check(150, 490, 2, 10, __LINE__); + _update_current_and_check( 10, 500, 2, 100, __LINE__); + _update_current_and_check( 60, 560, 2, 40, __LINE__); + + _construct_context(4, __LINE__); + _update_current_and_check( 60, 600, 3, 100, __LINE__); + + _construct_context(6, __LINE__); + _scheduler.ready(_context(6)); + _update_current_and_check(120, 700, 6, 100, __LINE__); + + _scheduler.ready(_context(4)); + _update_current_and_check( 80, 780, 4, 90, __LINE__); + + _scheduler.unready(_context(4)); + _scheduler.ready(_context(1)); + _update_current_and_check( 50, 830, 1, 10, __LINE__); + _update_current_and_check( 50, 840, 1, 50, __LINE__); + _update_current_and_check( 50, 890, 6, 20, __LINE__); + _update_current_and_check(100, 910, 2, 90, __LINE__); + _update_current_and_check( 60, 970, 2, 30, __LINE__); + _update_current_and_check( 60, 0, 3, 110, __LINE__); + + + /************************************************* + ** Round #4: Multiple prioritized per priority ** + *************************************************/ + + _construct_context(5, __LINE__); + _update_current_and_check( 60, 60, 3, 50, __LINE__); + + _scheduler.ready(_context(4)); + _scheduler.unready(_context(3)); + _update_current_and_check( 40, 100, 1, 230, __LINE__); + + _construct_context(7, __LINE__); + _scheduler.ready(_context(7)); + _update_current_and_check(200, 300, 7, 180, __LINE__); + + _construct_context(8, __LINE__); + _scheduler.ready(_context(5)); + _update_current_and_check(100, 400, 5, 120, __LINE__); + + _scheduler.ready(_context(3)); + _update_current_and_check(100, 500, 3, 10, __LINE__); + _update_current_and_check( 30, 510, 5, 20, __LINE__); + + _construct_context(9, __LINE__); + _scheduler.ready(_context(9)); + _update_current_and_check( 10, 520, 5, 10, __LINE__); + _update_current_and_check( 50, 530, 7, 80, __LINE__); + + _scheduler.ready(_context(8)); + _scheduler.unready(_context(7)); + _update_current_and_check( 10, 540, 8, 100, __LINE__); + + _scheduler.unready(_context(8)); + _update_current_and_check( 80, 620, 1, 30, __LINE__); + _update_current_and_check(200, 650, 4, 90, __LINE__); + _update_current_and_check(100, 740, 2, 170, __LINE__); + + _scheduler.ready(_context(8)); + _scheduler.ready(_context(7)); + _update_current_and_check( 10, 750, 7, 70, __LINE__); + + _scheduler.unready(_context(7)); + _scheduler.unready(_context(3)); + _update_current_and_check( 10, 760, 8, 20, __LINE__); + + _scheduler.unready(_context(8)); + _update_current_and_check( 10, 770, 2, 160, __LINE__); + + _scheduler.unready(_context(2)); + _update_current_and_check( 40, 810, 4, 100, __LINE__); + + _scheduler.ready(_context(3)); + _update_current_and_check( 30, 840, 3, 100, __LINE__); + _update_current_and_check( 70, 910, 3, 30, __LINE__); + + _scheduler.ready(_context(7)); + _scheduler.ready(_context(8)); + _update_current_and_check( 10, 920, 8, 10, __LINE__); + _update_current_and_check( 30, 930, 7, 60, __LINE__); + + _scheduler.ready(_context(2)); + _scheduler.unready(_context(7)); + _update_current_and_check( 10, 940, 2, 60, __LINE__); + + _scheduler.unready(_context(3)); + _scheduler.unready(_context(5)); + _update_current_and_check( 40, 980, 2, 20, __LINE__); + + _scheduler.unready(_context(9)); + _scheduler.unready(_context(4)); + _update_current_and_check( 10, 990, 2, 10, __LINE__); + _update_current_and_check( 40, 0, 1, 230, __LINE__); + + + /************************************ + ** Round #5: Yield, ready & check ** + ************************************/ + + _scheduler.unready(_context(6)); + _update_current_and_check( 30, 30, 1, 200, __LINE__); + + _scheduler.yield(); + _update_current_and_check( 20, 50, 8, 100, __LINE__); + _update_current_and_check(200, 150, 2, 170, __LINE__); + + _scheduler.yield(); + _update_current_and_check( 70, 220, 8, 100, __LINE__); + + _scheduler.unready(_context(8)); + _scheduler.yield(); + _update_current_and_check( 40, 260, 2, 10, __LINE__); + _update_current_and_check( 40, 270, 1, 100, __LINE__); + + _scheduler.unready(_context(1)); + _update_current_and_check( 40, 310, 2, 100, __LINE__); + _update_current_and_check( 10, 320, 2, 90, __LINE__); + + _set_context_ready_and_check(1, true, __LINE__); + _update_current_and_check(200, 410, 1, 60, __LINE__); + _update_current_and_check( 10, 420, 1, 50, __LINE__); + + _scheduler.unready(_context(1)); + _update_current_and_check( 10, 430, 2, 100, __LINE__); + + _set_context_ready_and_check(5, true, __LINE__); + _update_current_and_check( 10, 440, 5, 120, __LINE__); + + _scheduler.yield(); + _update_current_and_check( 90, 530, 5, 100, __LINE__); + + _scheduler.yield(); + _update_current_and_check( 10, 540, 2, 90, __LINE__); + + _set_context_ready_and_check(7, true, __LINE__); + _update_current_and_check( 10, 550, 7, 180, __LINE__); + + _scheduler.yield(); + _update_current_and_check( 10, 560, 7, 100, __LINE__); + + _scheduler.yield(); + _update_current_and_check( 10, 570, 2, 80, __LINE__); + + _scheduler.yield(); + _update_current_and_check( 10, 580, 5, 100, __LINE__); + + _scheduler.unready(_context(5)); + _update_current_and_check( 10, 590, 7, 100, __LINE__); + + _scheduler.unready(_context(7)); + _set_context_ready_and_check(5, true, __LINE__); + _update_current_and_check( 10, 600, 5, 90, __LINE__); + + _set_context_ready_and_check(7, true, __LINE__); + _update_current_and_check(200, 690, 7, 90, __LINE__); + + _scheduler.unready(_context(5)); + _scheduler.unready(_context(7)); + _update_current_and_check( 20, 710, 2, 100, __LINE__); + + _scheduler.unready(_context(2)); + _update_current_and_check( 10, 720, 0, 100, __LINE__); + _update_current_and_check( 10, 730, 0, 100, __LINE__); + _update_current_and_check(100, 830, 0, 100, __LINE__); + + _set_context_ready_and_check(9, true, __LINE__); + _update_current_and_check( 10, 840, 9, 100, __LINE__); + + _set_context_ready_and_check(6, true, __LINE__); + _update_current_and_check( 20, 860, 6, 100, __LINE__); + + _set_context_ready_and_check(8, true, __LINE__); + _update_current_and_check( 10, 870, 8, 100, __LINE__); + + _scheduler.yield(); + _update_current_and_check( 10, 880, 6, 90, __LINE__); + + _scheduler.yield(); + _update_current_and_check( 10, 890, 9, 80, __LINE__); + + _set_context_ready_and_check(7, true, __LINE__); + _scheduler.yield(); + _update_current_and_check( 20, 910, 7, 70, __LINE__); + + _scheduler.unready(_context(8)); + _scheduler.unready(_context(9)); + _update_current_and_check( 10, 920, 7, 60, __LINE__); + + _scheduler.unready(_context(6)); + _scheduler.unready(_context(7)); + _update_current_and_check( 10, 930, 0, 70, __LINE__); + + _set_context_ready_and_check(4, true, __LINE__); + _update_current_and_check( 20, 950, 4, 50, __LINE__); + + _set_context_ready_and_check(3, true, __LINE__); + _set_context_ready_and_check(1, true, __LINE__); + _update_current_and_check( 10, 960, 3, 40, __LINE__); + + _set_context_ready_and_check(5, false, __LINE__); + _scheduler.unready(_context(4)); + _update_current_and_check( 10, 970, 3, 30, __LINE__); + + _scheduler.unready(_context(3)); + _update_current_and_check( 10, 980, 5, 20, __LINE__); + + _set_context_ready_and_check(3, true, __LINE__); + _update_current_and_check( 10, 990, 3, 10, __LINE__); + + _scheduler.yield(); + _update_current_and_check( 10, 0, 5, 120, __LINE__); + + + /************************************* + ** Round #6: Destroy and re-create ** + *************************************/ + + _destroy_context(3, __LINE__); + _update_current_and_check( 30, 30, 5, 90, __LINE__); + + _scheduler.unready(_context(5)); + _update_current_and_check( 30, 60, 1, 230, __LINE__); + + _destroy_context(4, __LINE__); + _destroy_context(7, __LINE__); + _update_current_and_check( 20, 80, 1, 210, __LINE__); + + _scheduler.unready(_context(1)); + _set_context_ready_and_check(9, true, __LINE__); + _update_current_and_check( 40, 120, 9, 100, __LINE__); + + _scheduler.ready(_context(5)); + _set_context_ready_and_check(8, true, __LINE__); + _update_current_and_check( 70, 190, 5, 60, __LINE__); + + _destroy_context(8, __LINE__); + _scheduler.unready(_context(5)); + _update_current_and_check( 10, 200, 9, 30, __LINE__); + + _set_context_ready_and_check(6, true, __LINE__); + _construct_context(4, __LINE__); + _update_current_and_check( 10, 210, 6, 100, __LINE__); + + _destroy_context(5, __LINE__); + _set_context_ready_and_check(4, true, __LINE__); + _update_current_and_check( 10, 220, 4, 90, __LINE__); + _update_current_and_check(100, 310, 4, 100, __LINE__); + _update_current_and_check( 10, 320, 4, 90, __LINE__); + + _destroy_context(4, __LINE__); + _update_current_and_check(200, 410, 6, 90, __LINE__); + + _construct_context(5, __LINE__); + _scheduler.ready(_context(5)); + _update_current_and_check( 10, 420, 5, 120, __LINE__); + + _construct_context(4, __LINE__); + _scheduler.yield(); + _update_current_and_check( 10, 430, 5, 100, __LINE__); + + _set_context_ready_and_check(4, true, __LINE__); + _scheduler.yield(); + _update_current_and_check( 50, 480, 4, 90, __LINE__); + + _destroy_context(6, __LINE__); + _scheduler.yield(); + _update_current_and_check( 20, 500, 4, 100, __LINE__); + + _destroy_context(9, __LINE__); + _update_current_and_check(200, 600, 5, 100, __LINE__); + + _construct_context(7, __LINE__); + _construct_context(8, __LINE__); + _update_current_and_check(200, 700, 4, 100, __LINE__); + + _set_context_ready_and_check(1, true, __LINE__); + _set_context_ready_and_check(7, true, __LINE__); + _update_current_and_check( 10, 710, 7, 180, __LINE__); + + _set_context_ready_and_check(8, true, __LINE__); + _update_current_and_check( 40, 750, 8, 100, __LINE__); + + _destroy_context(7, __LINE__); + _update_current_and_check(200, 850, 1, 150, __LINE__); + _update_current_and_check( 50, 900, 1, 100, __LINE__); + + _scheduler.yield(); + _update_current_and_check( 60, 960, 8, 40, __LINE__); + _update_current_and_check(100, 0, 5, 120, __LINE__); + + + /********************************************** + ** Round #7: Re-configure quota, first part ** + **********************************************/ + + _scheduler.quota(_context(5), 100); + _construct_context(6, __LINE__); + _update_current_and_check( 40, 40, 5, 80, __LINE__); + + _scheduler.quota(_context(5), 70); + _scheduler.ready(_context(6)); + _update_current_and_check( 10, 50, 5, 70, __LINE__); + + _scheduler.quota(_context(5), 40); + _construct_context(9, __LINE__); + _update_current_and_check( 10, 60, 5, 40, __LINE__); + + _scheduler.quota(_context(5), 0); + _scheduler.ready(_context(9)); + _update_current_and_check( 20, 80, 8, 100, __LINE__); + + _scheduler.quota(_context(8), 120); + _update_current_and_check( 30, 110, 8, 70, __LINE__); + + _scheduler.quota(_context(9), 40); + _update_current_and_check( 10, 120, 8, 60, __LINE__); + + _scheduler.quota(_context(8), 130); + _update_current_and_check( 10, 130, 8, 50, __LINE__); + + _scheduler.quota(_context(8), 50); + _update_current_and_check( 20, 150, 8, 30, __LINE__); + + _scheduler.quota(_context(6), 60); + _update_current_and_check( 10, 160, 8, 20, __LINE__); + + _scheduler.unready(_context(8)); + _update_current_and_check( 10, 170, 1, 230, __LINE__); + + _scheduler.unready(_context(1)); + _update_current_and_check(100, 270, 4, 90, __LINE__); + _update_current_and_check(100, 360, 4, 90, __LINE__); + + _scheduler.quota(_context(1), 110); + _update_current_and_check( 10, 370, 4, 80, __LINE__); + + _scheduler.quota(_context(1), 120); + _update_current_and_check( 20, 390, 4, 60, __LINE__); + + _scheduler.quota(_context(4), 210); + _update_current_and_check( 10, 400, 4, 50, __LINE__); + + _scheduler.ready(_context(1)); + _update_current_and_check( 10, 410, 1, 110, __LINE__); + + _scheduler.quota(_context(1), 100); + _update_current_and_check( 30, 440, 1, 80, __LINE__); + + _set_context_ready_and_check(8, true, __LINE__); + _update_current_and_check( 10, 450, 8, 10, __LINE__); + + _set_context_ready_and_check(2, false, __LINE__); + _update_current_and_check( 10, 460, 1, 70, __LINE__); + + _scheduler.quota(_context(1), 20); + _update_current_and_check( 30, 490, 1, 20, __LINE__); + + _scheduler.quota(_context(1), 50); + _update_current_and_check( 10, 500, 1, 10, __LINE__); + + _scheduler.quota(_context(1), 0); + _update_current_and_check( 30, 510, 2, 170, __LINE__); + + _scheduler.quota(_context(2), 180); + _update_current_and_check( 50, 560, 2, 120, __LINE__); + + _scheduler.unready(_context(2)); + _scheduler.quota(_context(4), 80); + _update_current_and_check( 70, 630, 8, 60, __LINE__); + _update_current_and_check( 50, 680, 8, 10, __LINE__); + + _scheduler.unready(_context(8)); + _update_current_and_check( 10, 690, 4, 40, __LINE__); + + _construct_context(3, __LINE__); + _update_current_and_check( 30, 720, 4, 10, __LINE__); + + _scheduler.quota(_context(3), 210); + _scheduler.yield(); + _scheduler.unready(_context(4)); + _update_current_and_check( 20, 730, 9, 100, __LINE__); + + _scheduler.unready(_context(9)); + _set_context_ready_and_check(4, true, __LINE__); + _update_current_and_check( 60, 790, 4, 100, __LINE__); + + _set_context_ready_and_check(2, true, __LINE__); + _update_current_and_check( 40, 830, 2, 50, __LINE__); + _update_current_and_check( 60, 880, 2, 90, __LINE__); + _update_current_and_check( 10, 890, 2, 80, __LINE__); + + _scheduler.yield(); + _set_context_ready_and_check(9, true, __LINE__); + _update_current_and_check( 60, 950, 9, 40, __LINE__); + + _scheduler.unready(_context(6)); + _update_current_and_check( 20, 970, 9, 20, __LINE__); + + _scheduler.yield(); + _scheduler.ready(_context(8)); + _update_current_and_check( 10, 980, 8, 20, __LINE__); + + _scheduler.unready(_context(8)); + _scheduler.yield(); + _update_current_and_check( 10, 990, 4, 10, __LINE__); + + _scheduler.yield(); + _update_current_and_check( 20, 0, 9, 40, __LINE__); + + + /*********************************************** + ** Round #8: Re-configure quota, second part ** + ***********************************************/ + + _scheduler.ready(_context(3)); + _update_current_and_check( 30, 30, 3, 210, __LINE__); + + _scheduler.unready(_context(3)); + _update_current_and_check(110, 140, 9, 10, __LINE__); + _update_current_and_check( 40, 150, 4, 80, __LINE__); + _update_current_and_check(100, 230, 2, 180, __LINE__); + + _scheduler.quota(_context(2), 90); + _update_current_and_check( 40, 270, 2, 90, __LINE__); + + _scheduler.yield(); + _scheduler.quota(_context(8), 130); + _update_current_and_check( 40, 310, 4, 100, __LINE__); + _update_current_and_check(100, 410, 9, 100, __LINE__); + + _scheduler.quota(_context(3), 80); + _set_context_ready_and_check(3, true, __LINE__); + _update_current_and_check( 60, 470, 3, 80, __LINE__); + + _set_context_ready_and_check(8, false, __LINE__); + _scheduler.quota(_context(8), 50); + _update_current_and_check(100, 550, 8, 50, __LINE__); + _update_current_and_check( 20, 570, 8, 30, __LINE__); + + _set_context_ready_and_check(6, true, __LINE__); + _scheduler.quota(_context(6), 50); + _update_current_and_check( 10, 580, 6, 50, __LINE__); + _update_current_and_check( 70, 630, 8, 20, __LINE__); + _update_current_and_check( 40, 650, 8, 100, __LINE__); + _update_current_and_check( 40, 690, 8, 60, __LINE__); + + _destroy_context(6, __LINE__); + _update_current_and_check(200, 750, 3, 100, __LINE__); + + _destroy_context(3, __LINE__); + _update_current_and_check( 90, 840, 9, 40, __LINE__); + _update_current_and_check( 60, 880, 5, 20, __LINE__); + _update_current_and_check(120, 900, 1, 100, __LINE__); + _update_current_and_check(100, 0, 9, 40, __LINE__); + + + _env.parent().exit(0); +} + + +void Component::construct(Env &env) +{ + static Scheduler_test::Main main { env }; +} diff --git a/repos/base-hw/src/test/cpu_scheduler/target.mk b/repos/base-hw/src/test/cpu_scheduler/target.mk index 1aad543c50..c36ac734fc 100644 --- a/repos/base-hw/src/test/cpu_scheduler/target.mk +++ b/repos/base-hw/src/test/cpu_scheduler/target.mk @@ -5,9 +5,11 @@ # TARGET = test-cpu_scheduler -SRC_CC = test.cc cpu_scheduler.cc +SRC_CC = main.cc scheduler.cc INC_DIR += $(REP_DIR)/src/core $(REP_DIR)/src/include $(BASE_DIR)/src/include LIBS = base -vpath test.cc $(PRG_DIR) +REP_INC_DIR += src/core/include + +vpath main.cc $(PRG_DIR) vpath %.cc $(REP_DIR)/src/core/kernel diff --git a/repos/base-hw/src/test/cpu_scheduler/test.cc b/repos/base-hw/src/test/cpu_scheduler/test.cc deleted file mode 100644 index f26e2924ce..0000000000 --- a/repos/base-hw/src/test/cpu_scheduler/test.cc +++ /dev/null @@ -1,401 +0,0 @@ -/* - * \brief Test CPU-scheduler implementation of the kernel - * \author Martin Stein - * \date 2014-09-30 - */ - -/* - * Copyright (C) 2014-2022 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -/* Genode includes */ -#include -#include - -/* core includes */ -#include - -using namespace Genode; -using namespace Kernel; - -struct Main -{ - enum { MAX_SHARES = 10 }; - - Constructible shares[MAX_SHARES] {}; - Cpu_scheduler scheduler; - time_t current_time { 0 }; - - Cpu_share & _idle() - { - if (!shares[0].constructed()) shares[0].construct(0, 0); - return *shares[0]; - } - - Main() : scheduler(_idle(), 1000, 100) { } - - void done() - { - Genode::log("done"); - while (1) ; - } - - unsigned share_id(Cpu_share & share) - { - for (unsigned i = 0; i < MAX_SHARES; i++) - if (shares[i].constructed() && (&*shares[i] == &share)) - return i; - return ~0U; - } - - Cpu_share & share(unsigned const id) - { - return *shares[id]; - } - - void create(unsigned const id) - { - switch (id) { - case 1: shares[id].construct(2, 230); break; - case 2: shares[id].construct(0, 170); break; - case 3: shares[id].construct(3, 110); break; - case 4: shares[id].construct(1, 90); break; - case 5: shares[id].construct(3, 120); break; - case 6: shares[id].construct(3, 0); break; - case 7: shares[id].construct(2, 180); break; - case 8: shares[id].construct(2, 100); break; - case 9: shares[id].construct(2, 0); break; - default: return; - } - scheduler.insert(*shares[id]); - } - - void destroy(unsigned const id) - { - if (!id || id >= MAX_SHARES) - return; - - scheduler.remove(share(id)); - shares[id].destruct(); - } - - unsigned time() - { - return scheduler.quota() - scheduler.residual(); - } - - void update_check(unsigned const l, unsigned const c, unsigned const t, - unsigned const s, unsigned const q) - { - current_time += c; - scheduler.update(current_time); - unsigned const st = time(); - if (t != st) { - log("wrong time ", st, " in line ", l); - done(); - } - Cpu_share & hs = scheduler.head(); - unsigned const hq = scheduler.head_quota(); - if (&hs != &share(s)) { - log("wrong share ", share_id(hs), " in line ", l); - done(); - } - if (hq != q) { - log("wrong quota ", hq, " in line ", l); - done(); - } - } - - void ready_check(unsigned const l, unsigned const s, bool const x) - { - scheduler.ready(share(s)); - if (scheduler.need_to_schedule() != x) { - log("wrong check result ", scheduler.need_to_schedule(), " in line ", l); - done(); - } - } - - void test(); -}; - - - -/* - * Shortcuts for all basic operations that the test consists of - */ - -#define C(s) create(s); -#define D(s) destroy(s); -#define A(s) scheduler.ready(share(s)); -#define I(s) scheduler.unready(share(s)); -#define Y scheduler.yield(); -#define Q(s, q) scheduler.quota(share(s), q); -#define U(c, t, s, q) update_check(__LINE__, c, t, s, q); -#define O(s) ready_check(__LINE__, s, true); -#define N(s) ready_check(__LINE__, s, false); - - -/** - * Main routine - */ -void Component::construct(Genode::Env &) -{ - static Main main; - main.test(); -} - - -void Main::test() -{ - /* - * Step-by-step testing - * - * Every line in this test is structured according to the scheme - * ' U(t,c,s,q) ' where the symbols are defined as follows: - * - * ops Operations that affect the schedule but not the head of the - * scheduler (which is a buffer to remember the last scheduling - * choice). These operations are: - * - * C(s) construct the context with ID 's' and insert it - * D(s) remove the context with ID 's' and destruct it - * A(s) set the context with ID 's' active - * I(s) set the context with ID 's' inactive - * O(s) do 'A(s)' and check that this will outdate the head - * N(s) do 'A(s)' and check that this won't outdate the head - * Y annotate that the current head wants to yield - * - * U(c,t,s,q) - * First update the head and time of the scheduler according to - * the new schedule and the fact that the head consumed a - * quantum of 'c'. Then, check the consumed time 't' for the - * actual round and if the new head is the context with ID 's' - * that has a quota of 'q'. - * - * doc Documents the expected schedule for the point after the head - * update in the corresponding line. First it lists all claims - * via their ID followed by a ' (active) or a ° (inactive) and the - * corresponding quota. So 5°120 is the inactive context 5 that - * has a quota of 120 left for the current round. They are sorted - * decurrent by their priorities and the priority bands are - * separated by dashes. After the lowest priority band there is - * an additional dash followed by the current state of the round- - * robin scheduling that has no quota or priority. Only active - * contexts are listed here and only the head is listed together - * with its remaining quota. So 4'50 1 7 means that the active - * context 4 is the round-robin head with quota 50 remaining and - * that he is followed by the active contexts 1 and 7 both with a - * fresh time-slice. - * - * The order of operations is the same as in the operative kernel so each - * line can be seen as one "kernel pass". If any check in a line fails, - * the test prematurely stops and prints out where and why it has stopped. - */ - - /* first round - idle */ - U( 10, 10, 0, 100) /* - */ - U( 90, 100, 0, 100) /* - */ - U(120, 200, 0, 100) /* - */ - U(130, 300, 0, 100) /* - */ - U(140, 400, 0, 100) /* - */ - U(150, 500, 0, 100) /* - */ - U(160, 600, 0, 100) /* - */ - U(170, 700, 0, 100) /* - */ - U(180, 800, 0, 100) /* - */ - U(190, 900, 0, 100) /* - */ - U(200, 0, 0, 100) /* - */ - - /* second round - one claim, one filler */ - C(1) U(111, 100, 0, 100) /* 1°230 - */ - A(1) U(123, 200, 1, 230) /* 1'230 - 1'100 */ - I(1) U(200, 400, 0, 100) /* 1°30 - */ - A(1) U( 10, 410, 1, 30) /* 1'30 - 1'100 */ - U(100, 440, 1, 100) /* 1'0 - 1'100 */ - U(200, 540, 1, 100) /* 1'0 - 1'100 */ - I(1) U(200, 640, 0, 100) /* 1°0 - */ - U(200, 740, 0, 100) /* 1°0 - */ - A(1) U( 10, 750, 1, 100) /* 1'0 - 1'100 */ - U( 50, 800, 1, 50) /* 1'0 - 1'50 */ - U( 20, 820, 1, 30) /* 1'0 - 1'30 */ - U(100, 850, 1, 100) /* 1'0 - 1'100 */ - U(200, 950, 1, 50) /* 1'0 - 1'100 */ - U(200, 0, 1, 230) /* 1'230 - 1'100 */ - - /* third round - one claim per priority */ - C(2) A(2) U( 50, 50, 1, 180) /* 1'180 - 2'170 - 1'100 2 */ - I(1) U( 70, 120, 2, 170) /* 1°110 - 2'170 - 2'100 */ - A(1) I(2) U(110, 230, 1, 110) /* 1'110 - 2°60 - 1'100 */ - U( 90, 320, 1, 20) /* 1'20 - 2°60 - 1'100 */ - A(2) I(1) U( 10, 330, 2, 60) /* 1°10 - 2'60 - 2'100 */ - C(3) U( 40, 370, 2, 20) /* 3°110 - 1°10 - 2'10 - 2'100 */ - A(3) U( 10, 380, 3, 110) /* 3'110 - 1°10 - 2'10 - 2'100 3 */ - U(150, 490, 2, 10) /* 3'0 - 1°10 - 2'10 - 2'100 3 */ - U( 10, 500, 2, 100) /* 3'0 - 1°10 - 2'0 - 2'100 3 */ - U( 60, 560, 2, 40) /* 3'0 - 1°10 - 2'0 - 2'40 3 */ - C(4) U( 60, 600, 3, 100) /* 3'0 - 1°10 - 4°90 - 2'0 - 3'100 2 */ - C(6) A(6) U(120, 700, 2, 100) /* 3'0 - 1°10 - 4°90 - 2'0 - 2'100 6 3*/ - A(4) U( 80, 780, 4, 90) /* 3'0 - 1°10 - 4'90 - 2'0 - 2'20 6 3 4 */ - I(4) A(1) U( 50, 830, 1, 10) /* 3'0 - 1'10 - 4°40 - 2'0 - 2'20 6 3 1 */ - U( 50, 840, 2, 20) /* 3'0 - 1'0 - 4°40 - 2'0 - 2'20 6 3 1 */ - U( 50, 860, 6, 100) /* 3'0 - 1'0 - 4°40 - 2'0 - 6'100 3 1 2 */ - U(100, 960, 3, 40) /* 3'0 - 1'0 - 4°40 - 2'0 - 3'100 1 2 6 */ - U( 60, 0, 3, 110) /* 3'110 - 1'230 - 4°40 - 2'170 - 3'60 1 2 6 */ - - /* fourth round - multiple claims per priority */ - C(5) U( 60, 60, 3, 50) /* 3'50 5°120 - 1'230 - 4°90 - 2'170 - 3'60 1 2 6 */ - A(4) I(3) U( 40, 100, 1, 230) /* 3°10 5°120 - 1'230 - 4'90 - 2'170 - 1'100 2 6 4 */ - C(7) A(7) U(200, 300, 7, 180) /* 3°10 5°120 - 7'180 1'30 - 4'90 - 2'170 - 1'100 2 6 4 7 */ - C(8) A(5) U(100, 400, 5, 120) /* 5'120 3°10 - 7'80 1'30 8°100 - 4'90 - 2'170 - 1'100 2 6 4 7 5 */ - A(3) U(100, 500, 3, 10) /* 3'10 5'20 - 7'80 1'30 8°100 - 4'90 - 2'170 - 1'100 2 6 4 7 5 3 */ - U( 30, 510, 5, 20) /* 5'20 3'0 - 7'80 1'30 8°100 - 4'90 - 2'170 - 1'100 2 6 4 7 5 3 */ - C(9) A(9) U( 10, 520, 5, 10) /* 5'10 3'0 - 7'80 1'30 8°100 - 4'90 - 2'170 - 1'100 2 6 4 7 5 3 9 */ - U( 50, 530, 7, 80) /* 5'0 3'0 - 7'80 1'30 8°100 - 4'90 - 2'170 - 1'100 2 6 4 7 5 3 9 */ - A(8) I(7) U( 10, 540, 8, 100) /* 5'0 3'0 - 8'100 1'30 7°70 - 4'90 - 2'170 - 1'100 2 6 4 5 3 9 8 */ - I(8) U( 80, 620, 1, 30) /* 5'0 3'0 - 1'30 7°70 8°20 - 4'90 - 2'170 - 1'100 2 6 4 5 3 9 */ - U(200, 650, 4, 90) /* 5'0 3'0 - 1'0 7°70 8°20 - 4'90 - 2'170 - 1'100 2 6 4 5 3 9 */ - U(100, 740, 2, 170) /* 5'0 3'0 - 1'0 7°70 8°20 - 4'0 - 2'170 - 1'100 2 6 4 5 3 9 */ - A(8) A(7) U( 10, 750, 7, 70) /* 5'0 3'0 - 7'70 8'20 1'0 - 4'0 - 2'160 - 1'100 2 6 4 5 3 9 8 7 */ - I(7) I(3) U( 10, 760, 8, 20) /* 5'0 3°0 - 8'20 1'0 7°60 - 4'0 - 2'160 - 1'100 2 6 4 5 9 8 */ - I(8) U( 10, 770, 2, 160) /* 5'0 3°0 - 1'0 7°60 8°10 - 4'0 - 2'160 - 1'100 2 6 4 5 9 */ - I(2) U( 40, 810, 1, 100) /* 5'0 3°0 - 1'0 7°60 8°10 - 4'0 - 2°120 - 1'100 6 4 5 9 */ - A(3) U( 30, 840, 1, 70) /* 5'0 3'0 - 1'0 7°60 8°10 - 4'0 - 2°120 - 1'100 6 4 5 9 3 */ - U( 80, 910, 6, 90) /* 5'0 3'0 - 1'0 7°60 8°10 - 4'0 - 2°120 - 6'100 4 5 9 3 1 */ - A(7) A(8) U( 10, 920, 8, 10) /* 5'0 3'0 - 8'10 7'60 1'0 - 4'0 - 2°120 - 6'90 4 5 9 3 1 7 8 */ - U( 30, 930, 7, 60) /* 5'0 3'0 - 7'60 1'0 8'0 - 4°0 - 2°120 - 6'90 4 5 9 3 1 7 8 */ - A(2) I(7) U( 10, 940, 2, 60) /* 5'0 3'0 - 1'0 8'0 7°50 - 4'0 - 2'120 - 6'90 4 5 9 3 1 8 2 */ - I(3) I(5) U( 40, 980, 2, 20) /* 5°0 3°0 - 1'0 8'0 7°50 - 4'0 - 2'80 - 6'90 4 9 1 8 2 */ - I(9) I(4) U( 10, 990, 2, 10) /* 5°0 3°0 - 1'0 8'0 7°50 - 4°0 - 2'70 - 6'90 1 8 2 */ - U( 40, 0, 1, 230) /* 5°120 3°110 - 1'230 8'100 7°180 - 4°90 - 2'170 - 6'90 1 8 2 */ - - /* fifth round - yield, ready & check*/ - I(6) U( 30, 30, 1, 200) /* 5°120 3°110 - 1'200 8'100 7°180 - 4°90 - 2'170 - 1'100 8 2 */ - Y U( 20, 50, 8, 100) /* 5°120 3°110 - 8'100 1'0 7°180 - 4°90 - 2'170 - 1'100 8 2 */ - U(200, 150, 2, 170) /* 5°120 3°110 - 1'0 8'0 7°180 - 4°90 - 2'170 - 1'100 8 2 */ - Y U( 70, 220, 1, 100) /* 5°120 3°110 - 1'0 8'0 7°180 - 4°90 - 2'0 - 1'100 8 2 */ - I(8) Y U( 40, 260, 2, 100) /* 5°120 3°110 - 1'0 7°180 8°0 - 4°90 - 2'0 - 2'100 1 */ - I(1) U( 50, 310, 2, 50) /* 5°120 3°110 - 1°0 7°180 8°0 - 4°90 - 2'0 - 2'50 */ - U( 10, 320, 2, 40) /* 5°120 3°110 - 1°0 7°180 8°0 - 4°90 - 2'0 - 2'40 */ - N(1) U(200, 360, 1, 100) /* 5°120 3°110 - 1°0 7°180 8°0 - 4°90 - 2'0 - 1'100 2 */ - U( 10, 370, 1, 90) /* 5°120 3°110 - 1'0 7°180 8°0 - 4°90 - 2'0 - 1'90 2 */ - I(1) U( 10, 380, 2, 100) /* 5°120 3°110 - 1°0 7°180 8°0 - 4°90 - 2'0 - 2'100 */ - O(5) U( 10, 390, 5, 120) /* 5'120 3°110 - 1°0 7°180 8°0 - 4°90 - 2'0 - 2'90 5 */ - Y U( 90, 480, 2, 90) /* 5'0 3°110 - 1°0 7°180 8°0 - 4°90 - 2'0 - 2'90 5 */ - Y U( 10, 490, 5, 100) /* 5'0 3°110 - 1°0 7°180 8°0 - 4°90 - 2'0 - 5'100 2 */ - O(7) U( 10, 500, 7, 180) /* 5'0 3°110 - 7'180 1°0 8°0 - 4°90 - 2'0 - 5'90 2 7 */ - Y U( 10, 510, 5, 90) /* 5'0 3°110 - 7'0 1°0 8°0 - 4°90 - 2'0 - 5'90 2 7 */ - Y U( 10, 520, 2, 100) /* 5'0 3°110 - 7'0 1°0 8°0 - 4°90 - 2'0 - 2'100 7 5 */ - Y U( 10, 530, 7, 100) /* 5'0 3°110 - 7'0 1°0 8°0 - 4°90 - 2'0 - 7'100 5 2 */ - I(5) U( 10, 540, 7, 90) /* 5°0 3°110 - 7'0 1°0 8°0 - 4°90 - 2'0 - 7'90 2 */ - I(7) N(5) U( 10, 550, 2, 100) /* 5'0 3°110 - 7°0 1°0 8°0 - 4°90 - 2'0 - 2'100 5 */ - N(7) U(200, 650, 5, 100) /* 5'0 3°110 - 7'0 1°0 8°0 - 4°90 - 2'0 - 5'100 7 2 */ - I(5) I(7) U( 10, 660, 2, 100) /* 5°0 3°110 - 7°0 1°0 8°0 - 4°90 - 2'0 - 2'100 */ - I(2) U( 10, 670, 0, 100) /* 5°0 3°110 - 7°0 1°0 8°0 - 4°90 - 2°0 - */ - U( 10, 680, 0, 100) /* 5°0 3°110 - 7°0 1°0 8°0 - 4°90 - 2°0 - */ - U(100, 780, 0, 100) /* 5°0 3°110 - 7°0 1°0 8°0 - 4°90 - 2°0 - */ - O(9) U( 10, 790, 9, 100) /* 5°0 3°110 - 7°0 1°0 8°0 - 4°90 - 2°0 - 9'100 */ - N(6) U( 20, 810, 9, 80) /* 5°0 3°110 - 7°0 1°0 8°0 - 4°90 - 2°0 - 9'80 6 */ - N(8) U( 10, 820, 9, 70) /* 5°0 3°110 - 8'0 7°0 1°0 - 4°90 - 2°0 - 9'70 6 8 */ - Y U( 10, 830, 6, 100) /* 5°0 3°110 - 8'0 7°0 1°0 - 4°90 - 2°0 - 6'100 8 9 */ - Y U( 10, 840, 8, 100) /* 5°0 3°110 - 8'0 7°0 1°0 - 4°90 - 2°0 - 8'100 9 6 */ - N(7) Y U( 20, 860, 9, 100) /* 5°0 3°110 - 8'0 7'0 1°0 - 4°90 - 2°0 - 9'100 6 7 8 */ - I(8) I(9) U( 10, 870, 6, 100) /* 5°0 3°110 - 7'0 8°0 1°0 - 4°90 - 2°0 - 6'100 7 */ - I(6) I(7) U( 10, 880, 0, 100) /* 5°0 3°110 - 7°0 8°0 1°0 - 4°90 - 2°0 - */ - O(4) U( 20, 900, 4, 90) /* 5°0 3°110 - 7°0 8°0 1°0 - 4'90 - 2°0 - 4'100 */ - O(3) N(1) U( 10, 910, 3, 90) /* 3'110 5°0 - 1'0 7°0 8°0 - 4'80 - 2°0 - 4'100 3 1 */ - N(5) I(4) U( 10, 920, 3, 80) /* 3'100 5'0 - 1'0 7°0 8°0 - 4°80 - 2°0 - 3 1 5 */ - I(3) U( 10, 930, 1, 70) /* 5'0 3°90 - 1'0 7°0 8°0 - 4°80 - 2°0 - 1'100 5 */ - O(3) U( 10, 940, 3, 60) /* 3'90 5'0 - 1'0 7°0 8°0 - 4°80 - 2°0 - 1'90 5 3 */ - N(4) U( 10, 950, 3, 50) /* 3'80 5'0 - 1'0 7°0 8°0 - 4'80 - 2°0 - 1'90 5 3 4 */ - I(4) U( 10, 960, 3, 40) /* 3'70 5'0 - 1'0 7°0 8°0 - 4°80 - 2°0 - 1'90 5 3 */ - I(3) N(4) U( 10, 970, 4, 30) /* 5'0 3°60 - 1'0 7°0 8°0 - 4'80 - 2°0 - 1'90 5 4 */ - I(4) U( 10, 980, 1, 20) /* 5'0 3°60 - 1'0 7°0 8°0 - 4°70 - 2°0 - 1'90 5 */ - O(3) O(4) U( 10, 990, 3, 10) /* 3'60 5'0 - 1'0 7°0 8°0 - 4'70 - 2°0 - 1'80 5 3 4 */ - Y U( 10, 0, 5, 120) /* 5'120 3'110 - 1'230 7°180 8°100 - 4'90 - 2°170 - 1'80 5 3 4 */ - - /* sixth round - destroy and re-create */ - D(3) U( 30, 30, 5, 90) /* 5'90 - 1'230 7°180 8°100 - 4'90 - 2°170 - 1'80 5 4 */ - I(5) U( 30, 60, 1, 230) /* 5°60 - 1'230 7°180 8°100 - 4'90 - 2°170 - 1'80 4 */ - D(4) D(7) U( 20, 80, 1, 210) /* 5°60 - 1'210 8°100 - 2°170 - 1'80 4 */ - I(1) N(9) U( 40, 120, 9, 100) /* 5°60 - 1°170 8°100 - 2°170 - 9'100 */ - A(5) O(8) U( 70, 190, 5, 60) /* 5'60 - 1°170 8'100 - 2°170 - 9'30 5 8 */ - D(8) I(5) U( 10, 200, 9, 30) /* 5°60 - 1°170 - 2°170 - 9'30 */ - N(6) C(4) U( 10, 210, 9, 20) /* 5°60 - 1°170 - 4°90 - 2°170 - 9'20 6 */ - D(5) O(4) U( 10, 220, 4, 90) /* 1°170 - 4'90 - 2°170 - 9'10 6 4 */ - U(100, 310, 9, 10) /* 1°170 - 4'0 - 2°170 - 9'10 6 4 */ - U( 10, 320, 6, 100) /* 1°170 - 4'0 - 2°170 - 6'100 4 9 */ - D(4) U(200, 420, 9, 100) /* 1°170 - 2°170 - 9'100 6 */ - C(5) A(5) U( 10, 430, 5, 120) /* 5'120 - 1°210 - 2°170 - 9'90 6 5 */ - C(4) Y U( 10, 440, 9, 90) /* 5'0 - 1°170 - 4°90 - 2°170 - 9'90 6 5 */ - O(4) Y U( 50, 490, 4, 90) /* 5'0 - 1°170 - 4'90 - 2°170 - 6'100 5 4 9 */ - D(6) Y U( 10, 500, 5, 100) /* 5'0 - 1°170 - 4'0 - 2°170 - 5'100 4 9 */ - D(9) U(200, 600, 4, 100) /* 5'0 - 1°170 - 4'0 - 2°170 - 4'100 5 */ - C(7) C(8) U(200, 700, 5, 100) /* 5'0 - 1°170 7°180 8°100 - 4'0 - 2°170 - 5'100 4 */ - O(1) O(7) U( 10, 710, 7, 180) /* 5'0 - 7'180 1'170 8°100 - 4'0 - 2°170 - 5'90 4 1 7 */ - O(8) U( 40, 750, 8, 100) /* 5'0 - 8'100 7'140 1'170 - 4'0 - 2°170 - 5'90 4 1 7 8 */ - D(7) U(200, 850, 1, 150) /* 5'0 - 1'170 8'0 - 4'0 - 2°170 - 5'90 4 1 8 */ - U( 50, 900, 1, 100) /* 5'0 - 1'120 8'0 - 4'0 - 2°170 - 5'90 4 1 8 */ - Y U( 60, 960, 5, 40) /* 5'0 - 8'0 1'0 - 4'0 - 2°170 - 5'90 4 1 8 */ - U(100, 0, 5, 120) /* 5'120 - 8'100 1'230 - 4'90 - 2°170 - 5'50 4 1 8 */ - - /* seventh round - re-configure quota, first part */ - Q(5, 100) C(6) U( 40, 40, 5, 80) /* 5'80 - 8'100 1'230 - 4'90 - 2°170 - 5'50 4 1 8 */ - Q(5, 70) A(6) U( 10, 50, 5, 70) /* 5'70 - 8'100 1'230 - 4'90 - 2°170 - 5'50 4 1 8 6 */ - Q(5, 40) C(9) U( 10, 60, 5, 40) /* 5'40 - 8'100 1'230 - 4'90 - 2°170 - 5'50 4 1 8 6 */ - Q(5, 0) A(9) U( 20, 80, 8, 100) /* 8'100 1'230 - 4'90 - 2°170 - 5'50 4 1 8 6 9 */ - Q(8, 120) U( 30, 110, 8, 70) /* 8'70 1'230 - 4'90 - 2°170 - 5'50 4 1 8 6 9 */ - Q(9, 40) U( 10, 120, 8, 60) /* 8'60 1'230 9'0 - 4'90 - 2°170 - 5'50 4 1 8 6 9 */ - Q(8, 130) U( 10, 130, 8, 50) /* 8'50 1'230 9'0 - 4'90 - 2°170 - 5'50 4 1 8 6 9 */ - Q(8, 50) U( 20, 150, 8, 30) /* 8'30 1'230 9'0 - 4'90 - 2°170 - 5'50 4 1 8 6 9 */ - Q(6, 60) U( 10, 160, 8, 20) /* 6'0 - 8'20 1'230 9'0 - 4'90 - 2°170 - 5'50 4 1 8 6 9 */ - I(8) U( 10, 170, 1, 230) /* 6'0 - 1'230 9'0 8°10 - 4'90 - 2°170 - 5'50 4 1 6 9 */ - I(1) U(100, 270, 4, 90) /* 6'0 - 9'0 8°10 1°130 - 4'90 - 2°170 - 5'50 4 6 9 */ - U(100, 360, 5, 50) /* 6'0 - 9'0 8°10 1°130 - 4'0 - 2°170 - 5'50 4 6 9 */ - Q(1, 110) U( 10, 370, 5, 40) /* 6'0 - 9'0 8°10 1°110 - 4'0 - 2°170 - 5'40 4 6 9 */ - Q(1, 120) U( 20, 390, 5, 20) /* 6'0 - 9'0 8°10 1°110 - 4'0 - 2°170 - 5'20 4 6 9 */ - Q(4, 210) U( 10, 400, 5, 10) /* 6'0 - 9'0 8°10 1°110 - 4'0 - 2°170 - 5'10 4 6 9 */ - A(1) U( 20, 410, 1, 110) /* 6'0 - 1'110 9'0 8°10 - 4'0 - 2°170 - 4'100 6 9 1 5 */ - Q(1, 100) U( 30, 440, 1, 80) /* 6'0 - 1'80 9'0 8°10 - 4'0 - 2°170 - 4'100 6 9 1 5 */ - O(8) U( 10, 450, 8, 10) /* 6'0 - 8'10 1'70 9'0 - 4'0 - 2°170 - 4'100 6 9 1 5 8 */ - N(2) U( 10, 460, 1, 70) /* 6'0 - 1'70 9'0 8'0 - 4'0 - 2'170 - 4'100 6 9 1 5 8 2 */ - Q(1, 20) U( 30, 490, 1, 20) /* 6'0 - 1'20 9'0 8'0 - 4'0 - 2'170 - 4'100 6 9 1 5 8 2 */ - Q(1, 50) U( 10, 500, 1, 10) /* 6'0 - 1'10 9'0 8'0 - 4'0 - 2'170 - 4'100 6 9 1 5 8 2 */ - Q(1, 0) U( 30, 510, 2, 170) /* 6'0 - 9'0 8'0 - 4'0 - 2'170 - 4'100 6 9 1 5 8 2 */ - Q(2, 180) U( 50, 560, 2, 120) /* 6'0 - 9'0 8'0 - 4'0 - 2'120 - 4'100 6 9 1 5 8 2 */ - I(2) Q(4, 80) U( 70, 630, 4, 100) /* 6'0 - 9'0 8'0 - 4'0 - 2°50 - 4'100 6 9 1 5 8 */ - U( 50, 680, 4, 50) /* 6'0 - 9'0 8'0 - 4'0 - 2°50 - 4'100 6 9 1 5 8 */ - I(4) U( 10, 690, 6, 100) /* 6'0 - 9'0 8'0 - 4°0 - 2°50 - 6'100 9 1 5 8 */ - C(3) U( 30, 720, 6, 70) /* 6'0 3°110 - 9'0 8'0 - 4°0 - 2°50 - 6'70 9 1 5 8 */ - Q(3, 210) Y U( 20, 740, 9, 100) /* 6'0 3°110 - 9'0 8'0 - 4°0 - 2°50 - 9'100 1 5 8 6 */ - I(9) N(4) U( 50, 790, 1, 100) /* 6'0 3°110 - 9°0 8'0 - 4'0 - 2°50 - 1'100 5 8 6 4 */ - O(2) U(170, 890, 2, 50) /* 6'0 3°110 - 9°0 8'0 - 4'0 - 2'50 - 5'100 8 6 4 2 1 */ - Y N(9) U( 60, 940, 5, 60) /* 6'0 3°110 - 9'0 8'0 - 4'0 - 2'0 - 5'100 8 6 4 2 1 9 */ - I(6) U( 20, 960, 5, 40) /* 6°0 3°110 - 9'0 8'0 - 4'0 - 2'0 - 5'80 8 4 2 1 9 */ - Y U( 10, 970, 8, 30) /* 6°0 3°110 - 9'0 8'0 - 4'0 - 2'0 - 8'100 4 2 1 9 5 */ - I(8) Y U( 10, 980, 4, 20) /* 6°0 3°110 - 9'0 8°0 - 4'0 - 2'0 - 4'100 2 1 9 5 */ - Y U( 20, 0, 9, 40) /* 6°60 3°210 - 9'40 8°50 - 4'80 - 2'180 - 2'100 1 9 5 4 */ - - /* eighth round - re-configure quota, second part */ - A(3) U( 30, 30, 3, 210) /* 3'210 6°60 - 9'10 8°50 - 4'80 - 2'180 - 2'100 1 9 5 4 3 */ - I(3) U(110, 140, 9, 10) /* 6°60 3°100 - 9'10 8°50 - 4'80 - 2'180 - 2'100 1 9 5 4 */ - U( 40, 150, 4, 80) /* 6°60 3°100 - 9'0 8°50 - 4'80 - 2'180 - 2'100 1 9 5 4 */ - U(100, 230, 2, 180) /* 6°60 3°100 - 9'0 8°50 - 4'0 - 2'180 - 2'100 1 9 5 4 */ - Q(2, 90) U( 40, 270, 2, 90) /* 6°60 3°100 - 9'0 8°50 - 4'0 - 2'90 - 2'100 1 9 5 4 */ - Y Q(8, 130) U( 40, 310, 2, 100) /* 6°60 3°100 - 9'0 8°50 - 4'0 - 2'0 - 2'100 1 9 5 4 */ - U(100, 410, 1, 100) /* 6°60 3°100 - 9'0 8°50 - 4'0 - 2'0 - 1'100 9 5 4 2 */ - Q(3, 80) O(3) U( 60, 470, 3, 80) /* 3'80 6°60 - 9'0 8°50 - 4'0 - 2'0 - 1'40 9 5 4 2 3*/ - N(8) Q(8, 50) U(100, 550, 8, 50) /* 3'0 6°60 - 8'50 9'0 - 4'0 - 2'0 - 1'40 9 5 4 2 3 8 */ - U( 20, 570, 8, 30) /* 3'0 6°60 - 8'30 9'0 - 4'0 - 2'0 - 1'40 9 5 4 2 3 8 */ - O(6) Q(6, 50) U( 10, 580, 6, 50) /* 6'50 3'0 - 8'20 9'0 - 4'0 - 2'0 - 1'40 9 5 4 2 3 8 6 */ - U( 70, 630, 8, 20) /* 6'0 3'0 - 9'0 8'20 - 4'0 - 2'0 - 1'40 9 5 4 2 3 8 6 */ - U( 40, 650, 1, 40) /* 6'0 3'0 - 9'0 8'0 - 4'0 - 2'0 - 1'40 9 5 4 2 3 8 6 */ - U( 40, 690, 9, 100) /* 6'0 3'0 - 9'0 8'0 - 4'0 - 2'0 - 9'100 5 4 2 3 8 6 1 */ - D(6) U(200, 790, 5, 100) /* 3'0 - 9'0 8'0 - 4'0 - 2'0 - 5'100 4 2 3 8 1 9 */ - D(3) U(100, 890, 4, 100) /* 9'0 8'0 - 4'0 - 2'0 - 4'100 2 8 1 9 5 */ - U(120, 990, 2, 10) /* 9'0 8'0 - 4'0 - 2'0 - 2'100 8 1 9 5 4 */ - U( 80, 0, 9, 40) /* 9'40 8'50 - 4'80 - 2'90 - 2'90 8 1 9 5 4 */ - - done(); -} diff --git a/repos/base-hw/src/test/double_list/target.mk b/repos/base-hw/src/test/double_list/target.mk deleted file mode 100644 index 5fc7acf945..0000000000 --- a/repos/base-hw/src/test/double_list/target.mk +++ /dev/null @@ -1,12 +0,0 @@ -# -# \brief Build config for a core that tests its double-list implementation -# \author Martin Stein -# \date 2011-12-16 -# - -TARGET = test-double_list -INC_DIR = $(REP_DIR)/src/core -SRC_CC = test.cc -LIBS = base - -vpath double_list.cc $(REP_DIR)/src/core/kernel diff --git a/repos/base-hw/src/test/double_list/test.cc b/repos/base-hw/src/test/double_list/test.cc deleted file mode 100644 index ae88aeb153..0000000000 --- a/repos/base-hw/src/test/double_list/test.cc +++ /dev/null @@ -1,222 +0,0 @@ -/* - * \brief Test double-list implementation of the kernel - * \author Martin Stein - * \date 2014-09-30 - */ - -/* - * Copyright (C) 2014-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -/* base includes */ -#include -#include -#include - -/* core includes */ -#include - - -/* - * Utilities - */ - -using Genode::size_t; -using Kernel::Double_list; -using Kernel::Double_list_item; - - -struct Item_load { char volatile x = 0, y = 0, z = 0; }; - - -struct Item : Item_load, Double_list_item -{ - unsigned _id; - - Item(unsigned const id) : Double_list_item(*this), _id(id) { x = 1; y = 2; z = 3; } - - void iteration() { Genode::log(_id); } -}; - - -struct Data -{ - static constexpr unsigned nr_of_items = 9; - - Double_list list { }; - char items[nr_of_items][sizeof(Item)]; - - Data() - { - for (unsigned i = 0; i < nr_of_items; i++) { - Genode::construct_at(&items[i], i + 1); } - } -}; - - -Data * data() -{ - static Data d; - return &d; -} - - -void done() -{ - Genode::log("done"); - while (1) ; -} - - -void check(unsigned i1, unsigned l) -{ - Double_list_item * const li2 = data()->list.head(); - if (li2) { - Item * const i2 = &li2->payload(); - if (i1) { - if(i1 == i2->_id) { return; } - Genode::log("head ", i2->_id, " in line ", l); - done(); - } else { - Genode::log("non-empty ", i2->_id, " in line ", l); - done(); - } - } else if (i1) { - Genode::log("empty in line ", l); - done(); - } -} - - -void print_each() -{ - Genode::log("print each"); - data()->list.for_each([] (Item &i) { i.iteration(); }); -} - - -Item * item(unsigned const i) { - return reinterpret_cast(&data()->items[i - 1]); } - - -/* - * Shortcuts for all basic operations that the test consists of - */ - -#define C(i) check(i, __LINE__); -#define T(i) data()->list.insert_tail(item(i)); -#define H(i) data()->list.insert_head(item(i)); -#define R(i) data()->list.remove(item(i)); -#define B(i) data()->list.to_tail(item(i)); -#define P print_each(); -#define N data()->list.head_to_tail(); - - -/** - * Main routine - */ -void Component::construct(Genode::Env &) -{ - /* - * Step-by-step testing - * - * Every line in this test is structured according to the scheme - * ' C(i) ' where the symbols are defined as follows: - * - * ops Operations that affect the list structure. These are: - * - * T(i) insert the item with ID 'i' as tail - * H(i) insert the item with ID 'i' as head - * R(i) remove the item with ID 'i' - * B(i) move the item with ID 'i' to the tail - * N move the head to the tail - * P print IDs of the items in the list in their list order - * - * C(i) check if the item with ID 'i' is head - * - * doc Documents the expected list content for the point after the - * operations in the corresponding line. - * - * If any check in a line fails, the test prematurely stops and prints out - * where and why it has stopped. - */ - - C(0) /* */ - N C(0) /* */ - P C(0) /* */ - T(1) C(1) /* 1 */ - N C(1) /* 1 */ - P N C(1) /* 1 */ - B(1) C(1) /* 1 */ - N C(1) /* 1 */ - R(1) C(0) /* */ - N C(0) /* */ - N C(0) /* */ - H(2) C(2) /* 2 */ - N C(2) /* 2 */ - N C(2) /* 2 */ - T(3) C(2) /* 2 3 */ - N C(3) /* 3 2 */ - B(2) C(3) /* 3 2 */ - N C(2) /* 2 3 */ - H(4) C(4) /* 4 2 3 */ - N C(2) /* 2 3 4 */ - N C(3) /* 3 4 2 */ - N C(4) /* 4 2 3 */ - R(4) N C(3) /* 3 2 */ - N C(2) /* 2 3 */ - T(1) C(2) /* 2 3 1 */ - N C(3) /* 3 1 2 */ - N C(1) /* 1 2 3 */ - N C(2) /* 2 3 1 */ - N C(3) /* 3 1 2 */ - R(1) C(3) /* 3 2 */ - N C(2) /* 2 3 */ - N C(3) /* 3 2 */ - B(3) C(2) /* 2 3 */ - T(4) T(1) C(2) /* 2 3 4 1 */ - N N C(4) /* 4 1 2 3 */ - N C(1) /* 1 2 3 4 */ - N N C(3) /* 3 4 1 2 */ - R(2) C(3) /* 3 4 1 */ - R(3) C(4) /* 4 1 */ - N C(1) /* 1 4 */ - N N C(1) /* 1 4 */ - T(3) T(2) C(1) /* 1 4 3 2 */ - T(5) N C(4) /* 4 3 2 5 1 */ - T(7) H(6) C(6) /* 6 4 3 2 5 1 7 */ - N C(4) /* 4 3 2 5 1 7 6 */ - B(4) C(3) /* 3 2 5 1 7 6 4 */ - B(4) N N C(5) /* 5 1 7 6 4 3 2 */ - N B(7) N C(6) /* 6 4 3 2 5 7 1*/ - N N B(1) C(3) /* 3 2 5 7 6 4 1 */ - P C(3) /* 3 2 5 7 6 4 1 */ - R(4) H(4) C(4) /* 4 3 2 5 7 6 1 */ - B(7) B(6) C(4) /* 4 3 2 5 1 7 6 */ - N N N C(5) /* 5 1 7 6 4 3 2 */ - N N N C(6) /* 6 4 3 2 5 1 7 */ - N N N C(2) /* 2 5 1 7 6 4 3 */ - T(9) N N C(1) /* 1 7 6 4 3 9 2 5 */ - N N N N C(3) /* 3 9 2 5 1 7 6 4 */ - N N N N C(1) /* 1 7 6 4 3 9 2 5 */ - N N N C(4) /* 4 3 9 2 5 1 7 6 */ - N N C(9) /* 9 2 5 1 7 6 4 3 */ - H(8) P C(8) /* 8 9 2 5 1 7 6 4 3 */ - R(8) C(9) /* 9 2 5 1 7 6 4 3 */ - R(9) C(2) /* 2 5 1 7 6 4 3 */ - R(1) N N C(7) /* 7 6 4 3 2 5 */ - N R(6) N C(3) /* 3 2 5 7 4 */ - T(8) R(3) C(2) /* 2 5 7 4 8 */ - N N R(5) C(7) /* 7 4 8 2 */ - R(2) R(4) C(7) /* 7 8 */ - N C(8) /* 8 7 */ - N P C(7) /* 7 8 */ - R(7) C(8) /* 7 8 */ - R(8) C(0) /* */ - C(0) /* */ - - done(); -} diff --git a/repos/base-hw/src/timer/hw/main.cc b/repos/base-hw/src/timer/hw/main.cc new file mode 100644 index 0000000000..91e10224d2 --- /dev/null +++ b/repos/base-hw/src/timer/hw/main.cc @@ -0,0 +1,305 @@ +/* + * \brief Timer driver for the base-hw kernel + * \author Norman Feske + * \date 2024-03-11 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* Genode includes */ +#include +#include +#include +#include +#include +#include + +/* base-internal includes */ +#include + +/* base-hw includes */ +#include + +namespace Timer { + + using namespace Genode; + + struct Clock; + struct Device; + struct Alarm; + struct Root; + struct Session_component; + struct Main; + + using Alarms = Alarm_registry; +} + + +struct Timer::Clock +{ + uint64_t us; + + static constexpr uint64_t MASK = uint64_t(-1); + + uint64_t value() const { return us; } + + void print(Output &out) const { Genode::print(out, us/1000); } +}; + + +class Timer::Device : Noncopyable +{ + public: + + struct Wakeup_dispatcher : Interface + { + virtual void dispatch_device_wakeup() = 0; + }; + + struct Deadline : Clock { }; + + static constexpr Deadline infinite_deadline { uint64_t(-1) }; + + private: + + Env &_env; + + Kernel::time_t const _max_timeout_us = Kernel::timeout_max_us(); + + Wakeup_dispatcher &_dispatcher; + + Signal_handler _handler { _env.ep(), *this, &Device::_handle_timeout }; + + Signal_context_capability const _handler_cap = _handler; + + Kernel::capid_t const _sel = Kernel::capid_t(addr_t(_handler_cap.data()) & 0xffffu); + + void _handle_timeout() { _dispatcher.dispatch_device_wakeup(); } + + public: + + Device(Env &env, Wakeup_dispatcher &dispatcher) + : _env(env), _dispatcher(dispatcher) { } + + Clock now() const + { + return Clock { .us = Kernel::time() }; + } + + void update_deadline(Deadline const deadline) + { + uint64_t const now_us = now().us; + uint64_t const rel_us = (deadline.us > now_us) + ? min(_max_timeout_us, deadline.us - now_us) + : 0; + + Kernel::timeout(Kernel::timeout_t(rel_us), _sel); + } +}; + + +struct Timer::Alarm : Alarms::Element +{ + Session_component &session; + + Alarm(Alarms &alarms, Session_component &session, Clock time) + : + Alarms::Element(alarms, *this, time), session(session) + { } + + void print(Output &out) const; +}; + + +static Timer::Device::Deadline next_deadline(Timer::Alarms &alarms) +{ + using namespace Timer; + + return alarms.soonest(Clock { 0 }).convert( + [&] (Clock soonest) -> Device::Deadline { + + /* scan alarms for a cluster nearby the soonest */ + uint64_t const MAX_DELAY_US = 250; + Device::Deadline result { soonest.us }; + alarms.for_each_in_range(soonest, Clock { soonest.us + MAX_DELAY_US }, + [&] (Alarm const &alarm) { + result.us = max(result.us, alarm.time.us); }); + + return result; + }, + [&] (Alarms::None) { return Device::infinite_deadline; }); +} + + +struct Timer::Session_component : Session_object +{ + Alarms &_alarms; + Device &_device; + + Signal_context_capability _sigh { }; + + Clock const _creation_time = _device.now(); + + uint64_t _local_now_us() const { return _device.now().us - _creation_time.us; } + + struct Period { uint64_t us; }; + + Constructible _period { }; + Constructible _alarm { }; + + Session_component(Env &env, + Resources const &resources, + Label const &label, + Diag const &diag, + Alarms &alarms, + Device &device) + : + Session_object(env.ep(), resources, label, diag), + _alarms(alarms), _device(device) + { } + + /** + * Called by Device::Wakeup_dispatcher + */ + void handle_wakeup() + { + if (_sigh.valid()) + Signal_transmitter(_sigh).submit(); + + if (_period.constructed()) { + Clock const next = _alarm.constructed() + ? Clock { _alarm->time.us + _period->us } + : Clock { _device.now().us + _period->us }; + + _alarm.construct(_alarms, *this, next); + + } else /* response of 'trigger_once' */ { + _alarm.destruct(); + } + } + + /****************************** + ** Timer::Session interface ** + ******************************/ + + void trigger_once(uint64_t rel_us) override + { + _period.destruct(); + _alarm.destruct(); + + Clock const now = _device.now(); + + rel_us = max(rel_us, 250u); + _alarm.construct(_alarms, *this, Clock { now.us + rel_us }); + + _device.update_deadline(next_deadline(_alarms)); + } + + void trigger_periodic(uint64_t period_us) override + { + _period.destruct(); + _alarm.destruct(); + + if (period_us) { + period_us = max(period_us, 1000u); + _period.construct(period_us); + handle_wakeup(); + } + + _device.update_deadline(next_deadline(_alarms)); + } + + void sigh(Signal_context_capability sigh) override { _sigh = sigh; } + + uint64_t elapsed_ms() const override { return _local_now_us()/1000; } + uint64_t elapsed_us() const override { return _local_now_us(); } + + void msleep(uint64_t) override { } + void usleep(uint64_t) override { } +}; + + +struct Timer::Root : public Root_component +{ + private: + + Env &_env; + Alarms &_alarms; + Device &_device; + + protected: + + Session_component *_create_session(const char *args) override + { + return new (md_alloc()) + Session_component(_env, + session_resources_from_args(args), + session_label_from_args(args), + session_diag_from_args(args), + _alarms, _device); + } + + void _upgrade_session(Session_component *s, const char *args) override + { + s->upgrade(ram_quota_from_args(args)); + s->upgrade(cap_quota_from_args(args)); + } + + void _destroy_session(Session_component *session) override + { + Genode::destroy(md_alloc(), session); + } + + public: + + Root(Env &env, Allocator &md_alloc, Alarms &alarms, Device &device) + : + Root_component(&env.ep().rpc_ep(), &md_alloc), + _env(env), _alarms(alarms), _device(device) + { } +}; + + +void Timer::Alarm::print(Output &out) const { Genode::print(out, session.label()); } + + +struct Timer::Main : Device::Wakeup_dispatcher +{ + Env &_env; + + Device _device { _env, *this }; + + Alarms _alarms { }; + + Sliced_heap _sliced_heap { _env.ram(), _env.rm() }; + + Root _root { _env, _sliced_heap, _alarms, _device }; + + /** + * Device::Wakeup_dispatcher + */ + void dispatch_device_wakeup() override + { + Clock const now = _device.now(); + + /* handle and remove pending alarms */ + while (_alarms.with_any_in_range({ 0 }, now, [&] (Alarm &alarm) { + alarm.session.handle_wakeup(); })); + + /* schedule next wakeup */ + _device.update_deadline(next_deadline(_alarms)); + } + + Main(Genode::Env &env) : _env(env) + { + _env.parent().announce(_env.ep().manage(_root)); + } +}; + + +void Component::construct(Genode::Env &env) { static Timer::Main inst(env); } diff --git a/repos/base-hw/src/timer/hw/target.mk b/repos/base-hw/src/timer/hw/target.mk index bd3672a2d8..83bde6887b 100644 --- a/repos/base-hw/src/timer/hw/target.mk +++ b/repos/base-hw/src/timer/hw/target.mk @@ -1,7 +1,5 @@ -TARGET = hw_timer_drv -REQUIRES = hw -LIBS = syscall-hw -INC_DIR += $(PRG_DIR) -SRC_CC += time_source.cc - -include $(call select_from_repositories,src/timer/target.inc) +TARGET = hw_timer +REQUIRES = hw +LIBS = syscall-hw base +REP_INC_DIR += src/include +SRC_CC += main.cc diff --git a/repos/base-hw/src/timer/hw/time_source.cc b/repos/base-hw/src/timer/hw/time_source.cc deleted file mode 100644 index e95c2334d4..0000000000 --- a/repos/base-hw/src/timer/hw/time_source.cc +++ /dev/null @@ -1,64 +0,0 @@ -/* - * \brief Time source that uses the timeout syscalls of the HW kernel - * \author Martin Stein - * \date 2012-05-03 - */ - -/* - * Copyright (C) 2012-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -/* Genode includes */ -#include -#include -#include - -/* local includes */ -#include - -using namespace Genode; - -enum { MIN_TIMEOUT_US = 1000 }; - - -Timer::Time_source::Time_source(Env &env) -: - Signalled_time_source(env), - _max_timeout_us(Kernel::timeout_max_us()) -{ - if (_max_timeout_us < MIN_TIMEOUT_US) { - error("minimum timeout greater then maximum timeout"); - throw Genode::Exception(); - } -} - - -void Timer::Time_source::set_timeout(Microseconds duration, - Timeout_handler &handler) -{ - Kernel::timeout_t duration_us = (Kernel::timeout_t)duration.value; - if (duration_us < MIN_TIMEOUT_US) { - duration_us = MIN_TIMEOUT_US; } - - if (duration_us > _max_timeout_us) { - duration_us = (Kernel::timeout_t)_max_timeout_us; } - - _handler = &handler; - Signal_context_capability cap = _signal_handler; - Kernel::timeout(duration_us, (Kernel::capid_t)((addr_t)cap.data() & 0xffff)); -} - - -Duration Timer::Time_source::curr_time() -{ - /* - * FIXME: the `Microseconds` constructor takes a machine-word as value - * thereby limiting the possible value to something ~1.19 hours. - * must be changed when the timeout framework internally does not use - * machine-word wide microseconds values anymore. - */ - return Duration(Microseconds(Kernel::time())); -} diff --git a/repos/base-hw/src/timer/hw/time_source.h b/repos/base-hw/src/timer/hw/time_source.h deleted file mode 100644 index 514c77e855..0000000000 --- a/repos/base-hw/src/timer/hw/time_source.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * \brief Time source that uses the timeout syscalls of the HW kernel - * \author Martin Stein - * \date 2012-05-03 - */ - -/* - * Copyright (C) 2012-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _TIME_SOURCE_H_ -#define _TIME_SOURCE_H_ - -/* Genode includes */ -#include - -/* base-hw includes */ -#include - -/* local includes */ -#include - -namespace Timer { - - using Microseconds = Genode::Microseconds; - using Duration = Genode::Duration; - using Timeout_handler = Genode::Timeout_handler; - - class Time_source; -} - - -class Timer::Time_source : public Genode::Signalled_time_source -{ - private: - - Kernel::time_t const _max_timeout_us; - - public: - - Time_source(Genode::Env &env); - - - /************************* - ** Genode::Time_source ** - *************************/ - - Duration curr_time() override; - void set_timeout(Microseconds duration, Timeout_handler &handler) override; - Microseconds max_timeout() const override { - return Microseconds(_max_timeout_us); }; -}; - -#endif /* _TIME_SOURCE_H_ */ diff --git a/repos/base-linux/include/spec/arm_64/trace/timestamp.h b/repos/base-linux/include/spec/arm_64/trace/timestamp.h index 741528fb52..14a6b8a2b9 100644 --- a/repos/base-linux/include/spec/arm_64/trace/timestamp.h +++ b/repos/base-linux/include/spec/arm_64/trace/timestamp.h @@ -18,7 +18,7 @@ namespace Genode { namespace Trace { - typedef uint64_t Timestamp; + using Timestamp = uint64_t; /* * In Linux/AARCH64, the 'mrs' instruction cannot be executed in user land. diff --git a/repos/base-linux/lib/mk/base-linux.inc b/repos/base-linux/lib/mk/base-linux.inc index 55fc01c046..1428b7f343 100644 --- a/repos/base-linux/lib/mk/base-linux.inc +++ b/repos/base-linux/lib/mk/base-linux.inc @@ -5,6 +5,7 @@ include $(BASE_DIR)/lib/mk/base.inc -SRC_CC += platform_env.cc +SRC_CC += platform.cc +SRC_CC += capability_slab.cc LIBS += syscall-linux diff --git a/repos/base-linux/lib/mk/base-linux.mk b/repos/base-linux/lib/mk/base-linux.mk index abfa2aebda..b8fe14fcd0 100644 --- a/repos/base-linux/lib/mk/base-linux.mk +++ b/repos/base-linux/lib/mk/base-linux.mk @@ -11,4 +11,3 @@ SRC_CC += thread.cc thread_myself.cc thread_linux.cc SRC_CC += capability_space.cc capability_raw.cc SRC_CC += attach_stack_area.cc SRC_CC += signal_transmitter.cc signal.cc -SRC_CC += platform.cc diff --git a/repos/base-linux/recipes/api/base-linux/hash b/repos/base-linux/recipes/api/base-linux/hash index dbb7c16ebe..1be3ab1910 100644 --- a/repos/base-linux/recipes/api/base-linux/hash +++ b/repos/base-linux/recipes/api/base-linux/hash @@ -1 +1 @@ -2022-10-11 4544924c73b2ee1d8d2717672320f14732807267 +2024-08-28 1671a2b8cf81fd078dd8060c1748bf0866ffa2e0 diff --git a/repos/base-linux/recipes/src/base-linux/content.mk b/repos/base-linux/recipes/src/base-linux/content.mk index ac78f59846..c0393f0b40 100644 --- a/repos/base-linux/recipes/src/base-linux/content.mk +++ b/repos/base-linux/recipes/src/base-linux/content.mk @@ -10,6 +10,6 @@ content: mv lib/mk/spec/$$spec/ld-linux.mk lib/mk/spec/$$spec/ld.mk; done; sed -i "/TARGET/s/core-linux/core/" src/core/linux/target.mk sed -i "s/BOARD.*unknown/BOARD := linux/" lib/mk/core-linux.inc - sed -i "s/linux_timer_drv/timer/" src/timer/linux/target.mk + sed -i "s/linux_timer/timer/" src/timer/linux/target.mk rm -rf src/initramfs diff --git a/repos/base-linux/recipes/src/base-linux/hash b/repos/base-linux/recipes/src/base-linux/hash index 7f3752b7d0..1e53e310e6 100644 --- a/repos/base-linux/recipes/src/base-linux/hash +++ b/repos/base-linux/recipes/src/base-linux/hash @@ -1 +1 @@ -2022-10-11 d7e12d81f12f081bb7c00233c18f3c8ac2f00d67 +2024-08-28 cbea0285f523b6943841f460fb1dab4471cb72f5 diff --git a/repos/base-linux/run/lx_fs.run b/repos/base-linux/run/lx_fs.run index 91d0094e88..80cf14ad21 100644 --- a/repos/base-linux/run/lx_fs.run +++ b/repos/base-linux/run/lx_fs.run @@ -11,7 +11,7 @@ assert_spec linux # Build # -build { core init server/lx_fs test/libc_vfs } +build { core init lib/ld lib/libc lib/vfs server/lx_fs test/libc_vfs } create_boot_directory @@ -61,10 +61,7 @@ exec mkdir -p bin/libc_vfs # Boot modules # -build_boot_image { - core init ld.lib.so libc.lib.so vfs.lib.so lx_fs test-libc_vfs - libc_vfs -} +build_boot_image [list {*}[build_artifacts] libc_vfs] # # Execute test case diff --git a/repos/base-linux/run/lx_fs_notify.run b/repos/base-linux/run/lx_fs_notify.run index 1944d26856..ef77682b97 100644 --- a/repos/base-linux/run/lx_fs_notify.run +++ b/repos/base-linux/run/lx_fs_notify.run @@ -283,7 +283,7 @@ exec mkdir -p bin/lx_fs_notify/mnt # # Boot modules # -build_boot_image { lx_fs test-rom_log test-file_writer lx_fs_notify } +build_boot_image [list {*}[build_artifacts] lx_fs_notify] # # build the test program for Linux diff --git a/repos/base-linux/run/lx_hybrid_ctors.run b/repos/base-linux/run/lx_hybrid_ctors.run index 53465130b3..d968a0ab8e 100644 --- a/repos/base-linux/run/lx_hybrid_ctors.run +++ b/repos/base-linux/run/lx_hybrid_ctors.run @@ -5,21 +5,10 @@ # \date 2011-11-24 # -# -# Build -# - -build { - core init - test/lx_hybrid_ctors -} +build { core init lib/ld test/lx_hybrid_ctors } create_boot_directory -# -# Generate config -# - install_config { @@ -38,28 +27,10 @@ install_config { } -# -# Boot modules -# - -# generic modules -set boot_modules { - core ld.lib.so init - test-lx_hybrid_ctors -} - -build_boot_image $boot_modules - -# -# Execute test case -# +build_boot_image [build_artifacts] run_genode_until {child "test-lx_hybrid_ctors" exited with exit value 0.*\n} 10 -# -# Compare output -# - grep_output {\[init -\> test-lx_hybrid_ctors\]} compare_output_to { diff --git a/repos/base-linux/run/lx_hybrid_errno.run b/repos/base-linux/run/lx_hybrid_errno.run index d68f917f53..aaa7747169 100644 --- a/repos/base-linux/run/lx_hybrid_errno.run +++ b/repos/base-linux/run/lx_hybrid_errno.run @@ -1,21 +1,7 @@ -# -# \brief Test thread-local errno works for hybrid Linux/Genode programs -# \author Norman Feske -# \date 2011-12-05 -# - -# -# Build -# - -build { core init test/lx_hybrid_errno } +build { core init lib/ld test/lx_hybrid_errno } create_boot_directory -# -# Generate config -# - install_config { @@ -27,24 +13,13 @@ install_config { - + } -# -# Boot modules -# - -# generic modules -set boot_modules { core ld.lib.so init test-lx_hybrid_errno } - -build_boot_image $boot_modules - -# -# Execute test case -# +build_boot_image [build_artifacts] run_genode_until "--- finished thread-local errno test ---.*\n" 10 diff --git a/repos/base-linux/run/lx_hybrid_exception.run b/repos/base-linux/run/lx_hybrid_exception.run index 18bc0d228f..55f780f1e6 100644 --- a/repos/base-linux/run/lx_hybrid_exception.run +++ b/repos/base-linux/run/lx_hybrid_exception.run @@ -1,24 +1,7 @@ -# -# \brief Test if the exception mechanism works in hybrid applications -# \author Christian Prochaska -# \date 2011-11-22 -# - -# -# Build -# - -build { - core init - test/lx_hybrid_exception -} +build { core init lib/ld test/lx_hybrid_exception } create_boot_directory -# -# Generate config -# - install_config { @@ -37,21 +20,7 @@ install_config { } -# -# Boot modules -# - -# generic modules -set boot_modules { - core ld.lib.so init - test-lx_hybrid_exception -} - -build_boot_image $boot_modules - -# -# Execute test case -# +build_boot_image [build_artifacts] run_genode_until {child "test-lx_hybrid_exception" exited with exit value 0.*\n} 10 diff --git a/repos/base-linux/run/lx_hybrid_pthread_ipc.run b/repos/base-linux/run/lx_hybrid_pthread_ipc.run index 1468b210ab..881cc92629 100644 --- a/repos/base-linux/run/lx_hybrid_pthread_ipc.run +++ b/repos/base-linux/run/lx_hybrid_pthread_ipc.run @@ -1,21 +1,7 @@ -# -# \brief Test IPC from pthread created outside of Genode -# \author Norman Feske -# \date 2011-12-20 -# - -# -# Build -# - -build { core init test/lx_hybrid_pthread_ipc } +build { core init lib/ld test/lx_hybrid_pthread_ipc } create_boot_directory -# -# Generate config -# - install_config { @@ -34,17 +20,6 @@ install_config { } -# -# Boot modules -# - -# generic modules -set boot_modules { core ld.lib.so init test-lx_hybrid_pthread_ipc } - -build_boot_image $boot_modules - -# -# Execute test case -# +build_boot_image [build_artifacts] run_genode_until "--- finished pthread IPC test ---.*\n" 10 diff --git a/repos/base-linux/run/lx_rmap.inc b/repos/base-linux/run/lx_rmap.inc index 19525a0822..e0fdc6010e 100644 --- a/repos/base-linux/run/lx_rmap.inc +++ b/repos/base-linux/run/lx_rmap.inc @@ -6,24 +6,11 @@ assert_spec linux -# -# Build -# - -set build_components { core init } - -lappend_if [expr {$test_type eq "static"}] build_components test/lx_rmap/static -lappend_if [expr {$test_type eq "dynamic"}] build_components test/lx_rmap/dynamic - -build $build_components +build [list core init lib/ld [test_build_target]] create_boot_directory -# -# Config -# - -set config { +install_config { @@ -34,40 +21,17 @@ set config { - } - -append_if [expr {$test_type eq "static"}] config { - } -append_if [expr {$test_type eq "dynamic"}] config { - } -append config { + + } -install_config $config -# -# Boot modules -# +build_boot_image [build_artifacts] -set boot_modules { core ld.lib.so init } +run_genode_until "child \"[test_program_name]\" exited with exit value 0.*\n" 10 -lappend_if [expr {$test_type eq "static"}] boot_modules test-lx_rmap_static -lappend_if [expr {$test_type eq "dynamic"}] boot_modules test-lx_rmap_dynamic -lappend_if [expr {$test_type eq "dynamic"}] boot_modules ld.lib.so - -build_boot_image $boot_modules - -# -# Execute test -# - -if {$test_type eq "static"} { - run_genode_until {child "test-lx_rmap_static" exited with exit value 0.*\n} 10 -} else { - run_genode_until {child "test-lx_rmap_dynamic" exited with exit value 0.*\n} 10 -} puts "Test succeeded" # vi: set ft=tcl : diff --git a/repos/base-linux/run/lx_rmap_dynamic.run b/repos/base-linux/run/lx_rmap_dynamic.run index 2d08bd5fa1..0589d4963f 100644 --- a/repos/base-linux/run/lx_rmap_dynamic.run +++ b/repos/base-linux/run/lx_rmap_dynamic.run @@ -1,10 +1,5 @@ -# -# \brief Test for Linux-specific region map (dynamic binary) -# \author Christian Helmuth -# \date 2013-09-06 -# - -set test_type "dynamic" +proc test_build_target { } { return "test/lx_rmap/static" } +proc test_program_name { } { return "test-lx_rmap_static" } source ${genode_dir}/repos/base-linux/run/lx_rmap.inc diff --git a/repos/base-linux/run/lx_rmap_static.run b/repos/base-linux/run/lx_rmap_static.run index 4143055577..2b9ebc1315 100644 --- a/repos/base-linux/run/lx_rmap_static.run +++ b/repos/base-linux/run/lx_rmap_static.run @@ -1,10 +1,5 @@ -# -# \brief Test for Linux-specific region map (static binary) -# \author Christian Helmuth -# \date 2013-09-06 -# - -set test_type "static" +proc test_build_target { } { return "test/lx_rmap/dynamic" } +proc test_program_name { } { return "test-lx_rmap_dynamic" } source ${genode_dir}/repos/base-linux/run/lx_rmap.inc diff --git a/repos/base-linux/run/lx_uid.run b/repos/base-linux/run/lx_uid.run deleted file mode 100644 index 9e86448ea0..0000000000 --- a/repos/base-linux/run/lx_uid.run +++ /dev/null @@ -1,98 +0,0 @@ -# -# \brief Test for assigning custom UIDs and GIDs to Genode processes -# \author Norman Feske -# \date 2012-11-21 -# - -build "core init test/printf" - -assert_spec linux - -create_boot_directory - -install_config { - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -} - -# -# Copy boot modules into run directory -# -# We cannot use the predefined 'build_boot_image' function here because -# this would create mere symlinks. However, we need to enable the setuid -# and setgid capabilities for core, which won't work if core were a symlink. -# -foreach binary { core ld.lib.so init } { - exec cp -H bin/$binary [run_dir] } - -# -# Allow core to set arbitrary UIDs and GIDs -# -exec sudo setcap cap_setuid,cap_setgid=ep [run_dir]/core - -# -# Execute Genode until the point where init_sub_77 is up -# -run_genode_until {\[init -> init_77 -> init_sub_77\].*No children to start.*\n} 10 - -# -# Obtain the list of Genode user processes starting with the name 'init' -# -set ps_output [exec ps -eo uid,gid,cmd | grep Genode | grep init] - -puts "Genode user processes:\n$ps_output" - -# -# Validate output of ps -# -# We are only interested in the lines for the init instances with the -# customized UIDs and GIDs. -# -if {![regexp {55\s*66 \[Genode\] init_55_66} $ps_output] - || ![regexp {77\s*77 \[Genode\] init_77} $ps_output] - || ![regexp {77\s*77 \[Genode\] init_77 -> init_sub_77} $ps_output]} { - puts stderr "Unexpected output of ps" - exit 1 -} - -puts "Test succeeded" - diff --git a/repos/base-linux/run/region_map_mmap.run b/repos/base-linux/run/region_map_mmap.run index 4f822ee850..b9ae7782dd 100644 --- a/repos/base-linux/run/region_map_mmap.run +++ b/repos/base-linux/run/region_map_mmap.run @@ -1,4 +1,4 @@ -build "core init test/region_map_mmap timer test/signal" +build { core init lib/ld test/region_map_mmap timer test/signal } create_boot_directory @@ -6,9 +6,6 @@ install_config { - - - @@ -27,12 +24,17 @@ install_config { - + } -build_boot_image "core ld.lib.so init test-region_map_mmap timer test-signal" +build_boot_image [build_artifacts] -run_genode_until forever +run_genode_until {--- Signalling test finished ---.*\n} 30 +grep_output {\[init -\> test-region_map_mmap\] Done.} + +compare_output_to { +[init -> test-region_map_mmap] Done. +} diff --git a/repos/base-linux/src/core/core_log_out.cc b/repos/base-linux/src/core/core_log_out.cc index 0a8b1703e8..46909013fe 100644 --- a/repos/base-linux/src/core/core_log_out.cc +++ b/repos/base-linux/src/core/core_log_out.cc @@ -17,4 +17,4 @@ /* Linux syscall bindings */ #include -void Genode::Core_log::out(char const c) { lx_write(1, &c, sizeof(c)); } +void Core::Core_log::out(char const c) { lx_write(1, &c, sizeof(c)); } diff --git a/repos/base-linux/src/core/core_rpc_cap_alloc.cc b/repos/base-linux/src/core/core_rpc_cap_alloc.cc index ea3359ea54..f086920b74 100644 --- a/repos/base-linux/src/core/core_rpc_cap_alloc.cc +++ b/repos/base-linux/src/core/core_rpc_cap_alloc.cc @@ -16,10 +16,14 @@ /* base-internal includes */ #include +#include using namespace Genode; +void Genode::init_rpc_cap_alloc(Parent &) { } + + Native_capability Rpc_entrypoint::_alloc_rpc_cap(Pd_session &, Native_capability, addr_t) { diff --git a/repos/base-linux/src/core/include/core_linux_syscalls.h b/repos/base-linux/src/core/include/core_linux_syscalls.h index 1b7adb6f3f..8966cf367a 100644 --- a/repos/base-linux/src/core/include/core_linux_syscalls.h +++ b/repos/base-linux/src/core/include/core_linux_syscalls.h @@ -117,8 +117,7 @@ inline int lx_ioctl_irq(int fd, int irq) ** Process creation and destruction ** **************************************/ -inline int lx_execve(const char *filename, char *const argv[], - char *const envp[]) +inline int lx_execve(char const *filename, char const *argv[], char const *envp[]) { return (int)lx_syscall(SYS_execve, filename, argv, envp); } diff --git a/repos/base-linux/src/core/include/core_region_map.h b/repos/base-linux/src/core/include/core_region_map.h index 92946ef424..98954ef094 100644 --- a/repos/base-linux/src/core/include/core_region_map.h +++ b/repos/base-linux/src/core/include/core_region_map.h @@ -17,10 +17,13 @@ /* base-internal includes */ #include -namespace Genode { class Core_region_map; } +/* core includes */ +#include + +namespace Core { class Core_region_map; } -struct Genode::Core_region_map : Region_map_mmap +struct Core::Core_region_map : Region_map_mmap { Core_region_map(Rpc_entrypoint &) : Region_map_mmap(false) { } }; diff --git a/repos/base-linux/src/core/include/dataspace_component.h b/repos/base-linux/src/core/include/dataspace_component.h index a49e42eafc..c0a013e9f8 100644 --- a/repos/base-linux/src/core/include/dataspace_component.h +++ b/repos/base-linux/src/core/include/dataspace_component.h @@ -19,15 +19,19 @@ #ifndef _CORE__INCLUDE__DATASPACE_COMPONENT_H_ #define _CORE__INCLUDE__DATASPACE_COMPONENT_H_ +/* Genode includes */ #include -#include #include #include /* base-internal includes */ #include -namespace Genode { +/* core includes */ +#include + +namespace Core { + class Dataspace_owner; class Dataspace_component; } @@ -36,10 +40,10 @@ namespace Genode { /** * Deriving classes can own a dataspace to implement conditional behavior */ -class Genode::Dataspace_owner : Interface { }; +class Core::Dataspace_owner : Interface { }; -class Genode::Dataspace_component : public Rpc_object +class Core::Dataspace_component : public Rpc_object { private: diff --git a/repos/base-linux/src/core/include/io_mem_session_component.h b/repos/base-linux/src/core/include/io_mem_session_component.h index 5c8c2bf2f2..3445367501 100644 --- a/repos/base-linux/src/core/include/io_mem_session_component.h +++ b/repos/base-linux/src/core/include/io_mem_session_component.h @@ -22,10 +22,10 @@ /* core includes */ #include -namespace Genode { class Io_mem_session_component; } +namespace Core { class Io_mem_session_component; } -class Genode::Io_mem_session_component : public Rpc_object +class Core::Io_mem_session_component : public Rpc_object { private: diff --git a/repos/base-linux/src/core/include/irq_object.h b/repos/base-linux/src/core/include/irq_object.h index c6aac790f3..c4c5cef7e2 100644 --- a/repos/base-linux/src/core/include/irq_object.h +++ b/repos/base-linux/src/core/include/irq_object.h @@ -14,12 +14,16 @@ #ifndef _IRQ_OBJECT_H_ #define _IRQ_OBJECT_H_ +/* Genode includes */ #include -namespace Genode { class Irq_object; }; +/* core includes */ +#include + +namespace Core { class Irq_object; }; -class Genode::Irq_object : public Thread +class Core::Irq_object : public Thread { private: @@ -39,7 +43,7 @@ class Genode::Irq_object : public Thread void sigh(Signal_context_capability cap); void ack_irq(); - void start() override; + Start_result start() override; }; diff --git a/repos/base-linux/src/core/include/irq_session_component.h b/repos/base-linux/src/core/include/irq_session_component.h index cb28ef0ff4..72d319dbc8 100644 --- a/repos/base-linux/src/core/include/irq_session_component.h +++ b/repos/base-linux/src/core/include/irq_session_component.h @@ -14,17 +14,20 @@ #ifndef _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_ #define _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_ +/* Genode includes */ #include #include #include #include + +/* core includes */ #include -namespace Genode { class Irq_session_component; } +namespace Core { class Irq_session_component; } -class Genode::Irq_session_component : public Rpc_object, - private List::Element +class Core::Irq_session_component : public Rpc_object, + private List::Element { private: diff --git a/repos/base-linux/src/core/include/native_cpu_component.h b/repos/base-linux/src/core/include/native_cpu_component.h index adf2927cc5..12cc9c5192 100644 --- a/repos/base-linux/src/core/include/native_cpu_component.h +++ b/repos/base-linux/src/core/include/native_cpu_component.h @@ -19,14 +19,18 @@ /* Genode includes */ #include -namespace Genode { +/* core includes */ +#include + +namespace Core { + class Cpu_session_component; class Native_cpu_component; } -class Genode::Native_cpu_component : public Rpc_object +class Core::Native_cpu_component : public Rpc_object { private: diff --git a/repos/base-linux/src/core/include/native_pd_component.h b/repos/base-linux/src/core/include/native_pd_component.h index 654d0187e4..22a4c83427 100644 --- a/repos/base-linux/src/core/include/native_pd_component.h +++ b/repos/base-linux/src/core/include/native_pd_component.h @@ -17,15 +17,19 @@ /* Genode includes */ #include -namespace Genode { +/* core includes */ +#include + +namespace Core { + class Dataspace_component; class Pd_session_component; class Native_pd_component; } -class Genode::Native_pd_component : public Rpc_object +class Core::Native_pd_component : public Rpc_object { private: diff --git a/repos/base-linux/src/core/include/pager.h b/repos/base-linux/src/core/include/pager.h index c58d8a0bdd..e41adf9ced 100644 --- a/repos/base-linux/src/core/include/pager.h +++ b/repos/base-linux/src/core/include/pager.h @@ -20,16 +20,19 @@ #include /* for 'Thread_capability' type */ #include -/* core-local includes */ +/* core includes */ #include -namespace Genode { +namespace Core { + struct Pager_object; struct Pager_entrypoint; + + using Pager_capability = Capability; } -struct Genode::Pager_object +struct Core::Pager_object { Thread_capability _thread_cap { }; Signal_context_capability _sigh { }; @@ -47,13 +50,12 @@ struct Genode::Pager_object }; -struct Genode::Pager_entrypoint +struct Core::Pager_entrypoint { Pager_entrypoint(Rpc_cap_factory &) { } - template - auto apply(Pager_capability, FUNC f) -> decltype(f(nullptr)) { - return f(nullptr); } + auto apply(Pager_capability, auto const &fn) -> decltype(fn(nullptr)) { + return fn(nullptr); } Pager_capability manage(Pager_object &) { return Pager_capability(); } diff --git a/repos/base-linux/src/core/include/platform.h b/repos/base-linux/src/core/include/platform.h index 0cad618cf5..69a35861e1 100644 --- a/repos/base-linux/src/core/include/platform.h +++ b/repos/base-linux/src/core/include/platform.h @@ -19,7 +19,7 @@ #include #include -/* core-local includes */ +/* core includes */ #include #include #include @@ -51,7 +51,7 @@ static unsigned long ram_quota_from_env() } -class Genode::Platform : public Platform_generic +class Core::Platform : public Platform_generic { private: diff --git a/repos/base-linux/src/core/include/platform_pd.h b/repos/base-linux/src/core/include/platform_pd.h index 6e69925082..cb08d07f9e 100644 --- a/repos/base-linux/src/core/include/platform_pd.h +++ b/repos/base-linux/src/core/include/platform_pd.h @@ -14,21 +14,24 @@ #ifndef _CORE__INCLUDE__PLATFORM_PD_H_ #define _CORE__INCLUDE__PLATFORM_PD_H_ +/* Genode includes */ #include #include -namespace Genode { +/* core includes */ +#include + +namespace Core { + struct Platform_pd; struct Platform_thread; } -struct Genode::Platform_pd +struct Core::Platform_pd { Platform_pd(Allocator &, char const *) { } - bool bind_thread(Platform_thread &) { return true; } - void assign_parent(Capability) { } }; diff --git a/repos/base-linux/src/core/include/platform_thread.h b/repos/base-linux/src/core/include/platform_thread.h index 4264b1685d..c9f2f7e78d 100644 --- a/repos/base-linux/src/core/include/platform_thread.h +++ b/repos/base-linux/src/core/include/platform_thread.h @@ -17,13 +17,17 @@ /* Genode includes */ #include #include +#include #include #include /* core includes */ #include -namespace Genode { class Platform_thread; } +namespace Core { + class Platform_thread; + class Platform_pd; +} /* @@ -34,32 +38,17 @@ namespace Genode { class Platform_thread; } * turn, we find the exception handler's 'Signal_context_capability'. */ -class Genode::Platform_thread : public List::Element +class Core::Platform_thread : Noncopyable { + using Location = Affinity::Location; + using Execution_time = Trace::Execution_time; + private: - struct Registry - { - Mutex _mutex { }; - List _list { }; - - void insert(Platform_thread *thread); - void remove(Platform_thread *thread); - - /** - * Trigger exception handler for 'Platform_thread' with matching PID. - */ - void submit_exception(unsigned long pid); - }; - - /** - * Return singleton instance of 'Platform_thread::Registry' - */ - static Registry &_registry(); - unsigned long _tid = -1; unsigned long _pid = -1; - char _name[32] { }; + + String<32> const _name; /* * Dummy pager object that is solely used for storing the @@ -67,89 +56,60 @@ class Genode::Platform_thread : public List::Element */ Pager_object _pager { }; + /** + * Singleton instance of platform-thread registry used to deliver + * exceptions. + */ + static Registry &_registry(); + + Registry::Element _elem { _registry(), *this }; + public: /** * Constructor */ - Platform_thread(size_t, const char *name, unsigned priority, - Affinity::Location, addr_t); - - ~Platform_thread(); + Platform_thread(Platform_pd &, size_t, auto const &name, auto...) + : _name(name) { } /** - * Pause this thread + * Return true if thread creation succeeded */ - void pause(); + bool valid() const { return true; } + + const char *name() { return _name.string(); } /** - * Enable/disable single stepping + * Notify Genode::Signal handler about sigchld */ - void single_step(bool) { } - - /** - * Resume this thread - */ - void resume(); - - /** - * Dummy implementation of platform-thread interface - */ - Pager_object &pager() { return _pager; } - void pager(Pager_object &) { } - int start(void *, void *) { return 0; } - - Thread_state state() - { - warning("Not implemented"); - throw Cpu_thread::State_access_failed(); - } - - void state(Thread_state) - { - warning("Not implemented"); - throw Cpu_thread::State_access_failed(); - } - - const char *name() { return _name; } - - /** - * Set the executing CPU for this thread - * - * SMP is currently not directly supported on Genode/Linux - * (but indirectly by the Linux kernel). - */ - void affinity(Affinity::Location) { } - - /** - * Request the affinity of this thread - */ - Affinity::Location affinity() const { return Affinity::Location(); } + static void submit_exception(unsigned pid); /** * Register process ID and thread ID of thread */ void thread_id(int pid, int tid) { _pid = pid, _tid = tid; } - /** - * Notify Genode::Signal handler about sigchld + /* + * Part of the platform-thread interface that is not used on Linux */ - static void submit_exception(int pid) + + void pause() { }; + void single_step(bool) { } + void resume() { } + Pager_object &pager() { return _pager; } + void pager(Pager_object &) { } + void start(void *, void *) { } + void affinity(Location) { } + Location affinity() const { return { }; } + void quota(size_t) { } + void state(Thread_state) { } + Execution_time execution_time() const { return { 0, 0 }; } + unsigned long pager_object_badge() const { return 0; } + + Thread_state state() { - _registry().submit_exception(pid); + return { .state = Thread_state::State::UNAVAILABLE, .cpu = { } }; } - - /** - * Set CPU quota of the thread to 'quota' - */ - void quota(size_t const) { /* not supported*/ } - - /** - * Return execution time consumed by the thread - */ - Trace::Execution_time execution_time() const { return { 0, 0 }; } - - unsigned long pager_object_badge() const { return 0; } }; #endif /* _CORE__INCLUDE__PLATFORM_THREAD_H_ */ diff --git a/repos/base-linux/src/core/include/region_map_component.h b/repos/base-linux/src/core/include/region_map_component.h index aa0bddd726..18cc5be6ed 100644 --- a/repos/base-linux/src/core/include/region_map_component.h +++ b/repos/base-linux/src/core/include/region_map_component.h @@ -25,15 +25,16 @@ #include #include -namespace Genode { +namespace Core { + struct Rm_client; struct Rm_member; class Region_map_component; } -class Genode::Region_map_component : public Rpc_object, - private List::Element +class Core::Region_map_component : public Rpc_object, + private List::Element { private: @@ -51,15 +52,14 @@ class Genode::Region_map_component : public Rpc_object, void add_client(Rm_client &) { } void remove_client(Rm_client &) { } - Local_addr attach(Dataspace_capability, size_t, off_t, bool, - Local_addr, bool, bool) override { - return (addr_t)0; } + Attach_result attach(Dataspace_capability, Attr const &) override { + return Attach_error::REGION_CONFLICT; } - void detach(Local_addr) override { } + void detach(addr_t) override { } void fault_handler(Signal_context_capability) override { } - State state() override { return State(); } + Fault fault() override { return { }; } Dataspace_capability dataspace() override { return Dataspace_capability(); } @@ -74,7 +74,7 @@ class Genode::Region_map_component : public Rpc_object, }; -struct Genode::Rm_client : Pager_object +struct Core::Rm_client : Pager_object { Rm_client(Cpu_session_capability, Thread_capability, Region_map_component &, unsigned long, diff --git a/repos/base-linux/src/core/include/resource_path.h b/repos/base-linux/src/core/include/resource_path.h index 6e73aa77fd..caa09139bd 100644 --- a/repos/base-linux/src/core/include/resource_path.h +++ b/repos/base-linux/src/core/include/resource_path.h @@ -18,7 +18,7 @@ #include /* Genode includes */ -#include +#include /** * Return resource path for Genode @@ -27,18 +27,8 @@ */ static inline char const *resource_path() { - struct Resource_path - { - char string[32]; - - Resource_path() - { - Genode::snprintf(string, sizeof(string), "/tmp/genode-%d", lx_getuid()); - } - }; - - static Resource_path path; - return path.string; + static Genode::String<32> path("/tmp/genode-", lx_getuid()); + return path.string(); } #endif /* _CORE__INCLUDE__RESOURCE_PATH_H_ */ diff --git a/repos/base-linux/src/core/include/rpc_cap_factory.h b/repos/base-linux/src/core/include/rpc_cap_factory.h index f28c36414d..d42c364a6d 100644 --- a/repos/base-linux/src/core/include/rpc_cap_factory.h +++ b/repos/base-linux/src/core/include/rpc_cap_factory.h @@ -14,12 +14,17 @@ #ifndef _CORE__INCLUDE__RPC_CAP_FACTORY_H_ #define _CORE__INCLUDE__RPC_CAP_FACTORY_H_ +/* Genode includes */ #include #include -namespace Genode { class Rpc_cap_factory; } +/* core includes */ +#include -class Genode::Rpc_cap_factory +namespace Core { class Rpc_cap_factory; } + + +class Core::Rpc_cap_factory { private: diff --git a/repos/base-linux/src/core/include/util.h b/repos/base-linux/src/core/include/util.h index 538527b7f5..5f725add7c 100644 --- a/repos/base-linux/src/core/include/util.h +++ b/repos/base-linux/src/core/include/util.h @@ -17,4 +17,7 @@ /* base-internal includes */ #include +/* core includes */ +#include + #endif /* _CORE__INCLUDE__UTIL_H_ */ diff --git a/repos/base-linux/src/core/native_cpu_component.cc b/repos/base-linux/src/core/native_cpu_component.cc index 08910d953c..0a083e997c 100644 --- a/repos/base-linux/src/core/native_cpu_component.cc +++ b/repos/base-linux/src/core/native_cpu_component.cc @@ -11,14 +11,14 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* core-local includes */ +/* core includes */ #include #include /* base-internal includes */ #include -using namespace Genode; +using namespace Core; void Native_cpu_component::thread_id(Thread_capability thread_cap, int pid, int tid) diff --git a/repos/base-linux/src/core/native_pd_component.cc b/repos/base-linux/src/core/native_pd_component.cc index 7602552c07..5f0bdd2958 100644 --- a/repos/base-linux/src/core/native_pd_component.cc +++ b/repos/base-linux/src/core/native_pd_component.cc @@ -13,11 +13,9 @@ /* Genode includes */ #include -#include -#include #include -/* core-local includes */ +/* core includes */ #include #include @@ -28,7 +26,7 @@ /* Linux includes */ #include -using namespace Genode; +using namespace Core; /*************** @@ -43,8 +41,8 @@ struct Execve_args_and_stack struct Args { char const *filename; - char **argv; - char **envp; + char const **argv; + char const **envp; Lx_sd parent_sd; }; @@ -112,8 +110,7 @@ void Native_pd_component::_start(Dataspace_component &ds) const char *tmp_filename = "temporary_executable_elf_dataspace_file_for_execve"; /* we need 's' on stack to make it an lvalue with an lvalue member we use the pointer to */ - Linux_dataspace::Filename s = ds.fname(); - const char *filename = s.buf; + Linux_dataspace::Filename filename = ds.fname(); /* * In order to be executable via 'execve', a program must be represented as @@ -122,11 +119,11 @@ void Native_pd_component::_start(Dataspace_component &ds) * the dataspace content into a temporary file whose path is passed to * 'execve()'. */ - if (strcmp(filename, "") == 0) { + if (filename == "") { filename = tmp_filename; - int tmp_binary_fd = lx_open(filename, O_CREAT | O_EXCL | O_WRONLY, S_IRWXU); + int tmp_binary_fd = lx_open(filename.string(), O_CREAT | O_EXCL | O_WRONLY, S_IRWXU); if (tmp_binary_fd < 0) { error("Could not create file '", filename, "'"); return; /* XXX reflect error to client */ @@ -142,30 +139,24 @@ void Native_pd_component::_start(Dataspace_component &ds) } /* pass parent capability as environment variable to the child */ - enum { ENV_STR_LEN = 256 }; - static char envbuf[5][ENV_STR_LEN]; - Genode::snprintf(envbuf[1], ENV_STR_LEN, "parent_local_name=%lu", - _pd_session._parent.local_name()); - Genode::snprintf(envbuf[2], ENV_STR_LEN, "DISPLAY=%s", - get_env("DISPLAY")); - Genode::snprintf(envbuf[3], ENV_STR_LEN, "HOME=%s", - get_env("HOME")); - Genode::snprintf(envbuf[4], ENV_STR_LEN, "LD_LIBRARY_PATH=%s", - get_env("LD_LIBRARY_PATH")); - - char *env[] = { &envbuf[0][0], &envbuf[1][0], &envbuf[2][0], - &envbuf[3][0], &envbuf[4][0], 0 }; + using Env_string = String<256>; + static Env_string env_strings[] { + { "parent_local_name=", _pd_session._parent.local_name() }, + { "DISPLAY=", get_env("DISPLAY") }, + { "HOME=", get_env("HOME") }, + { "LD_LIBRARY_PATH=", get_env("LD_LIBRARY_PATH") }, + }; + char const *env[] = { env_strings[0].string(), env_strings[1].string(), + env_strings[2].string(), env_strings[3].string(), + nullptr }; /* prefix name of Linux program (helps killing some zombies) */ - char const *prefix = "[Genode] "; - char pname_buf[sizeof(_pd_session._label) + sizeof(prefix)]; - snprintf(pname_buf, sizeof(pname_buf), "%s%s", prefix, _pd_session._label.string()); - char *argv_buf[2]; - argv_buf[0] = pname_buf; - argv_buf[1] = 0; + using Pname = String; + Pname const pname("[Genode] ", _pd_session._label); + char const *argv_buf[] { pname.string(), nullptr }; _execve_args_and_stack().args = Execve_args_and_stack::Args { - .filename = filename, + .filename = filename.string(), .argv = argv_buf, .envp = env, .parent_sd = Capability_space::ipc_cap_data(_pd_session._parent).dst.socket @@ -174,8 +165,8 @@ void Native_pd_component::_start(Dataspace_component &ds) _pid = lx_create_process((int (*)())_exec_child, _execve_args_and_stack().initial_sp()); - if (strcmp(filename, tmp_filename) == 0) - lx_unlink(filename); + if (filename == tmp_filename) + lx_unlink(filename.string()); } diff --git a/repos/base-linux/src/core/platform.cc b/repos/base-linux/src/core/platform.cc index da2251bc69..12c7849a1b 100644 --- a/repos/base-linux/src/core/platform.cc +++ b/repos/base-linux/src/core/platform.cc @@ -27,7 +27,7 @@ /* Linux includes */ #include -using namespace Genode; +using namespace Core; /** @@ -69,24 +69,30 @@ class Pipe_semaphore }; -static Pipe_semaphore _wait_for_exit_sem; /* wakeup of '_wait_for_exit' */ -static bool _do_exit = false; /* exit condition */ +static Pipe_semaphore &_wait_for_exit_sem() +{ + static Pipe_semaphore inst { }; + return inst; +} + + +static bool _do_exit = false; /* exit condition */ static void sigint_handler(int) { _do_exit = true; - _wait_for_exit_sem.up(); + _wait_for_exit_sem().up(); } static void sigchld_handler(int) { - _wait_for_exit_sem.up(); + _wait_for_exit_sem().up(); } -Platform::Platform() +Core::Platform::Platform() : _core_mem_alloc(nullptr) { @@ -118,14 +124,14 @@ Platform::Platform() } -void Platform::wait_for_exit() +void Core::Platform::wait_for_exit() { for (;;) { /* * Block until a signal occurs. */ - _wait_for_exit_sem.down(); + _wait_for_exit_sem().down(); /* * Each time, the '_wait_for_exit_sem' gets unlocked, we could have @@ -154,9 +160,9 @@ void Platform::wait_for_exit() } -/**************************************************** - ** Support for Platform_env_base::Region_map_mmap ** - ****************************************************/ +/********************************* + ** Support for Region_map_mmap ** + *********************************/ size_t Region_map_mmap::_dataspace_size(Capability ds_cap) { diff --git a/repos/base-linux/src/core/platform_thread.cc b/repos/base-linux/src/core/platform_thread.cc index 219ea4d20b..6548587e35 100644 --- a/repos/base-linux/src/core/platform_thread.cc +++ b/repos/base-linux/src/core/platform_thread.cc @@ -14,89 +14,32 @@ /* Genode includes */ #include #include -#include -/* local includes */ -#include "platform_thread.h" +/* core includes */ +#include #include -using namespace Genode; +using namespace Core; -typedef Token Tid_token; - - -/******************************* - ** Platform_thread::Registry ** - *******************************/ - -void Platform_thread::Registry::insert(Platform_thread *thread) +void Platform_thread::submit_exception(unsigned pid) { - Mutex::Guard guard(_mutex); - _list.insert(thread); -} - - -void Platform_thread::Registry::remove(Platform_thread *thread) -{ - Mutex::Guard guard(_mutex); - _list.remove(thread); -} - - -void Platform_thread::Registry::submit_exception(unsigned long pid) -{ - Mutex::Guard guard(_mutex); - - /* traverse list to find 'Platform_thread' with matching PID */ - for (Platform_thread *curr = _list.first(); curr; curr = curr->next()) { - - if (curr->_tid == pid) { - Signal_context_capability sigh = curr->_pager._sigh; - - if (sigh.valid()) - Signal_transmitter(sigh).submit(); - + bool submitted = false; + _registry().for_each([&] (Platform_thread const &thread) { + if (submitted || thread._tid != pid) return; - } - } + + Signal_context_capability sigh = thread._pager._sigh; + if (sigh.valid()) + Signal_transmitter(sigh).submit(); + + submitted = true; + }); } -Platform_thread::Registry &Platform_thread::_registry() +Registry &Platform_thread::_registry() { - static Platform_thread::Registry registry; + static Registry registry { }; return registry; } - - -/********************* - ** Platform_thread ** - *********************/ - -Platform_thread::Platform_thread(size_t, const char *name, unsigned, - Affinity::Location, addr_t) -{ - copy_cstring(_name, name, min(sizeof(_name), strlen(name) + 1)); - - _registry().insert(this); -} - - -Platform_thread::~Platform_thread() -{ - _registry().remove(this); -} - - -void Platform_thread::pause() -{ - warning(__func__, "not implemented"); -} - - -void Platform_thread::resume() -{ - warning(__func__, "not implemented"); -} - diff --git a/repos/base-linux/src/core/ram_dataspace_support.cc b/repos/base-linux/src/core/ram_dataspace_support.cc index f4f3126b02..433811a9e9 100644 --- a/repos/base-linux/src/core/ram_dataspace_support.cc +++ b/repos/base-linux/src/core/ram_dataspace_support.cc @@ -14,9 +14,6 @@ /* glibc includes */ #include -/* Genode includes */ -#include - /* local includes */ #include #include @@ -28,19 +25,18 @@ #include -using namespace Genode; +using namespace Core; static int ram_ds_cnt = 0; /* counter for creating unique dataspace IDs */ void Ram_dataspace_factory::_export_ram_ds(Dataspace_component &ds) { - char fname[Linux_dataspace::FNAME_LEN]; + Linux_dataspace::Filename const fname(resource_path(), "/ds-", ram_ds_cnt++); /* create file using a unique file name in the resource path */ - snprintf(fname, sizeof(fname), "%s/ds-%d", resource_path(), ram_ds_cnt++); - lx_unlink(fname); - int const fd = lx_open(fname, O_CREAT|O_RDWR|O_TRUNC|LX_O_CLOEXEC, S_IRWXU); + lx_unlink(fname.string()); + int const fd = lx_open(fname.string(), O_CREAT|O_RDWR|O_TRUNC|LX_O_CLOEXEC, S_IRWXU); lx_ftruncate(fd, ds.size()); /* remember file descriptor in dataspace component object */ @@ -52,7 +48,7 @@ void Ram_dataspace_factory::_export_ram_ds(Dataspace_component &ds) * gone (i.e., an open file descriptor referring to the file). A process * w/o the right file descriptor won't be able to open and access the file. */ - lx_unlink(fname); + lx_unlink(fname.string()); } diff --git a/repos/base-linux/src/core/rom_session_component.cc b/repos/base-linux/src/core/rom_session_component.cc index fad600f1a3..e9f4ce0d62 100644 --- a/repos/base-linux/src/core/rom_session_component.cc +++ b/repos/base-linux/src/core/rom_session_component.cc @@ -30,7 +30,7 @@ /* local includes */ #include "rom_session_component.h" -using namespace Genode; +using namespace Core; /** diff --git a/repos/base-linux/src/core/rpc_cap_factory_linux.cc b/repos/base-linux/src/core/rpc_cap_factory_linux.cc index 09bf63fe62..84a37a8c69 100644 --- a/repos/base-linux/src/core/rpc_cap_factory_linux.cc +++ b/repos/base-linux/src/core/rpc_cap_factory_linux.cc @@ -14,7 +14,7 @@ /* core includes */ #include -using namespace Genode; +using namespace Core; Native_capability Rpc_cap_factory::alloc(Native_capability) diff --git a/repos/base-linux/src/core/spec/linux/dataspace_component.cc b/repos/base-linux/src/core/spec/linux/dataspace_component.cc index a869e4a12e..0abfb74b5e 100644 --- a/repos/base-linux/src/core/spec/linux/dataspace_component.cc +++ b/repos/base-linux/src/core/spec/linux/dataspace_component.cc @@ -21,31 +21,26 @@ /* Genode includes */ #include -#include -#include -#include #include /* local includes */ -#include "dataspace_component.h" +#include -using namespace Genode; +using namespace Core; Linux_dataspace::Filename Dataspace_component::_file_name(const char *args) { Session_label const label = label_from_args(args); - Linux_dataspace::Filename fname; - - if (label.last_element().length() > sizeof(fname.buf)) { + if (label.last_element().length() > Linux_dataspace::Filename::capacity()) { error("file name too long: ", label.last_element()); throw Service_denied(); } - copy_cstring(fname.buf, label.last_element().string(), sizeof(fname.buf)); + Linux_dataspace::Filename const fname = label.last_element(); /* only files inside the current working directory are allowed */ - for (const char *c = fname.buf; *c; ++c) + for (const char *c = fname.string(); *c; ++c) if (*c == '/') throw Service_denied(); return fname; @@ -54,8 +49,8 @@ Linux_dataspace::Filename Dataspace_component::_file_name(const char *args) size_t Dataspace_component::_file_size() { - uint64_t size = 0; - if (lx_stat_size(_fname.buf, size) < 0) + Genode::uint64_t size = 0; + if (lx_stat_size(_fname.string(), size) < 0) throw Service_denied(); return align_addr((size_t)size, 12); @@ -67,7 +62,7 @@ Dataspace_component::Dataspace_component(const char *args) _fname(_file_name(args)), _size(_file_size()), _addr(0), - _cap(_fd_to_cap(lx_open(_fname.buf, O_RDONLY | LX_O_CLOEXEC, S_IRUSR | S_IXUSR))), + _cap(_fd_to_cap(lx_open(_fname.string(), O_RDONLY | LX_O_CLOEXEC, S_IRUSR | S_IXUSR))), _writeable(false), _owner(0) { } @@ -79,5 +74,4 @@ Dataspace_component::Dataspace_component(size_t size, addr_t, addr_t phys_addr, _size(size), _addr(phys_addr), _cap(), _writeable(false), _owner(_owner) { warning("Should only be used for IOMEM and not within Linux."); - _fname.buf[0] = 0; } diff --git a/repos/base-linux/src/core/spec/linux/io_mem_session_component.cc b/repos/base-linux/src/core/spec/linux/io_mem_session_component.cc index 244ece4d86..f56f76f8ca 100644 --- a/repos/base-linux/src/core/spec/linux/io_mem_session_component.cc +++ b/repos/base-linux/src/core/spec/linux/io_mem_session_component.cc @@ -12,17 +12,16 @@ */ /* Genode includes */ -#include #include #include /* base-internal includes */ #include -/* core-local includes */ +/* core includes */ #include -using namespace Genode; +using namespace Core; size_t Io_mem_session_component::get_arg_size(const char *) diff --git a/repos/base-linux/src/core/spec/linux/io_port_session_component.cc b/repos/base-linux/src/core/spec/linux/io_port_session_component.cc index 25bc3ba57e..2be691e645 100644 --- a/repos/base-linux/src/core/spec/linux/io_port_session_component.cc +++ b/repos/base-linux/src/core/spec/linux/io_port_session_component.cc @@ -13,7 +13,7 @@ #include -using namespace Genode; +using namespace Core; Io_port_session_component::Io_port_session_component(Range_allocator &io_port_alloc, diff --git a/repos/base-linux/src/core/spec/linux/irq_session_component.cc b/repos/base-linux/src/core/spec/linux/irq_session_component.cc index 5b83f6eb72..940ad7d820 100644 --- a/repos/base-linux/src/core/spec/linux/irq_session_component.cc +++ b/repos/base-linux/src/core/spec/linux/irq_session_component.cc @@ -14,14 +14,13 @@ */ /* Genode includes */ -#include #include #include -/* core-local includes */ +/* core includes */ #include -using namespace Genode; +using namespace Core; Irq_session_component::Irq_session_component(Range_allocator &, const char *) @@ -76,9 +75,10 @@ void Irq_object::ack_irq() } -void Irq_object::start() +Thread::Start_result Irq_object::start() { warning(__func__, " not implemented"); + return Start_result::DENIED; } diff --git a/repos/base-linux/src/core/spec/linux/platform_services.cc b/repos/base-linux/src/core/spec/linux/platform_services.cc index 4d579c89d4..700f0c1248 100644 --- a/repos/base-linux/src/core/spec/linux/platform_services.cc +++ b/repos/base-linux/src/core/spec/linux/platform_services.cc @@ -19,8 +19,8 @@ #include -void Genode::platform_add_local_services(Rpc_entrypoint &, - Sliced_heap &, - Registry &, - Trace::Source_registry &) +void Core::platform_add_local_services(Rpc_entrypoint &, + Sliced_heap &, + Registry &, + Trace::Source_registry &) { } diff --git a/repos/base-linux/src/core/spec/pc/dataspace_component.cc b/repos/base-linux/src/core/spec/pc/dataspace_component.cc index 39f3645a36..7cff814cfc 100644 --- a/repos/base-linux/src/core/spec/pc/dataspace_component.cc +++ b/repos/base-linux/src/core/spec/pc/dataspace_component.cc @@ -25,39 +25,37 @@ #include #include -/* local includes */ -#include "dataspace_component.h" +/* core includes */ +#include -using namespace Genode; +using namespace Core; Linux_dataspace::Filename Dataspace_component::_file_name(const char *args) { Session_label const label = label_from_args(args); - Linux_dataspace::Filename fname; - - if (label.last_element().length() > sizeof(fname.buf)) { - Genode::error("file name too long: ", label.last_element()); + if (label.last_element().length() > Linux_dataspace::Filename::capacity()) { + error("file name too long: ", label.last_element()); throw Service_denied(); } - copy_cstring(fname.buf, label.last_element().string(), sizeof(fname.buf)); + Linux_dataspace::Filename const fname = label.last_element(); /* only files inside the current working directory are allowed */ - for (const char *c = fname.buf; *c; ++c) + for (const char *c = fname.string(); *c; ++c) if (*c == '/') throw Service_denied(); return fname; } -Genode::size_t Dataspace_component::_file_size() +size_t Dataspace_component::_file_size() { - uint64_t size = 0; - if (lx_stat_size(_fname.buf, size) < 0) + Genode::uint64_t size = 0; + if (lx_stat_size(_fname.string(), size) < 0) throw Service_denied(); - return size; + return align_addr((size_t)size, 12); } @@ -66,7 +64,7 @@ Dataspace_component::Dataspace_component(const char *args) _fname(_file_name(args)), _size(_file_size()), _addr(0), - _cap(_fd_to_cap(lx_open(_fname.buf, O_RDONLY | LX_O_CLOEXEC, S_IRUSR | S_IXUSR))), + _cap(_fd_to_cap(lx_open(_fname.string(), O_RDONLY | LX_O_CLOEXEC, S_IRUSR | S_IXUSR))), _writeable(false), _owner(0) { } @@ -76,6 +74,4 @@ Dataspace_component::Dataspace_component(size_t size, addr_t, addr_t phys_addr, Cache, bool writeable, Dataspace_owner *_owner) : _size(size), _addr(phys_addr), _cap(), _writeable(writeable), _owner(_owner) -{ - _fname.buf[0] = 0; -} +{ } diff --git a/repos/base-linux/src/core/spec/pc/io_mem_session_component.cc b/repos/base-linux/src/core/spec/pc/io_mem_session_component.cc index 3dcaeef938..1510a23d2c 100644 --- a/repos/base-linux/src/core/spec/pc/io_mem_session_component.cc +++ b/repos/base-linux/src/core/spec/pc/io_mem_session_component.cc @@ -12,15 +12,14 @@ */ /* Genode includes */ -#include #include #include #include -/* core-local includes */ +/* core includes */ #include -using namespace Genode; +using namespace Core; size_t Io_mem_session_component::get_arg_size(const char *args) diff --git a/repos/base-linux/src/core/spec/pc/io_port_session_component.cc b/repos/base-linux/src/core/spec/pc/io_port_session_component.cc index bb772b0eb5..2708941ac6 100644 --- a/repos/base-linux/src/core/spec/pc/io_port_session_component.cc +++ b/repos/base-linux/src/core/spec/pc/io_port_session_component.cc @@ -14,7 +14,7 @@ #include #include -using namespace Genode; +using namespace Core; Io_port_session_component::Io_port_session_component(Range_allocator &io_port_alloc, diff --git a/repos/base-linux/src/core/spec/pc/irq_session_component.cc b/repos/base-linux/src/core/spec/pc/irq_session_component.cc index 3f4dd7de43..192fa30731 100644 --- a/repos/base-linux/src/core/spec/pc/irq_session_component.cc +++ b/repos/base-linux/src/core/spec/pc/irq_session_component.cc @@ -13,15 +13,14 @@ */ /* Genode includes */ -#include #include -/* core-local includes */ +/* core includes */ #include #include #include -using namespace Genode; +using namespace Core; Irq_session_component::Irq_session_component(Range_allocator &, const char *args) @@ -111,10 +110,11 @@ void Irq_object::ack_irq() } -void Irq_object::start() +Thread::Start_result Irq_object::start() { - Thread::start(); + Start_result const result = Thread::start(); _sync_bootup.block(); + return result; } diff --git a/repos/base-linux/src/core/spec/pc/platform_services.cc b/repos/base-linux/src/core/spec/pc/platform_services.cc index a3334c29ee..2a9dae0ddd 100644 --- a/repos/base-linux/src/core/spec/pc/platform_services.cc +++ b/repos/base-linux/src/core/spec/pc/platform_services.cc @@ -22,10 +22,13 @@ #include #include -void Genode::platform_add_local_services(Rpc_entrypoint &, - Sliced_heap &md, - Registry ®, - Trace::Source_registry &) +using namespace Core; + + +void Core::platform_add_local_services(Rpc_entrypoint &, + Sliced_heap &md, + Registry ®, + Core::Trace::Source_registry &) { if (!lx_iopl(3)) { static Io_port_root io_port_root(*core_env().pd_session(), diff --git a/repos/base-linux/src/core/stack_area.cc b/repos/base-linux/src/core/stack_area.cc index fc43ca216a..e59fd93a0f 100644 --- a/repos/base-linux/src/core/stack_area.cc +++ b/repos/base-linux/src/core/stack_area.cc @@ -42,38 +42,35 @@ class Stack_area_region_map : public Genode::Region_map /** * Attach backing store to stack area */ - Local_addr attach(Genode::Dataspace_capability, Genode::size_t size, - Genode::off_t, bool, Local_addr local_addr, bool, - bool) override + Attach_result attach(Genode::Dataspace_capability, Attr const &attr) override { using namespace Genode; /* convert stack-area-relative to absolute virtual address */ - addr_t addr = (addr_t)local_addr + stack_area_virtual_base(); + addr_t const addr = attr.at + stack_area_virtual_base(); /* use anonymous mmap for allocating stack backing store */ int flags = MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE; int prot = PROT_READ | PROT_WRITE; - void *res = lx_mmap((void*)addr, size, prot, flags, -1, 0); + void *res = lx_mmap((void*)addr, attr.size, prot, flags, -1, 0); if ((addr_t)res != addr) - throw Region_conflict(); + return Attach_error::REGION_CONFLICT; - return local_addr; + return Range { .start = attr.at, .num_bytes = attr.size }; } - void detach(Local_addr local_addr) override + void detach(Genode::addr_t at) override { - Genode::warning("stack area detach from ", (void*)local_addr, + Genode::warning("stack area detach from ", (void*)at, " - not implemented"); } void fault_handler(Genode::Signal_context_capability) override { } - State state() override { return State(); } + Fault fault() override { return { }; } - Genode::Dataspace_capability dataspace() override { - return Genode::Dataspace_capability(); } + Genode::Dataspace_capability dataspace() override { return { }; } }; diff --git a/repos/base-linux/src/core/thread_linux.cc b/repos/base-linux/src/core/thread_linux.cc index 7887dc9a09..beb5d34882 100644 --- a/repos/base-linux/src/core/thread_linux.cc +++ b/repos/base-linux/src/core/thread_linux.cc @@ -64,8 +64,9 @@ void Thread::_init_platform_thread(size_t, Type) { } void Thread::_deinit_platform_thread() { } -void Thread::start() +Thread::Start_result Thread::start() { native_thread().tid = lx_create_thread(Thread::_thread_start, stack_top()); native_thread().pid = lx_getpid(); + return Start_result::OK; } diff --git a/repos/base-linux/src/include/base/internal/capability_space_tpl.h b/repos/base-linux/src/include/base/internal/capability_space_tpl.h index b4c8666ed4..f085d674f0 100644 --- a/repos/base-linux/src/include/base/internal/capability_space_tpl.h +++ b/repos/base-linux/src/include/base/internal/capability_space_tpl.h @@ -81,7 +81,7 @@ class Genode::Capability_space_tpl : Noncopyable { private: - typedef CAP_DATA Data; + using Data = CAP_DATA; /** * Supplement Native_capability::Data with the meta data needed to @@ -89,8 +89,7 @@ class Genode::Capability_space_tpl : Noncopyable */ struct Tree_managed_data : Data, Avl_node { - template - Tree_managed_data(ARGS... args) : Data(args...) { } + Tree_managed_data(auto &&... args) : Data(args...) { } Tree_managed_data() { } @@ -142,8 +141,7 @@ class Genode::Capability_space_tpl : Noncopyable * The arguments are passed to the constructor of the * 'Native_capability::Data' type. */ - template - Native_capability::Data &_create_capability_unsynchronized(ARGS &&... args) + Native_capability::Data &_create_capability_unsynchronized(auto &&... args) { addr_t const index = _alloc.alloc(); diff --git a/repos/base-linux/src/include/base/internal/local_parent.h b/repos/base-linux/src/include/base/internal/local_parent.h index 21d3b566b3..883a212edc 100644 --- a/repos/base-linux/src/include/base/internal/local_parent.h +++ b/repos/base-linux/src/include/base/internal/local_parent.h @@ -44,7 +44,9 @@ class Genode::Local_parent : public Expanding_parent_client { private: - Allocator &_alloc; + Region_map &_local_rm; + Allocator &_alloc; + Id_space _local_sessions_id_space { }; public: @@ -53,18 +55,18 @@ class Genode::Local_parent : public Expanding_parent_client ** Parent interface ** **********************/ - Session_capability session(Client::Id, Service_name const &, Session_args const &, - Affinity const & = Affinity()) override; + Session_result session(Client::Id, Service_name const &, Session_args const &, + Affinity const & = Affinity()) override; Close_result close(Client::Id) override; /** * Constructor * - * \param parent_cap real parent capability used to - * promote requests to non-local - * services + * \param parent_cap real parent capability used to direct requests to + * non-local services + * \param local_rm region map of local address space */ - Local_parent(Parent_capability parent_cap, Allocator &); + Local_parent(Parent_capability parent_cap, Region_map &local_rm, Allocator &); }; #endif /* _INCLUDE__BASE__INTERNAL__LOCAL_PARENT_H_ */ diff --git a/repos/base-linux/src/include/base/internal/local_rm_session.h b/repos/base-linux/src/include/base/internal/local_rm_session.h index bbfec0208a..7d6c7679cd 100644 --- a/repos/base-linux/src/include/base/internal/local_rm_session.h +++ b/repos/base-linux/src/include/base/internal/local_rm_session.h @@ -28,24 +28,36 @@ namespace Genode { struct Local_rm_session; } struct Genode::Local_rm_session : Rm_session, Local_session { - Allocator &md_alloc; + Region_map &_local_rm; + Allocator &_md_alloc; - Local_rm_session(Allocator &md_alloc, Id_space &id_space, - Parent::Client::Id id) + Local_rm_session(Region_map &local_rm, Allocator &md_alloc, + Id_space &id_space, Parent::Client::Id id) : - Local_session(id_space, id, *this), md_alloc(md_alloc) + Local_session(id_space, id, *this), + _local_rm(local_rm), _md_alloc(md_alloc) { } - Capability create(size_t size) override + Create_result create(size_t size) override { - Region_map *rm = new (md_alloc) Region_map_mmap(true, size); - return Local_capability::local_cap(rm); + try { + Region_map *rm = new (_md_alloc) Region_map_mmap(true, size); + return Local_capability::local_cap(rm); + } + catch (Out_of_ram) { return Create_error::OUT_OF_RAM; } + catch (Out_of_caps) { return Create_error::OUT_OF_CAPS; } } void destroy(Capability cap) override { - Region_map *rm = Local_capability::deref(cap); - Genode::destroy(md_alloc, rm); + Region_map *rm_ptr = Local_capability::deref(cap); + + /* detach sub region map from local address space */ + Region_map_mmap &rm = static_cast(*rm_ptr); + rm.with_attached_sub_rm_base_ptr([&] (void *base_ptr) { + _local_rm.detach(addr_t(base_ptr)); }); + + Genode::destroy(_md_alloc, &rm); } }; diff --git a/repos/base-linux/src/include/base/internal/native_thread.h b/repos/base-linux/src/include/base/internal/native_thread.h index e921e837f1..9f7740fd39 100644 --- a/repos/base-linux/src/include/base/internal/native_thread.h +++ b/repos/base-linux/src/include/base/internal/native_thread.h @@ -80,8 +80,7 @@ class Genode::Native_thread /* * Execute functor 'fn' in the context of the 'poll' method. */ - template - void _exec_control(FN const &); + void _exec_control(auto const &fn); public: diff --git a/repos/base-linux/src/include/base/internal/platform.h b/repos/base-linux/src/include/base/internal/platform.h new file mode 100644 index 0000000000..d48dfad17b --- /dev/null +++ b/repos/base-linux/src/include/base/internal/platform.h @@ -0,0 +1,67 @@ +/* + * \brief Linux-specific environment + * \author Norman Feske + * \author Christian Helmuth + * \date 2006-07-28 + */ + +/* + * Copyright (C) 2006-2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _INCLUDE__BASE__INTERNAL__PLATFORM_H_ +#define _INCLUDE__BASE__INTERNAL__PLATFORM_H_ + +/* Genode includes */ +#include + +/* base-internal includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Genode { struct Platform; } + + +struct Genode::Platform +{ + Region_map_mmap rm { false }; + + static Capability _obtain_parent_cap(); + + Local_parent parent { _obtain_parent_cap(), rm, heap }; + + Capability pd_cap = + parent.session_cap(Parent::Env::pd()).convert>( + [&] (Capability cap) { return static_cap_cast(cap); }, + [&] (Parent::Session_cap_error) { return Capability(); }); + + Capability cpu_cap = + parent.session_cap(Parent::Env::cpu()).convert>( + [&] (Capability cap) { return static_cap_cast(cap); }, + [&] (Parent::Session_cap_error) { return Capability(); }); + + Local_pd_session pd { parent, pd_cap }; + + Expanding_cpu_session_client cpu { parent, cpu_cap, Parent::Env::cpu() }; + + Heap heap { pd, rm }; + + Platform() { _attach_stack_area(); } + + /** + * Attach stack area to local address space (for non-hybrid components) + */ + void _attach_stack_area(); +}; + +#endif /* _INCLUDE__BASE__INTERNAL__PLATFORM_H_ */ diff --git a/repos/base-linux/src/include/base/internal/platform_env.h b/repos/base-linux/src/include/base/internal/platform_env.h deleted file mode 100644 index dbd2ea3dc1..0000000000 --- a/repos/base-linux/src/include/base/internal/platform_env.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * \brief Linux-specific environment - * \author Norman Feske - * \author Christian Helmuth - * \date 2006-07-28 - */ - -/* - * Copyright (C) 2006-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _INCLUDE__BASE__INTERNAL__PLATFORM_ENV_H_ -#define _INCLUDE__BASE__INTERNAL__PLATFORM_ENV_H_ - -/* Genode includes */ -#include - -/* base-internal includes */ -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Genode { - class Platform_env_base; - class Platform_env; -} - - -/** - * Common base class of the 'Platform_env' implementations for core and - * non-core processes. - */ -class Genode::Platform_env_base : public Env_deprecated -{ - private: - - Cpu_session_capability _cpu_session_cap; - Expanding_cpu_session_client _cpu_session_client; - Region_map_mmap _region_map_mmap; - Pd_session_capability _pd_session_cap; - - protected: - - /* - * The '_local_pd_session' is protected because it is needed by - * 'Platform_env' to initialize the stack area. This must not happen - * in 'Platform_env_base' because the procedure differs between - * core and non-core components. - */ - Local_pd_session _local_pd_session; - - public: - - /** - * Constructor - */ - Platform_env_base(Parent &parent, - Cpu_session_capability cpu_cap, - Pd_session_capability pd_cap) - : - _cpu_session_cap(cpu_cap), - _cpu_session_client(parent, cpu_cap, Parent::Env::cpu()), - _region_map_mmap(false), - _pd_session_cap(pd_cap), - _local_pd_session(parent, _pd_session_cap) - { } - - /** - * Constructor used by 'Core_env' - */ - Platform_env_base(Parent &parent) - : - Platform_env_base(parent, Cpu_session_capability(), Pd_session_capability()) - { } - - - /****************************** - ** Env_deprecated interface ** - ******************************/ - - Region_map *rm_session() override { return &_region_map_mmap; } - Cpu_session *cpu_session() override { return &_cpu_session_client; } - Cpu_session_capability cpu_session_cap() override { return _cpu_session_cap; } - Pd_session *pd_session() override { return &_local_pd_session; } - Pd_session_capability pd_session_cap() override { return _pd_session_cap; } -}; - - -/** - * 'Platform_env' used by all processes except for core - */ -class Genode::Platform_env : public Platform_env_base -{ - private: - - /** - * Return instance of parent interface - */ - Local_parent &_parent(); - - Heap _heap; - - /** - * Attach stack area to local address space (for non-hybrid components) - */ - void _attach_stack_area(); - - public: - - /** - * Constructor - */ - Platform_env(); - - /** - * Destructor - */ - ~Platform_env() { _parent().exit(0); } - - - /****************************** - ** Env_deprecated interface ** - ******************************/ - - Parent *parent() override { return &_parent(); } -}; - -#endif /* _INCLUDE__BASE__INTERNAL__PLATFORM_ENV_H_ */ diff --git a/repos/base-linux/src/include/base/internal/region_map_mmap.h b/repos/base-linux/src/include/base/internal/region_map_mmap.h index b723ea622f..3be5ca4a4c 100644 --- a/repos/base-linux/src/include/base/internal/region_map_mmap.h +++ b/repos/base-linux/src/include/base/internal/region_map_mmap.h @@ -19,7 +19,6 @@ #include #include #include -#include /* base-internal includes */ #include @@ -61,26 +60,35 @@ class Genode::Region_map_mmap : public Region_map, public Dataspace bool _is_attached() const { return _base > 0; } - void _add_to_rmap(Region const &); + /* + * \return true on success + */ + bool _add_to_rmap(Region const &); + + enum class Reserve_local_error { REGION_CONFLICT }; + using Reserve_local_result = Attempt; /** * Reserve VM region for sub-rm dataspace */ - addr_t _reserve_local(bool use_local_addr, - addr_t local_addr, - size_t size); + Reserve_local_result _reserve_local(bool use_local_addr, + addr_t local_addr, + size_t size); + + enum class Map_local_error { REGION_CONFLICT }; + using Map_local_result = Attempt; /** * Map dataspace into local address space */ - void *_map_local(Dataspace_capability ds, - size_t size, - addr_t offset, - bool use_local_addr, - addr_t local_addr, - bool executable, - bool overmap, - bool writeable); + Map_local_result _map_local(Dataspace_capability ds, + size_t size, + addr_t offset, + bool use_local_addr, + addr_t local_addr, + bool executable, + bool overmap, + bool writeable); /** * Determine size of dataspace @@ -106,11 +114,10 @@ class Genode::Region_map_mmap : public Region_map, public Dataspace Region_map_mmap(bool sub_rm, size_t size = ~0) : _sub_rm(sub_rm), _size(size), _base(0) { } - ~Region_map_mmap() + void with_attached_sub_rm_base_ptr(auto const &fn) { - /* detach sub RM session when destructed */ if (_sub_rm && _is_attached()) - env_deprecated()->rm_session()->detach((void *)_base); + fn((void *)_base); } @@ -118,14 +125,13 @@ class Genode::Region_map_mmap : public Region_map, public Dataspace ** Region map interface ** **************************/ - Local_addr attach(Dataspace_capability, size_t size, off_t, bool, - Local_addr, bool, bool) override; + Attach_result attach(Dataspace_capability, Attr const &) override; - void detach(Local_addr) override; + void detach(addr_t) override; void fault_handler(Signal_context_capability) override { } - State state() override { return State(); } + Fault fault() override { return { }; } /************************* diff --git a/repos/base-linux/src/include/base/internal/region_registry.h b/repos/base-linux/src/include/base/internal/region_registry.h index 80c4a3d221..495c8259c8 100644 --- a/repos/base-linux/src/include/base/internal/region_registry.h +++ b/repos/base-linux/src/include/base/internal/region_registry.h @@ -28,7 +28,7 @@ class Genode::Region private: addr_t _start { 0 }; - off_t _offset { 0 }; + addr_t _offset { 0 }; Dataspace_capability _ds { }; size_t _size { 0 }; @@ -41,7 +41,7 @@ class Genode::Region Region() { } - Region(addr_t start, off_t offset, Dataspace_capability ds, size_t size) + Region(addr_t start, addr_t offset, Dataspace_capability ds, size_t size) : _start(start), _offset(offset), _ds(ds), _size(size) { } bool used() const { return _size > 0; } diff --git a/repos/base-linux/src/include/base/internal/stack_area.h b/repos/base-linux/src/include/base/internal/stack_area.h index 767da7f143..8c405b9102 100644 --- a/repos/base-linux/src/include/base/internal/stack_area.h +++ b/repos/base-linux/src/include/base/internal/stack_area.h @@ -49,10 +49,8 @@ static inline void flush_stack_area() Genode::size_t const size = stack_area_virtual_size(); int ret; - if ((ret = lx_munmap(base, size)) < 0) { + if ((ret = lx_munmap(base, size)) < 0) error(__func__, ": failed ret=", ret); - throw Region_map::Region_conflict(); - } } @@ -61,7 +59,7 @@ static inline Genode::addr_t reserve_stack_area() using namespace Genode; using Genode::size_t; - int const flags = MAP_ANONYMOUS | MAP_PRIVATE; + int const flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED; int const prot = PROT_NONE; size_t const size = stack_area_virtual_size(); void * const addr_in = (void *)stack_area_virtual_base(); @@ -71,10 +69,8 @@ static inline Genode::addr_t reserve_stack_area() if (addr_in != addr_out) { lx_munmap((void *)addr_out, size); error(__func__, ": failed addr_in=", addr_in, " addr_out=", addr_out); - throw Region_map::Region_conflict(); } - - return (addr_t) addr_out; + return (addr_t)addr_out; } #endif /* _INCLUDE__BASE__INTERNAL__STACK_AREA_H_ */ diff --git a/repos/base-linux/src/include/linux_dataspace/linux_dataspace.h b/repos/base-linux/src/include/linux_dataspace/linux_dataspace.h index 8803c3afda..c6940f25bb 100644 --- a/repos/base-linux/src/include/linux_dataspace/linux_dataspace.h +++ b/repos/base-linux/src/include/linux_dataspace/linux_dataspace.h @@ -16,16 +16,15 @@ #include #include -#include #include +#include namespace Genode { struct Linux_dataspace; } struct Genode::Linux_dataspace : Dataspace { - enum { FNAME_LEN = 64 }; - struct Filename { char buf[FNAME_LEN]; }; + using Filename = String<64>; virtual ~Linux_dataspace() { } @@ -42,11 +41,11 @@ struct Genode::Linux_dataspace : Dataspace */ virtual Untyped_capability fd() = 0; + /********************* ** RPC declaration ** *********************/ - GENODE_RPC(Rpc_fname, Filename, fname); GENODE_RPC(Rpc_fd, Untyped_capability, fd); GENODE_RPC_INTERFACE_INHERIT(Dataspace, Rpc_fname, Rpc_fd); diff --git a/repos/base-linux/src/lib/base/attach_stack_area.cc b/repos/base-linux/src/lib/base/attach_stack_area.cc index 8f75ab9c3e..c832e39d0d 100644 --- a/repos/base-linux/src/lib/base/attach_stack_area.cc +++ b/repos/base-linux/src/lib/base/attach_stack_area.cc @@ -16,14 +16,22 @@ */ /* base-internal includes */ -#include +#include using namespace Genode; -void Platform_env::_attach_stack_area() +void Platform::_attach_stack_area() { - _local_pd_session._address_space.attach_at(_local_pd_session._stack_area.dataspace(), - stack_area_virtual_base(), - stack_area_virtual_size()); + pd._address_space.attach(pd._stack_area.dataspace(), Region_map::Attr { + .size = stack_area_virtual_size(), + .offset = { }, + .use_at = true, + .at = stack_area_virtual_base(), + .executable = { }, + .writeable = true + }); + + env_stack_area_region_map = &pd._stack_area; + env_stack_area_ram_allocator = &pd; } diff --git a/repos/base-linux/src/lib/base/child_process.cc b/repos/base-linux/src/lib/base/child_process.cc index 5f80bc68b9..fad039cdcd 100644 --- a/repos/base-linux/src/lib/base/child_process.cc +++ b/repos/base-linux/src/lib/base/child_process.cc @@ -24,68 +24,45 @@ using namespace Genode; +static Thread_capability create_thread(auto &pd, auto &cpu, auto const &name) +{ + return cpu.create_thread(pd, name, { }, { }).template convert( + [&] (Thread_capability cap) { return cap; }, + [&] (Cpu_session::Create_thread_error) { + error("failed to create thread via CPU session"); + return Thread_capability(); }); +} + + /* * Register main thread at core * * At this point in time, we do not yet know the TID and PID of the new * thread. Those information will be provided to core by the constructor of - * the 'Platform_env' of the new process. + * the 'Platform' of the new process. */ Child::Initial_thread::Initial_thread(Cpu_session &cpu, Pd_session_capability pd, Name const &name) : - _cpu(cpu), - _cap(cpu.create_thread(pd, name, Affinity::Location(), Cpu_session::Weight())) + _cpu(cpu), _cap(create_thread(pd, cpu, name)) { } Child::Initial_thread::~Initial_thread() { } -void Child::Initial_thread::start(addr_t) { } +void Child::Initial_thread::start(addr_t, Start &) { } -/* - * On Linux, the ELF loading is performed by the kernel - */ -Child::Process::Loaded_executable::Loaded_executable(Type, - Dataspace_capability, - Ram_allocator &, - Region_map &, - Region_map &, - Parent_capability) { } - - -Child::Process::Process(Type type, - Dataspace_capability ldso_ds, - Pd_session &pd, - Initial_thread_base &, - Region_map &local_rm, - Region_map &remote_rm, - Parent_capability parent_cap) -: - loaded_executable(type, ldso_ds, pd, local_rm, remote_rm, parent_cap) +Child::Start_result Child::_start_process(Dataspace_capability ldso_ds, + Pd_session &pd, + Initial_thread_base &, + Initial_thread::Start &, + Region_map &, + Region_map &, + Parent_capability) { - /* skip loading when called during fork */ - if (type == TYPE_FORKED) - return; - - /* - * If the specified executable is a dynamically linked program, we load - * the dynamic linker instead. - */ - if (!ldso_ds.valid()) { - error("attempt to start dynamic executable without dynamic linker"); - throw Missing_dynamic_linker(); - } - - pd.assign_parent(parent_cap); - - Linux_native_pd_client lx_pd(pd.native_pd()); - - lx_pd.start(ldso_ds); + Linux_native_pd_client(pd.native_pd()).start(ldso_ds); + return Start_result::OK; } - - -Child::Process::~Process() { } diff --git a/repos/base-linux/src/lib/base/ipc.cc b/repos/base-linux/src/lib/base/ipc.cc index 543b0db58a..2683db3256 100644 --- a/repos/base-linux/src/lib/base/ipc.cc +++ b/repos/base-linux/src/lib/base/ipc.cc @@ -17,7 +17,6 @@ /* Genode includes */ #include #include -#include #include #include #include @@ -111,7 +110,7 @@ namespace { private: - typedef Genode::size_t size_t; + using size_t = Genode::size_t; msghdr _msg { }; iovec _iovec { }; @@ -326,7 +325,7 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst, int const send_ret = lx_sendmsg(dst_socket, snd_msg.msg(), 0); if (send_ret < 0) { error(lx_getpid(), ":", lx_gettid(), " lx_sendmsg to sd ", dst_socket, - " failed with ", send_ret, " in lx_call()"); + " failed with ", send_ret, " in lx_call()"); sleep_forever(); } @@ -339,14 +338,19 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst, rcv_msg.accept_sockets(Message::MAX_SDS_PER_MSG); rcv_msgbuf.reset(); - int const recv_ret = lx_recvmsg(reply_channel.local, rcv_msg.msg(), 0); - /* system call got interrupted by a signal */ - if (recv_ret == -LX_EINTR) - throw Genode::Blocking_canceled(); + for (;;) { + int const recv_ret = lx_recvmsg(reply_channel.local, rcv_msg.msg(), 0); - if (recv_ret < 0) { - error(lx_getpid(), ":", lx_gettid(), " ipc_call failed to receive result (", recv_ret, ")"); + /* system call got interrupted by a signal */ + if (recv_ret == -LX_EINTR) + continue; + + if (recv_ret >= 0) + break; + + error(lx_getpid(), ":", lx_gettid(), + " ipc_call failed to receive result (", recv_ret, ")"); sleep_forever(); } diff --git a/repos/base-linux/src/lib/base/native_thread.cc b/repos/base-linux/src/lib/base/native_thread.cc index 815e0b3902..5936fd7985 100644 --- a/repos/base-linux/src/lib/base/native_thread.cc +++ b/repos/base-linux/src/lib/base/native_thread.cc @@ -195,7 +195,7 @@ Native_capability Native_thread::Epoll::alloc_rpc_cap() dst.foreign = false; - _exec_control([&] () { _add(socketpair.local); }); + _exec_control([&] { _add(socketpair.local); }); return Capability_space::import(dst, Rpc_obj_key(socketpair.local.value)); } @@ -205,5 +205,5 @@ void Native_thread::Epoll::free_rpc_cap(Native_capability cap) { int const local_socket = (int)Capability_space::ipc_cap_data(cap).rpc_obj_key.value(); - _exec_control([&] () { _remove(Lx_sd{local_socket}); }); + _exec_control([&] { _remove(Lx_sd{local_socket}); }); } diff --git a/repos/base-linux/src/lib/base/platform.cc b/repos/base-linux/src/lib/base/platform.cc index 70d15d7ff2..53b1da83b3 100644 --- a/repos/base-linux/src/lib/base/platform.cc +++ b/repos/base-linux/src/lib/base/platform.cc @@ -1,42 +1,182 @@ /* - * \brief Platform dependant hook after binary ready + * \brief Support for the Linux-specific environment + * \author Norman Feske * \author Stefan Thoeni - * \date 2019-12-13 + * \date 2008-12-12 */ /* - * Copyright (C) 2019 Genode Labs GmbH - * Copyright (C) 2019 gapfruit AG + * Copyright (C) 2008-2017 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. */ /* Genode includes */ -#include +#include +#include +#include +#include /* base-internal includes */ -#include -#include +#include +#include +#include +#include + +using namespace Genode; + + +/********************************* + ** Support for Rm_session_mmap ** + *********************************/ + +size_t Region_map_mmap::_dataspace_size(Dataspace_capability ds) +{ + if (local(ds)) + return Local_capability::deref(ds)->size(); + + return Dataspace_client(ds).size(); + +} + + +int Region_map_mmap::_dataspace_fd(Dataspace_capability ds) +{ + Untyped_capability fd_cap = Linux_dataspace_client(ds).fd(); + return lx_dup(Capability_space::ipc_cap_data(fd_cap).dst.socket.value); +} + + +bool Region_map_mmap::_dataspace_writeable(Dataspace_capability ds) +{ + return Dataspace_client(ds).writeable(); +} + + +/****************** + ** Local_parent ** + ******************/ + +Parent::Session_result Local_parent::session(Parent::Client::Id id, + Service_name const &service_name, + Session_args const &args, + Affinity const &affinity) +{ + if (strcmp(service_name.string(), Rm_session::service_name()) == 0) { + + Local_rm_session *local_rm_session = new (_alloc) + Local_rm_session(_local_rm, _alloc, _local_sessions_id_space, id); + + return local_rm_session->local_session_cap(); + } + + return Expanding_parent_client::session(id, service_name, args, affinity); +} + + +Parent::Close_result Local_parent::close(Client::Id id) +{ + /* + * Local RM sessions are present in the '_local_sessions_id_space'. If the + * apply succeeds, 'id' referred to the local session. Otherwise, we + * forward the request to the parent. + */ + return _local_sessions_id_space.apply(id, + [&] (Local_session &local_session) -> Parent::Close_result { + Capability rm = + static_cap_cast(local_session.local_session_cap()); + destroy(_alloc, Local_capability::deref(rm)); + return Parent::Close_result::DONE; + }, + [&] /* missing */ { + return Parent_client::close(id); }); +} + + +Local_parent::Local_parent(Parent_capability parent_cap, + Region_map &local_rm, Allocator &alloc) +: + Expanding_parent_client(parent_cap), _local_rm(local_rm), _alloc(alloc) +{ } + + +/************** + ** Platform ** + **************/ + +/** + * List of Unix environment variables, initialized by the startup code + */ +extern char **lx_environ; + + +/** + * Read environment variable as long value + */ +static unsigned long get_env_ulong(const char *key) +{ + for (char **curr = lx_environ; curr && *curr; curr++) { + + Arg arg = Arg_string::find_arg(*curr, key); + if (arg.valid()) + return arg.ulong_value(0); + } + + return 0; +} + + +Capability Platform::_obtain_parent_cap() +{ + long const local_name = get_env_ulong("parent_local_name"); + + Untyped_capability parent_cap = + Capability_space::import(Rpc_destination(Lx_sd{PARENT_SOCKET_HANDLE}), + Rpc_obj_key(local_name)); + + return reinterpret_cap_cast(parent_cap); +} + + +void Genode::init_parent_resource_requests(Genode::Env & env) +{ + using Parent = Expanding_parent_client; + static_cast(&env.parent())->init_fallback_signal_handling(); +} + + +Platform &Genode::init_platform() +{ + static Genode::Platform platform; + + init_log(platform.parent); + init_rpc_cap_alloc(platform.parent); + init_cap_slab(platform.pd, platform.parent); + init_thread(platform.cpu, platform.rm); + init_thread_start(platform.pd.rpc_cap()); + init_thread_bootstrap(platform.cpu, platform.parent.main_thread_cap()); + init_exception_handling(platform.pd, platform.rm); + init_signal_receiver(platform.pd, platform.parent); + + return platform; +} + + +/************************* + ** Support for seccomp ** + *************************/ + +/* Linux includes */ #include #include /* prctl */ #include /* seccomp's constants */ -using namespace Genode; extern char _binary_seccomp_bpf_policy_bin_start[]; extern char _binary_seccomp_bpf_policy_bin_end[]; -namespace Genode { - - struct Bpf_program - { - uint16_t blk_cnt; - uint64_t *blks; - }; -} - void Genode::binary_ready_hook_for_platform() { if (lx_prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0) { @@ -44,8 +184,18 @@ void Genode::binary_ready_hook_for_platform() throw Exception(); } + struct Bpf_program + { + uint16_t blk_cnt; + uint64_t *blks; + }; + + size_t _binary_seccomp_bpf_policy_bin_size = + _binary_seccomp_bpf_policy_bin_end - _binary_seccomp_bpf_policy_bin_start; + for (char* i = _binary_seccomp_bpf_policy_bin_start; - i < _binary_seccomp_bpf_policy_bin_end - sizeof(uint32_t); i++) { + i < &_binary_seccomp_bpf_policy_bin_start[_binary_seccomp_bpf_policy_bin_size - + sizeof(uint32_t)]; i++) { uint32_t *v = reinterpret_cast(i); if (*v == 0xCAFEAFFE) { @@ -54,9 +204,8 @@ void Genode::binary_ready_hook_for_platform() } Bpf_program program { - .blk_cnt = (uint16_t)((_binary_seccomp_bpf_policy_bin_end - - _binary_seccomp_bpf_policy_bin_start) / - sizeof(uint64_t)), + .blk_cnt = (uint16_t)(_binary_seccomp_bpf_policy_bin_size / + sizeof(uint64_t)), .blks = (uint64_t *)_binary_seccomp_bpf_policy_bin_start }; @@ -67,4 +216,3 @@ void Genode::binary_ready_hook_for_platform() throw Exception(); } } - diff --git a/repos/base-linux/src/lib/base/platform_env.cc b/repos/base-linux/src/lib/base/platform_env.cc deleted file mode 100644 index 7e8a8d03e2..0000000000 --- a/repos/base-linux/src/lib/base/platform_env.cc +++ /dev/null @@ -1,171 +0,0 @@ -/* - * \brief Support for the Linux-specific environment - * \author Norman Feske - * \date 2008-12-12 - */ - -/* - * Copyright (C) 2008-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -/* Genode includes */ -#include -#include -#include -#include - -/* base-internal includes */ -#include -#include -#include -#include -#include - -using namespace Genode; - - -/**************************************************** - ** Support for Platform_env_base::Rm_session_mmap ** - ****************************************************/ - -size_t Region_map_mmap::_dataspace_size(Dataspace_capability ds) -{ - if (local(ds)) - return Local_capability::deref(ds)->size(); - - return Dataspace_client(ds).size(); - -} - - -int Region_map_mmap::_dataspace_fd(Dataspace_capability ds) -{ - Untyped_capability fd_cap = Linux_dataspace_client(ds).fd(); - return lx_dup(Capability_space::ipc_cap_data(fd_cap).dst.socket.value); -} - - -bool Region_map_mmap::_dataspace_writeable(Dataspace_capability ds) -{ - return Dataspace_client(ds).writeable(); -} - - - -/****************** - ** Local_parent ** - ******************/ - -Session_capability Local_parent::session(Parent::Client::Id id, - Service_name const &service_name, - Session_args const &args, - Affinity const &affinity) -{ - if (strcmp(service_name.string(), Rm_session::service_name()) == 0) { - - Local_rm_session *local_rm_session = new (_alloc) - Local_rm_session(_alloc, _local_sessions_id_space, id); - - return local_rm_session->local_session_cap(); - } - - return Expanding_parent_client::session(id, service_name, args, affinity); -} - - -Parent::Close_result Local_parent::close(Client::Id id) -{ - auto close_local_fn = [&] (Local_session &local_session) - { - Capability rm = - static_cap_cast(local_session.local_session_cap()); - destroy(_alloc, Local_capability::deref(rm)); - }; - - /* - * Local RM sessions are present in the '_local_sessions_id_space'. If the - * apply succeeds, 'id' referred to the local session. Otherwise, we - * forward the request to the parent. - */ - try { - _local_sessions_id_space.apply(id, close_local_fn); - return CLOSE_DONE; - } - catch (Id_space::Unknown_id) { } - - return Parent_client::close(id); -} - - -Local_parent::Local_parent(Parent_capability parent_cap, - Allocator &alloc) -: - Expanding_parent_client(parent_cap), _alloc(alloc) -{ } - - -/****************** - ** Platform_env ** - ******************/ - -/** - * List of Unix environment variables, initialized by the startup code - */ -extern char **lx_environ; - - -/** - * Read environment variable as long value - */ -static unsigned long get_env_ulong(const char *key) -{ - for (char **curr = lx_environ; curr && *curr; curr++) { - - Arg arg = Arg_string::find_arg(*curr, key); - if (arg.valid()) - return arg.ulong_value(0); - } - - return 0; -} - - -static Parent_capability obtain_parent_cap() -{ - long const local_name = get_env_ulong("parent_local_name"); - - Untyped_capability parent_cap = - Capability_space::import(Rpc_destination(Lx_sd{PARENT_SOCKET_HANDLE}), - Rpc_obj_key(local_name)); - - return reinterpret_cap_cast(parent_cap); -} - - -Local_parent &Platform_env::_parent() -{ - static Local_parent local_parent(obtain_parent_cap(), _heap); - return local_parent; -} - - -Platform_env::Platform_env() -: - Platform_env_base(_parent(), - static_cap_cast(_parent().session_cap(Parent::Env::cpu())), - static_cap_cast (_parent().session_cap(Parent::Env::pd()))), - _heap(Platform_env_base::pd_session(), Platform_env_base::rm_session()) -{ - _attach_stack_area(); - - env_stack_area_region_map = &_local_pd_session._stack_area; - env_stack_area_ram_allocator = Platform_env_base::pd_session(); - - /* register TID and PID of the main thread at core */ - Linux_native_cpu_client native_cpu(cpu_session()->native_cpu()); - native_cpu.thread_id(parent()->main_thread_cap(), lx_getpid(), lx_gettid()); -} - diff --git a/repos/base-linux/src/lib/base/region_map_client.cc b/repos/base-linux/src/lib/base/region_map_client.cc index 2874c970d4..209e2b04a4 100644 --- a/repos/base-linux/src/lib/base/region_map_client.cc +++ b/repos/base-linux/src/lib/base/region_map_client.cc @@ -40,19 +40,14 @@ Region_map_client::Region_map_client(Capability session) : Rpc_client(session) { } -Region_map::Local_addr -Region_map_client::attach(Dataspace_capability ds, size_t size, - off_t offset, bool use_local_addr, - Region_map::Local_addr local_addr, - bool executable, bool writeable) +Region_map::Attach_result +Region_map_client::attach(Dataspace_capability ds, Attr const &attr) { - return _local(rpc_cap())->attach(ds, size, offset, use_local_addr, - local_addr, executable, writeable); + return _local(rpc_cap())->attach(ds, attr); } -void Region_map_client::detach(Local_addr local_addr) { - return _local(rpc_cap())->detach(local_addr); } +void Region_map_client::detach(addr_t at) { return _local(rpc_cap())->detach(at); } void Region_map_client::fault_handler(Signal_context_capability /*handler*/) @@ -66,7 +61,7 @@ void Region_map_client::fault_handler(Signal_context_capability /*handler*/) } -Region_map::State Region_map_client::state() { return _local(rpc_cap())->state(); } +Region_map::Fault Region_map_client::fault() { return _local(rpc_cap())->fault(); } Dataspace_capability Region_map_client::dataspace() diff --git a/repos/base-linux/src/lib/base/region_map_mmap.cc b/repos/base-linux/src/lib/base/region_map_mmap.cc index 46b34ae66b..80411fc1ef 100644 --- a/repos/base-linux/src/lib/base/region_map_mmap.cc +++ b/repos/base-linux/src/lib/base/region_map_mmap.cc @@ -73,14 +73,13 @@ static Mutex &mutex() } -addr_t Region_map_mmap::_reserve_local(bool use_local_addr, - addr_t local_addr, - Genode::size_t size) +Region_map_mmap::Reserve_local_result +Region_map_mmap::_reserve_local(bool use_at, addr_t at, size_t size) { /* special handling for stack area */ - if (use_local_addr - && local_addr == stack_area_virtual_base() - && size == stack_area_virtual_size()) { + if (use_at + && at == stack_area_virtual_base() + && size == stack_area_virtual_size()) { /* * On the first request to reserve the stack area, we flush the @@ -97,37 +96,38 @@ addr_t Region_map_mmap::_reserve_local(bool use_local_addr, } } inst; - return local_addr; + return at; } int const flags = MAP_ANONYMOUS | MAP_PRIVATE; int const prot = PROT_NONE; - void * const addr_in = use_local_addr ? (void *)local_addr : 0; + void * const addr_in = use_at ? (void *)at : 0; void * const addr_out = lx_mmap(addr_in, size, prot, flags, -1, 0); /* reserve at local address failed - unmap incorrect mapping */ - if (use_local_addr && addr_in != addr_out) + if (use_at && addr_in != addr_out) lx_munmap((void *)addr_out, size); - if ((use_local_addr && addr_in != addr_out) + if ((use_at && addr_in != addr_out) || (((long)addr_out < 0) && ((long)addr_out > -4095))) { error("_reserve_local: lx_mmap failed " "(addr_in=", addr_in, ",addr_out=", addr_out, "/", (long)addr_out, ")"); - throw Region_map::Region_conflict(); + return Reserve_local_error::REGION_CONFLICT; } return (addr_t) addr_out; } -void *Region_map_mmap::_map_local(Dataspace_capability ds, - Genode::size_t size, - addr_t offset, - bool use_local_addr, - addr_t local_addr, - bool executable, - bool overmap, - bool writeable) +Region_map_mmap::Map_local_result +Region_map_mmap::_map_local(Dataspace_capability ds, + size_t size, + addr_t offset, + bool use_at, + addr_t at, + bool executable, + bool overmap, + bool writeable) { writeable = _dataspace_writeable(ds) && writeable; @@ -136,7 +136,7 @@ void *Region_map_mmap::_map_local(Dataspace_capability ds, int const prot = PROT_READ | (writeable ? PROT_WRITE : 0) | (executable ? PROT_EXEC : 0); - void * const addr_in = use_local_addr ? (void*)local_addr : 0; + void * const addr_in = use_at ? (void*)at : 0; void * const addr_out = lx_mmap(addr_in, size, prot, flags, fd, offset); /* @@ -148,27 +148,28 @@ void *Region_map_mmap::_map_local(Dataspace_capability ds, lx_close(fd); /* attach at local address failed - unmap incorrect mapping */ - if (use_local_addr && addr_in != addr_out) + if (use_at && addr_in != addr_out) lx_munmap((void *)addr_out, size); - if ((use_local_addr && addr_in != addr_out) + if ((use_at && addr_in != addr_out) || (((long)addr_out < 0) && ((long)addr_out > -4095))) { error("_map_local: lx_mmap failed" "(addr_in=", addr_in, ", addr_out=", addr_out, "/", (long)addr_out, ") " "overmap=", overmap); - throw Region_map::Region_conflict(); + return Map_local_error::REGION_CONFLICT; } return addr_out; } -void Region_map_mmap::_add_to_rmap(Region const ®ion) +bool Region_map_mmap::_add_to_rmap(Region const ®ion) { if (_rmap.add_region(region) < 0) { error("_add_to_rmap: could not add region to sub RM session"); - throw Region_conflict(); + return false; } + return true; } @@ -190,38 +191,30 @@ struct Inhibit_tracing_guard }; -Region_map::Local_addr Region_map_mmap::attach(Dataspace_capability ds, - size_t size, off_t offset, - bool use_local_addr, - Region_map::Local_addr local_addr, - bool executable, bool writeable) +Region_map_mmap::Attach_result +Region_map_mmap::attach(Dataspace_capability ds, Attr const &attr) { Mutex::Guard mutex_guard(mutex()); Inhibit_tracing_guard it_guard { }; /* only support attach_at for sub RM sessions */ - if (_sub_rm && !use_local_addr) { + if (_sub_rm && !attr.use_at) { error("Region_map_mmap::attach: attaching w/o local addr not supported"); - throw Region_conflict(); - } - - if (offset < 0) { - error("Region_map_mmap::attach: negative offset not supported"); - throw Region_conflict(); + return Attach_error::REGION_CONFLICT; } if (!ds.valid()) - throw Invalid_dataspace(); + return Attach_error::INVALID_DATASPACE; - size_t const remaining_ds_size = _dataspace_size(ds) > (addr_t)offset - ? _dataspace_size(ds) - (addr_t)offset : 0; + size_t const remaining_ds_size = _dataspace_size(ds) > attr.offset + ? _dataspace_size(ds) - attr.offset : 0; /* determine size of virtual address region */ - size_t const region_size = size ? min(remaining_ds_size, size) - : remaining_ds_size; + size_t const region_size = attr.size ? min(remaining_ds_size, attr.size) + : remaining_ds_size; if (region_size == 0) - throw Region_conflict(); + return Attach_error::REGION_CONFLICT; /* * We have to distinguish the following cases @@ -243,19 +236,20 @@ Region_map::Local_addr Region_map_mmap::attach(Dataspace_capability ds, */ if (is_sub_rm_session(ds)) { error("Region_map_mmap::attach: nesting sub RM sessions is not supported"); - throw Invalid_dataspace(); + return Attach_error::INVALID_DATASPACE; } /* * Check for the dataspace to not exceed the boundaries of the * sub RM session */ - if (region_size + (addr_t)local_addr > _size) { + if (region_size + attr.at > _size) { error("Region_map_mmap::attach: dataspace does not fit in sub RM session"); - throw Region_conflict(); + return Attach_error::REGION_CONFLICT; } - _add_to_rmap(Region(local_addr, offset, ds, region_size)); + if (!_add_to_rmap(Region(attr.at, attr.offset, ds, region_size))) + return Attach_error::REGION_CONFLICT; /* * Case 3.1 @@ -266,9 +260,11 @@ Region_map::Local_addr Region_map_mmap::attach(Dataspace_capability ds, * argument as the region was reserved by a PROT_NONE mapping. */ if (_is_attached()) - _map_local(ds, region_size, offset, true, _base + (addr_t)local_addr, executable, true, writeable); + _map_local(ds, region_size, attr.offset, + true, _base + attr.at, + attr.executable, true, attr.writeable); - return (void *)local_addr; + return Range { .start = attr.at, .num_bytes = region_size }; } else { @@ -279,7 +275,7 @@ Region_map::Local_addr Region_map_mmap::attach(Dataspace_capability ds, Region_map_mmap *rm = dynamic_cast(ds_if); if (!rm) - throw Invalid_dataspace(); + return Attach_error::INVALID_DATASPACE; /* * Case 2.1 @@ -288,39 +284,51 @@ Region_map::Local_addr Region_map_mmap::attach(Dataspace_capability ds, */ if (rm->_base) { error("Region_map_mmap::attach: mapping a sub RM session twice is not supported"); - throw Region_conflict(); + return Attach_error::REGION_CONFLICT; } /* * Reserve local address range that can hold the entire sub RM * session. */ - rm->_base = _reserve_local(use_local_addr, local_addr, region_size); + return _reserve_local(attr.use_at, attr.at, region_size) + .convert( - _add_to_rmap(Region(rm->_base, offset, ds, region_size)); + [&] (addr_t base) -> Attach_result + { + rm->_base = base; - /* - * Cases 2.2, 3.2 - * - * The sub rm session was not attached until now but it may have - * been populated with dataspaces. Go through all regions and map - * each of them. - */ - for (int i = 0; i < Region_registry::MAX_REGIONS; i++) { - Region region = rm->_rmap.region(i); - if (!region.used()) - continue; + if (!_add_to_rmap(Region(rm->_base, attr.offset, ds, region_size))) + return Attach_error::REGION_CONFLICT; - /* - * We have to enforce the mapping via the 'overmap' argument as - * the region was reserved by a PROT_NONE mapping. - */ - _map_local(region.dataspace(), region.size(), region.offset(), - true, rm->_base + region.start() + region.offset(), - executable, true, writeable); - } + /* + * Cases 2.2, 3.2 + * + * The sub rm session was not attached until now but it may have + * been populated with dataspaces. Go through all regions and map + * each of them. + */ + for (int i = 0; i < Region_registry::MAX_REGIONS; i++) { + Region region = rm->_rmap.region(i); + if (!region.used()) + continue; - return rm->_base; + /* + * We have to enforce the mapping via the 'overmap' argument as + * the region was reserved by a PROT_NONE mapping. + */ + _map_local(region.dataspace(), region.size(), region.offset(), + true, rm->_base + region.start() + region.offset(), + attr.executable, true, attr.writeable); + } + + return Range { .start = rm->_base, .num_bytes = region_size }; + }, + [&] (Reserve_local_error e) { + switch (e) { case Reserve_local_error::REGION_CONFLICT: break; } + return Attach_error::REGION_CONFLICT; + } + ); } else { @@ -330,18 +338,28 @@ Region_map::Local_addr Region_map_mmap::attach(Dataspace_capability ds, * Boring, a plain dataspace is attached to a root RM session. * Note, we do not overmap. */ - void *addr = _map_local(ds, region_size, offset, use_local_addr, - local_addr, executable, false, writeable); + return _map_local(ds, region_size, attr.offset, attr.use_at, + attr.at, attr.executable, false, attr.writeable) + .convert( - _add_to_rmap(Region((addr_t)addr, offset, ds, region_size)); + [&] (void *addr) -> Attach_result { + if (_add_to_rmap(Region((addr_t)addr, attr.offset, ds, region_size))) + return Range { .start = (addr_t)addr, .num_bytes = region_size }; - return addr; + return Attach_error::REGION_CONFLICT; + }, + + [&] (Map_local_error e) { + switch (e) { case Map_local_error::REGION_CONFLICT: break; } + return Attach_error::REGION_CONFLICT; + } + ); } } } -void Region_map_mmap::detach(Region_map::Local_addr local_addr) +void Region_map_mmap::detach(addr_t at) { Mutex::Guard mutex_guard(mutex()); @@ -356,14 +374,14 @@ void Region_map_mmap::detach(Region_map::Local_addr local_addr) * 2.2 we are attached to a root RM */ - Region region = _rmap.lookup(local_addr); + Region region = _rmap.lookup(at); if (!region.used()) return; /* * Remove meta data from region map */ - _rmap.remove_region(local_addr); + _rmap.remove_region(at); if (_sub_rm) { @@ -379,8 +397,8 @@ void Region_map_mmap::detach(Region_map::Local_addr local_addr) * needed. */ if (_is_attached()) { - lx_munmap((void *)((addr_t)local_addr + _base), region.size()); - _reserve_local(true, (addr_t)local_addr + _base, region.size()); + lx_munmap((void *)(at + _base), region.size()); + _reserve_local(true, at + _base, region.size()); } } else { @@ -392,7 +410,7 @@ void Region_map_mmap::detach(Region_map::Local_addr local_addr) * sub RM session. In both cases, we simply mark the local address * range as free. */ - lx_munmap(local_addr, region.size()); + lx_munmap((void *)at, region.size()); } /* diff --git a/repos/base-linux/src/lib/base/rm_session_client.cc b/repos/base-linux/src/lib/base/rm_session_client.cc index eefecc08c2..bc44619e46 100644 --- a/repos/base-linux/src/lib/base/rm_session_client.cc +++ b/repos/base-linux/src/lib/base/rm_session_client.cc @@ -35,7 +35,7 @@ Rm_session_client::Rm_session_client(Capability session) : Rpc_client(session) { } -Capability Rm_session_client::create(size_t size) { +Rm_session::Create_result Rm_session_client::create(size_t size) { return _local(rpc_cap())->create(size); } diff --git a/repos/base-linux/src/lib/base/rpc_cap_alloc.cc b/repos/base-linux/src/lib/base/rpc_cap_alloc.cc index 9645fd4968..044f942552 100644 --- a/repos/base-linux/src/lib/base/rpc_cap_alloc.cc +++ b/repos/base-linux/src/lib/base/rpc_cap_alloc.cc @@ -14,31 +14,53 @@ /* Genode includes */ #include #include -#include /* base-internal includes */ #include +#include using namespace Genode; +static Parent *_parent_ptr; +static Parent &_parent() +{ + if (_parent_ptr) + return *_parent_ptr; + + error("missing call of init_rpc_cap_alloc"); + for (;;); +} + + +void Genode::init_rpc_cap_alloc(Parent &parent) { _parent_ptr = &parent; } + + Native_capability Rpc_entrypoint::_alloc_rpc_cap(Pd_session& pd, Native_capability, addr_t) { /* first we allocate a cap from core, to allow accounting of caps. */ for (;;) { - Ram_quota ram_upgrade { 0 }; - Cap_quota cap_upgrade { 0 }; - try { pd.alloc_rpc_cap(_cap); break; } - catch (Out_of_ram) { ram_upgrade = Ram_quota { 2*1024*sizeof(long) }; } - catch (Out_of_caps) { cap_upgrade = Cap_quota { 4 }; } + Pd_session::Alloc_rpc_cap_result const result = pd.alloc_rpc_cap(_cap); + if (result.ok()) + break; - env_deprecated()->parent()->upgrade(Parent::Env::pd(), - String<100>("ram_quota=", ram_upgrade, ", " - "cap_quota=", cap_upgrade).string()); + using Error = Pd_session::Alloc_rpc_cap_error; + pd.alloc_rpc_cap(_cap).with_error([&] (Error e) { + + Ram_quota ram_upgrade { 0 }; + Cap_quota cap_upgrade { 0 }; + + switch (e) { + case Error::OUT_OF_RAM: ram_upgrade = { 2*1024*sizeof(long) }; break; + case Error::OUT_OF_CAPS: cap_upgrade = { 4 }; break; + } + _parent().upgrade(Parent::Env::pd(), + String<100>("ram_quota=", ram_upgrade, ", " + "cap_quota=", cap_upgrade).string()); + }); } - return Thread::native_thread().epoll.alloc_rpc_cap(); } diff --git a/repos/base-linux/src/lib/base/thread_env.cc b/repos/base-linux/src/lib/base/thread_env.cc index d7523d68a2..e2a5b51518 100644 --- a/repos/base-linux/src/lib/base/thread_env.cc +++ b/repos/base-linux/src/lib/base/thread_env.cc @@ -18,8 +18,12 @@ #include +/* base-internal includes */ +#include + using namespace Genode; + extern addr_t * __initial_sp; /* @@ -73,7 +77,7 @@ void lx_exception_signal_handlers() ** Startup library support ** *****************************/ -void prepare_init_main_thread() +void Genode::prepare_init_main_thread() { /* * Initialize the 'lx_environ' pointer diff --git a/repos/base-linux/src/lib/base/thread_linux.cc b/repos/base-linux/src/lib/base/thread_linux.cc index 5db0888e5e..f34b62e639 100644 --- a/repos/base-linux/src/lib/base/thread_linux.cc +++ b/repos/base-linux/src/lib/base/thread_linux.cc @@ -15,12 +15,10 @@ /* Genode includes */ #include #include -#include #include #include #include #include -#include /* base-internal includes */ #include @@ -31,11 +29,27 @@ using namespace Genode; + extern int main_thread_futex_counter; + static void empty_signal_handler(int) { } +static Capability pd_session_cap(Capability pd_cap = { }) +{ + static Capability cap = pd_cap; /* defined once by 'init_thread_start' */ + return cap; +} + + +static Thread_capability main_thread_cap(Thread_capability main_cap = { }) +{ + static Thread_capability cap = main_cap; /* defined once by 'init_thread_bootstrap' */ + return cap; +} + + static Blockade &startup_lock() { static Blockade blockade; @@ -89,15 +103,19 @@ void Thread::_thread_start() void Thread::_init_platform_thread(size_t /* weight */, Type type) { /* if no cpu session is given, use it from the environment */ - if (!_cpu_session) - _cpu_session = env_deprecated()->cpu_session(); + if (!_cpu_session) { + error("Thread::_init_platform_thread: _cpu_session not initialized"); + return; + } /* for normal threads create an object at the CPU session */ if (type == NORMAL) { - _thread_cap = _cpu_session->create_thread(env_deprecated()->pd_session_cap(), - _stack->name().string(), - Affinity::Location(), - Weight()); + _cpu_session->create_thread(pd_session_cap(), _stack->name().string(), + Affinity::Location(), Weight()).with_result( + [&] (Thread_capability cap) { _thread_cap = cap; }, + [&] (Cpu_session::Create_thread_error) { + error("Thread::_init_platform_thread: create_thread failed"); + }); return; } /* adjust initial object state for main threads */ @@ -136,11 +154,13 @@ void Thread::_deinit_platform_thread() } /* inform core about the killed thread */ - _cpu_session->kill_thread(_thread_cap); + _thread_cap.with_result( + [&] (Thread_capability cap) { _cpu_session->kill_thread(cap); }, + [&] (Cpu_session::Create_thread_error) { }); } -void Thread::start() +Thread::Start_result Thread::start() { /* synchronize calls of the 'start' function */ static Mutex mutex; @@ -165,4 +185,22 @@ void Thread::start() /* wait until the 'thread_start' function got entered */ startup_lock().block(); + + return Start_result::OK; +} + + +void Genode::init_thread_start(Capability pd_cap) +{ + pd_session_cap(pd_cap); +} + + +void Genode::init_thread_bootstrap(Cpu_session &cpu, Thread_capability main_cap) +{ + main_thread_cap(main_cap); + + /* register TID and PID of the main thread at core */ + Linux_native_cpu_client native_cpu(cpu.native_cpu()); + native_cpu.thread_id(main_cap, lx_getpid(), lx_gettid()); } diff --git a/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc b/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc index 8cf10983bd..9bb2af2684 100644 --- a/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc +++ b/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc @@ -20,7 +20,7 @@ /* base-internal includes */ #include #include -#include +#include /** @@ -80,7 +80,6 @@ static Genode::Env *_env_ptr; namespace Genode { - extern void bootstrap_component(); extern void call_global_static_constructors(); struct Thread_meta_data_created; @@ -89,14 +88,20 @@ namespace Genode { /* - * This function is normally provided by the cxx library, which is not - * used for lx_hybrid programs. For lx_hybrid programs, the exception - * handling is initialized by the host system's regular startup code. - * - * However, we conveniently use this function to get hold of the - * component's environment and initialize the default log output. + * For lx_hybrid programs, C++ support is initialized by the startup code + * provided by the host toolchain. */ -void Genode::init_exception_handling(Env &env) +void Genode::init_exception_handling(Ram_allocator &, Region_map &) { } + + +/* + * This function is normally provided by the dynamic linker, which is not used + * for lx_hybrid programs. For lx_hybrid programs. + * + * However, we conveniently use this function to get hold of the component's + * environment and initialize the default log output. + */ +void Genode::init_ldso_phdr(Env &env) { _env_ptr = &env; @@ -125,7 +130,9 @@ Genode::size_t Component::stack_size() int main() { - Genode::bootstrap_component(); + using namespace Genode; + + bootstrap_component(init_platform()); /* never reached */ } @@ -401,6 +408,18 @@ static void *thread_start(void *arg) } +void Genode::init_thread(Cpu_session &, Region_map &) { } +void Genode::init_thread_start(Capability) { } + + +void Genode::init_thread_bootstrap(Cpu_session &cpu, Thread_capability main_cap) +{ + /* register TID and PID of the main thread at core */ + Linux_native_cpu_client native_cpu(cpu.native_cpu()); + native_cpu.thread_id(main_cap, lx_getpid(), lx_gettid()); +} + + extern "C" void *malloc(::size_t size); extern "C" void free(void *); @@ -408,7 +427,7 @@ namespace { struct Global_allocator : Allocator { - typedef Genode::size_t size_t; + using size_t = Genode::size_t; Alloc_result try_alloc(size_t size) override { return malloc(size); } @@ -474,12 +493,13 @@ Thread *Thread::myself() } -void Thread::start() +Thread::Start_result Thread::start() { /* * Unblock thread that is supposed to slumber in 'thread_start'. */ native_thread().meta_data->started(); + return Start_result::OK; } @@ -512,9 +532,14 @@ Thread::Thread(size_t weight, const char *name, size_t /* stack size */, _thread_cap = _cpu_session->create_thread(_env_ptr->pd_session_cap(), name, Location(), Weight(weight)); - - Linux_native_cpu_client native_cpu(_cpu_session->native_cpu()); - native_cpu.thread_id(_thread_cap, native_thread().pid, native_thread().tid); + _thread_cap.with_result( + [&] (Thread_capability cap) { + Linux_native_cpu_client native_cpu(_cpu_session->native_cpu()); + native_cpu.thread_id(cap, native_thread().pid, native_thread().tid); + }, + [&] (Cpu_session::Create_thread_error) { + error("failed to create hybrid thread"); } + ); } @@ -554,15 +579,17 @@ Thread::~Thread() _native_thread = nullptr; /* inform core about the killed thread */ - _cpu_session->kill_thread(_thread_cap); + _thread_cap.with_result( + [&] (Thread_capability cap) { _cpu_session->kill_thread(cap); }, + [&] (Cpu_session::Create_thread_error) { }); } -/****************** - ** Platform_env ** - ******************/ +/************** + ** Platform ** + **************/ -void Platform_env::_attach_stack_area() +void Platform::_attach_stack_area() { /* * Omit attaching the stack area to the local address space for hybrid diff --git a/repos/base-linux/src/lib/syscall/linux_syscalls.h b/repos/base-linux/src/lib/syscall/linux_syscalls.h index 8c7e96da23..0cf1bd8e41 100644 --- a/repos/base-linux/src/lib/syscall/linux_syscalls.h +++ b/repos/base-linux/src/lib/syscall/linux_syscalls.h @@ -36,7 +36,6 @@ /* Genode includes */ #include -#include #include #include @@ -77,14 +76,6 @@ extern "C" void wait_for_continue(void); -#define PRAW(fmt, ...) \ - do { \ - char str[128]; \ - Genode::snprintf(str, sizeof(str), \ - ESC_ERR fmt ESC_END "\n", ##__VA_ARGS__); \ - Genode::raw(Genode::Cstring(str)); \ - } while (0) - /********************************************************* ** System-call bindings implemented in syscall library ** diff --git a/repos/base-linux/src/test/lx_hybrid_ctors/main.cc b/repos/base-linux/src/test/lx_hybrid_ctors/main.cc index 273b07b391..0d6b06783b 100644 --- a/repos/base-linux/src/test/lx_hybrid_ctors/main.cc +++ b/repos/base-linux/src/test/lx_hybrid_ctors/main.cc @@ -44,10 +44,6 @@ extern Testlib_testclass testlib_testobject; Testapp_testclass testapp_testobject; -static int exit_status; -static void exit_on_suspended() { exit(exit_status); } - - /* * Component implements classical main function in construct. */ @@ -63,6 +59,5 @@ void Component::construct(Genode::Env &env) testapp_testobject.dummy(); log("--- returning from main ---"); - exit_status = 0; - env.ep().schedule_suspend(exit_on_suspended, nullptr); + env.parent().exit(0); } diff --git a/repos/base-linux/src/test/lx_hybrid_errno/main.cc b/repos/base-linux/src/test/lx_hybrid_errno/main.cc index b20cdc9550..8ef45ddbf7 100644 --- a/repos/base-linux/src/test/lx_hybrid_errno/main.cc +++ b/repos/base-linux/src/test/lx_hybrid_errno/main.cc @@ -42,15 +42,9 @@ struct Thread : Genode::Thread }; -static int exit_status; -static void exit_on_suspended() { exit(exit_status); } - - struct Unexpected_errno_change { }; -/* - * Component implements classical main function in construct. - */ + void Component::construct(Genode::Env &env) { Genode::log("--- thread-local errno test ---"); @@ -75,6 +69,5 @@ void Component::construct(Genode::Env &env) } Genode::log("--- finished thread-local errno test ---"); - exit_status = 0; - env.ep().schedule_suspend(exit_on_suspended, nullptr); + env.parent().exit(0); } diff --git a/repos/base-linux/src/test/lx_hybrid_exception/main.cc b/repos/base-linux/src/test/lx_hybrid_exception/main.cc index d18a17a232..76cc164472 100644 --- a/repos/base-linux/src/test/lx_hybrid_exception/main.cc +++ b/repos/base-linux/src/test/lx_hybrid_exception/main.cc @@ -23,13 +23,7 @@ using namespace Genode; class Test_exception { }; -static int exit_status; -static void exit_on_suspended() { exit(exit_status); } - -/* - * Component implements classical main function in construct. - */ void Component::construct(Genode::Env &env) { log("--- lx_hybrid exception test ---"); @@ -42,6 +36,5 @@ void Component::construct(Genode::Env &env) } log("--- returning from main ---"); - exit_status = 0; - env.ep().schedule_suspend(exit_on_suspended, nullptr); + env.parent().exit(0); } diff --git a/repos/base-linux/src/test/lx_hybrid_pthread_ipc/main.cc b/repos/base-linux/src/test/lx_hybrid_pthread_ipc/main.cc index 7d75d22619..a6ac592e00 100644 --- a/repos/base-linux/src/test/lx_hybrid_pthread_ipc/main.cc +++ b/repos/base-linux/src/test/lx_hybrid_pthread_ipc/main.cc @@ -50,13 +50,6 @@ static void *pthread_entry(void *) } -static int exit_status; -static void exit_on_suspended() { exit(exit_status); } - - -/* - * Component implements classical main function in construct. - */ void Component::construct(Genode::Env &env) { Genode::log("--- pthread IPC test ---"); @@ -69,6 +62,5 @@ void Component::construct(Genode::Env &env) main_wait_lock()->block(); Genode::log("--- finished pthread IPC test ---"); - exit_status = 0; - env.ep().schedule_suspend(exit_on_suspended, nullptr); + env.parent().exit(0); } diff --git a/repos/base-linux/src/test/lx_rmap/main.cc b/repos/base-linux/src/test/lx_rmap/main.cc index 7786b5fefc..3307666426 100644 --- a/repos/base-linux/src/test/lx_rmap/main.cc +++ b/repos/base-linux/src/test/lx_rmap/main.cc @@ -64,49 +64,64 @@ Main::Main(Env &env) : heap(env.ram(), env.rm()) log("blob region region ", Hex_range(beg, size), " size=", size); /* RAM dataspace attachment overlapping binary */ - try { - Ram_dataspace_capability ds(env.ram().alloc(size)); - - log("before RAM dataspace attach"); - env.rm().attach_at(ds, beg); - error("after RAM dataspace attach -- ERROR"); - env.parent().exit(-1); - } catch (Region_map::Region_conflict) { - log("OK caught Region_conflict exception"); - } + log("before RAM dataspace attach"); + env.rm().attach(env.ram().alloc(size), { + .size = { }, .offset = { }, + .use_at = true, .at = beg, + .executable = { }, .writeable = true + }).with_result( + [&] (Region_map::Range) { + error("after RAM dataspace attach -- ERROR"); + env.parent().exit(-1); }, + [&] (Region_map::Attach_error e) { + if (e == Region_map::Attach_error::REGION_CONFLICT) + log("OK caught Region_conflict exception"); } + ); /* empty managed dataspace overlapping binary */ - try { - Rm_connection rm_connection(env); - Region_map_client rm(rm_connection.create(size)); - Dataspace_capability ds(rm.dataspace()); + { + Rm_connection rm_connection(env); + Region_map_client rm(rm_connection.create(size)); log("before sub-RM dataspace attach"); - env.rm().attach_at(ds, beg); - error("after sub-RM dataspace attach -- ERROR"); - env.parent().exit(-1); - } catch (Region_map::Region_conflict) { - log("OK caught Region_conflict exception"); + env.rm().attach(rm.dataspace(), { + .size = { }, .offset = { }, + .use_at = true, .at = beg, + .executable = { }, .writeable = true + }).with_result( + [&] (Region_map::Range) { + error("after sub-RM dataspace attach -- ERROR"); + env.parent().exit(-1); }, + [&] (Region_map::Attach_error e) { + if (e == Region_map::Attach_error::REGION_CONFLICT) + log("OK caught Region_conflict exception"); } + ); } /* sparsely populated managed dataspace in free VM area */ - try { + { Rm_connection rm_connection(env); Region_map_client rm(rm_connection.create(0x100000)); - rm.attach_at(env.ram().alloc(0x1000), 0x1000); - - Dataspace_capability ds(rm.dataspace()); + rm.attach(env.ram().alloc(0x1000), { + .size = { }, .offset = { }, + .use_at = true, .at = 0x1000, + .executable = { }, .writeable = true + }); log("before populated sub-RM dataspace attach"); - char *addr = (char *)env.rm().attach(ds) + 0x1000; + char * const addr = env.rm().attach(rm.dataspace(), { + .size = { }, .offset = { }, + .use_at = { }, .at = { }, + .executable = { }, .writeable = true + }).convert( + [&] (Region_map::Range r) { return (char *)r.start + 0x1000; }, + [&] (Region_map::Attach_error) { return nullptr; } + ); log("after populated sub-RM dataspace attach / before touch"); char const val = *addr; *addr = 0x55; log("after touch (", val, "/", *addr, ")"); - } catch (Region_map::Region_conflict) { - error("Caught Region_conflict exception -- ERROR"); - env.parent().exit(-1); } env.parent().exit(0); } diff --git a/repos/base-linux/src/timer/linux/component.cc b/repos/base-linux/src/timer/linux/component.cc new file mode 100644 index 0000000000..60f04eb3a3 --- /dev/null +++ b/repos/base-linux/src/timer/linux/component.cc @@ -0,0 +1,377 @@ +/* + * \brief Timer driver for Linux + * \author Norman Feske + * \author Alexander Boettcher + * \date 2024-06-18 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* Genode includes */ +#include +#include +#include +#include +#include +#include + +/* base-internal includes */ +#include + +/* Linux includes */ +#include +#include + + +namespace Timer { + + using namespace Genode; + + struct Tsc { uint64_t tsc; }; + struct Clock; + struct Device; + struct Alarm; + struct Root; + struct Session_component; + struct Main; + + using Alarms = Alarm_registry; +} + + +struct Timer::Clock +{ + uint64_t us; + + static constexpr uint64_t MASK = uint64_t(-1); + + uint64_t value() const { return us; } + + void print(Output &out) const { Genode::print(out, us); } +}; + + +class Timer::Device +{ + public: + + struct Wakeup_dispatcher : Interface + { + virtual void dispatch_device_wakeup() = 0; + }; + + struct Deadline : Clock { }; + + static constexpr Deadline infinite_deadline { uint64_t(-1) }; + + private: + + struct Waiter : Thread + { + Wakeup_dispatcher &_dispatcher; + + Mutex _mutex { }; /* protect '_deadline' */ + Deadline _deadline { ~0ULL }; + + Device &_device; + + Waiter(Env &env, Wakeup_dispatcher &dispatcher, Device &device) + : + Thread(env, "waiter", 8*1024*sizeof(addr_t)), + _dispatcher(dispatcher), + _device(device) + { + start(); + } + + void entry() override + { + for (;;) { + + auto deadline_atomic = [&] + { + Mutex::Guard guard(_mutex); + return _deadline; + }; + + { + auto const deadline = deadline_atomic(); + auto const now = _device.now(); + + if (now.us < deadline.us) { + /* no support to cancel sleep, use 1ms granularity */ + auto usecs = min(deadline.us - now.us, 1000ull); + + struct timespec ts { + .tv_sec = long(usecs) / (1000 * 1000), + .tv_nsec = (long(usecs) % (1000 * 1000)) * 1000, + }; + + lx_nanosleep(&ts, &ts); + } + } + + if (_device.now().us >= deadline_atomic().us) + _dispatcher.dispatch_device_wakeup(); + } + } + + void update_deadline(Deadline const deadline) + { + Mutex::Guard guard(_mutex); + + bool const sooner_than_scheduled = (deadline.us < _deadline.us); + + _deadline = deadline; + + if (sooner_than_scheduled) { + /* cancel old timeout by waking sleeping waiter */ + + /* XXX not supported to cancel nanosleep */ + } + } + } _waiter; + + int lx_gettimeofday(struct timeval *tv, struct timeval *tz) const { + return int(lx_syscall(SYS_gettimeofday, tv, tz)); } + + public: + + Device(Env &env, Wakeup_dispatcher &dispatcher) + : _waiter(env, dispatcher, *this) { } + + Clock now() const + { + struct timeval tv { }; + + lx_gettimeofday(&tv, 0); + + return { .us = uint64_t(tv.tv_sec) * 1000 * 1000 + tv.tv_usec }; + } + + void update_deadline(Deadline deadline) { + _waiter.update_deadline(deadline); } +}; + + +struct Timer::Alarm : Alarms::Element +{ + Session_component &session; + + Alarm(Alarms &alarms, Session_component &session, Clock time) + : + Alarms::Element(alarms, *this, time), session(session) + { } + + void print(Output &out) const; +}; + + +static Timer::Device::Deadline next_deadline(Timer::Alarms &alarms) +{ + using namespace Timer; + + return alarms.soonest(Clock { 0 }).convert( + [&] (Clock soonest) -> Device::Deadline { + + /* scan alarms for a cluster nearby the soonest */ + Genode::uint64_t const MAX_DELAY_US = 250; + Device::Deadline result { soonest.us }; + alarms.for_each_in_range(soonest, Clock { soonest.us + MAX_DELAY_US }, + [&] (Alarm const &alarm) { + result.us = max(result.us, alarm.time.us); }); + + return result; + }, + [&] (Alarms::None) { return Device::infinite_deadline; }); +} + + +struct Timer::Session_component : Session_object +{ + Alarms &_alarms; + Mutex &_alarms_mutex; + Device &_device; + + Signal_context_capability _sigh { }; + + Clock const _creation_time = _device.now(); + + uint64_t _local_now_us() const { return _device.now().us - _creation_time.us; } + + struct Period { uint64_t us; }; + + Constructible _period { }; + Constructible _alarm { }; + + Session_component(Env &env, + Resources const &resources, + Label const &label, + Diag const &diag, + Alarms &alarms, + Mutex &alarms_mutex, + Device &device) + : + Session_object(env.ep(), resources, label, diag), + _alarms(alarms), _alarms_mutex(alarms_mutex), _device(device) + { } + + ~Session_component() + { + Mutex::Guard guard(_alarms_mutex); + + _alarm.destruct(); + } + + /** + * Called by Device::Wakeup_dispatcher with '_alarms_mutex' taken + */ + void handle_wakeup() + { + if (_sigh.valid()) + Signal_transmitter(_sigh).submit(); + + if (_period.constructed()) { + Clock const next = _alarm.constructed() + ? Clock { _alarm->time.us + _period->us } + : Clock { _device.now().us + _period->us }; + + _alarm.construct(_alarms, *this, next); + + } else /* response of 'trigger_once' */ { + _alarm.destruct(); + } + } + + /****************************** + ** Timer::Session interface ** + ******************************/ + + void trigger_once(uint64_t rel_us) override + { + Mutex::Guard guard(_alarms_mutex); + + _period.destruct(); + _alarm.destruct(); + + Clock const now = _device.now(); + + rel_us = max(rel_us, 250u); + _alarm.construct(_alarms, *this, Clock { now.us + rel_us }); + + _device.update_deadline(next_deadline(_alarms)); + } + + void trigger_periodic(uint64_t period_us) override + { + Mutex::Guard guard(_alarms_mutex); + + _period.destruct(); + _alarm.destruct(); + + if (period_us) { + period_us = max(period_us, 1000u); + _period.construct(period_us); + handle_wakeup(); + } + + _device.update_deadline(next_deadline(_alarms)); + } + + void sigh(Signal_context_capability sigh) override { _sigh = sigh; } + + uint64_t elapsed_ms() const override { return _local_now_us()/1000; } + uint64_t elapsed_us() const override { return _local_now_us(); } + + void msleep(uint64_t) override { } + void usleep(uint64_t) override { } +}; + + +struct Timer::Root : public Root_component +{ + private: + + Env &_env; + Alarms &_alarms; + Mutex &_alarms_mutex; + Device &_device; + + protected: + + Session_component *_create_session(const char *args) override + { + return new (md_alloc()) + Session_component(_env, + session_resources_from_args(args), + session_label_from_args(args), + session_diag_from_args(args), + _alarms, _alarms_mutex, _device); + } + + void _upgrade_session(Session_component *s, const char *args) override + { + s->upgrade(ram_quota_from_args(args)); + s->upgrade(cap_quota_from_args(args)); + } + + void _destroy_session(Session_component *session) override + { + Genode::destroy(md_alloc(), session); + } + + public: + + Root(Env &env, Allocator &md_alloc, + Alarms &alarms, Mutex &alarms_mutex, Device &device) + : + Root_component(&env.ep().rpc_ep(), &md_alloc), + _env(env), _alarms(alarms), _alarms_mutex(alarms_mutex), _device(device) + { } +}; + + +void Timer::Alarm::print(Output &out) const { Genode::print(out, session.label()); } + + +struct Timer::Main : Device::Wakeup_dispatcher +{ + Env &_env; + + Device _device { _env, *this }; + + Mutex _alarms_mutex { }; + Alarms _alarms { }; + + Sliced_heap _sliced_heap { _env.ram(), _env.rm() }; + + Root _root { _env, _sliced_heap, _alarms, _alarms_mutex, _device }; + + /** + * Device::Wakeup_dispatcher + */ + void dispatch_device_wakeup() override + { + Mutex::Guard guard(_alarms_mutex); + + /* handle and remove pending alarms */ + while (_alarms.with_any_in_range({ 0 }, _device.now(), [&] (Alarm &alarm) { + alarm.session.handle_wakeup(); })); + + /* schedule next wakeup */ + _device.update_deadline(next_deadline(_alarms)); + } + + Main(Genode::Env &env) : _env(env) + { + _env.parent().announce(_env.ep().manage(_root)); + } +}; + + +void Component::construct(Genode::Env &env) { static Timer::Main inst(env); } diff --git a/repos/base-linux/src/timer/linux/target.mk b/repos/base-linux/src/timer/linux/target.mk index 3c14cda4f9..9438921997 100644 --- a/repos/base-linux/src/timer/linux/target.mk +++ b/repos/base-linux/src/timer/linux/target.mk @@ -1,9 +1,6 @@ -TARGET = linux_timer_drv -GEN_DIR := $(call select_from_repositories,src/timer/periodic)/.. -INC_DIR += $(GEN_DIR)/periodic -SRC_CC += periodic/time_source.cc time_source.cc -LIBS += syscall-linux +TARGET = linux_timer +INC_DIR += $(PRG_DIR) +SRC_CC += component.cc +LIBS += base syscall-linux -include $(GEN_DIR)/target.inc - -vpath periodic/time_source.cc $(GEN_DIR) +REP_INC_DIR += src/include diff --git a/repos/base-linux/src/timer/linux/time_source.cc b/repos/base-linux/src/timer/linux/time_source.cc deleted file mode 100644 index 7aa076ac17..0000000000 --- a/repos/base-linux/src/timer/linux/time_source.cc +++ /dev/null @@ -1,52 +0,0 @@ -/* - * \brief Time source that uses sleeping by the means of the kernel - * \author Norman Feske - * \author Martin Stein - * \date 2006-08-15 - */ - -/* - * Copyright (C) 2006-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -/* Linux includes */ -#include -#include - -/* local includes */ -#include - -using namespace Genode; - - -inline int lx_gettimeofday(struct timeval *tv, struct timeval *tz) { - return (int)lx_syscall(SYS_gettimeofday, tv, tz); } - - -Microseconds Timer::Time_source::max_timeout() const -{ - Mutex::Guard mutex_guard(_mutex); - return Microseconds(1000 * 1000); -} - - -Duration Timer::Time_source::curr_time() -{ - struct timeval tv; - lx_gettimeofday(&tv, 0); - return Duration(Microseconds((uint64_t)tv.tv_sec * 1000 * 1000 + tv.tv_usec)); -} - - -void Timer::Time_source::_usleep(uint64_t us) -{ - struct timespec ts; - ts.tv_sec = (long)us / (1000 * 1000); - ts.tv_nsec = ((long)us % (1000 * 1000)) * 1000; - - if (lx_nanosleep(&ts, &ts) != 0) - throw Blocking_canceled(); -} diff --git a/repos/base-nova/README b/repos/base-nova/README index 5222292c52..938a359142 100644 --- a/repos/base-nova/README +++ b/repos/base-nova/README @@ -1,10 +1,5 @@ This repository contains the port of Genode to the NOVA microhypervisor. -For more information on this base platform, please refer to the official -website. +For more information on this kernel, please refer to the official website. :[http://hypervisor.org]: Official website for the NOVA microhypervisor. - -For information on using Genode on NOVA, please revisit the documentation at -'base-nova/doc/nova.txt': - diff --git a/repos/base-nova/include/nova/capability_space.h b/repos/base-nova/include/nova/capability_space.h index 5d351a6eea..c85542ff3d 100644 --- a/repos/base-nova/include/nova/capability_space.h +++ b/repos/base-nova/include/nova/capability_space.h @@ -24,7 +24,7 @@ namespace Genode { namespace Capability_space { static constexpr unsigned long INVALID_INDEX = ~0UL; - typedef Nova::Crd Ipc_cap_data; + using Ipc_cap_data = Nova::Crd; static inline Nova::Crd crd(Native_capability const &cap) { diff --git a/repos/base-nova/include/nova/syscall-generic.h b/repos/base-nova/include/nova/syscall-generic.h index 385080d98a..7a481d3d58 100644 --- a/repos/base-nova/include/nova/syscall-generic.h +++ b/repos/base-nova/include/nova/syscall-generic.h @@ -3,11 +3,12 @@ * \author Norman Feske * \author Sebastian Sumpf * \author Alexander Boettcher + * \author Benjamin Lamowski * \date 2009-12-27 */ /* - * Copyright (c) 2009 Genode Labs + * Copyright (c) 2009-2023 Genode Labs * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -56,7 +57,7 @@ namespace Nova { NOVA_CREATE_PT = 0x5, NOVA_CREATE_SM = 0x6, NOVA_REVOKE = 0x7, - NOVA_LOOKUP = 0x8, + NOVA_MISC = 0x8, /* lookup, delegate, acpi_suspend */ NOVA_EC_CTRL = 0x9, NOVA_SC_CTRL = 0xa, NOVA_PT_CTRL = 0xb, @@ -129,8 +130,9 @@ namespace Nova { uint32_t const tsc_freq; /* time-stamp counter frequency in kHz */ uint32_t const bus_freq; /* bus frequency in kHz */ - bool has_feature_vmx() const { return feature_flags & (1 << 1); } - bool has_feature_svm() const { return feature_flags & (1 << 2); } + bool has_feature_iommu() const { return feature_flags & (1 << 0); } + bool has_feature_vmx() const { return feature_flags & (1 << 1); } + bool has_feature_svm() const { return feature_flags & (1 << 2); } struct Cpu_desc { uint8_t flags; @@ -144,6 +146,9 @@ namespace Nova { uint8_t platform:3; uint8_t reserved:1; uint32_t patch; + + bool p_core() const { return flags & 0x2; } + bool e_core() const { return flags & 0x4; } uint8_t numa_id; } __attribute__((packed)); @@ -175,41 +180,102 @@ namespace Nova { } /** - * Map kernel cpu ids to virtual cpu ids. + * Resort CPU ids such, that + * - the boot CPU id is ever logical CPU id 0 + * - SMT threads of one CPU have logical CPU ids close together + * - P-Core has a smaller logical CPU id than E-Core CPUs + * + * Returns true, if re-mapping succeeded otherwise false. + * + * In case of failure, map_cpus will contain a 1:1 fallback mapping + * without any sorting as mentioned above. */ - bool remap_cpu_ids(uint8_t *map_cpus, uint8_t *cpu_numa_map, unsigned const boot_cpu) const { + bool remap_cpu_ids(uint16_t *map_cpus, uint8_t *cpu_numa_map, unsigned const max_cpus, + unsigned const boot_cpu) const + { unsigned const num_cpus = cpus(); + bool too_many_cpus = false; unsigned cpu_i = 0; + /* fallback lambda in case re-ordering fails */ + auto remap_failure = [&] { + for (uint16_t i = 0; i < max_cpus; i++) { map_cpus[i] = i; } + return false; + }; + /* assign boot cpu ever the virtual cpu id 0 */ Cpu_desc const * const boot = cpu_desc_of_cpu(boot_cpu); - if (!boot || !is_cpu_enabled(boot_cpu)) - return false; + if (!boot) + return remap_failure(); map_cpus[cpu_i++] = (uint8_t)boot_cpu; if (cpu_i >= num_cpus) return true; + if (cpu_i >= max_cpus) + return remap_failure(); - /* assign remaining cores and afterwards all threads to the ids */ - for (uint8_t package = 0; package < 255; package++) { - for (uint8_t core = 0; core < 255; core++) { - for (uint8_t thread = 0; thread < 255; thread++) { + /* assign cores + SMT threads first and skip E-cores */ + bool done = for_all_cpus([&](auto const &cpu, auto const kernel_cpu_id) { + if (kernel_cpu_id == boot_cpu) + return false; + + /* handle normal or P-core */ + if (cpu.e_core()) + return false; + + map_cpus[cpu_i++] = (uint8_t)kernel_cpu_id; + + too_many_cpus = !!(cpu_i >= max_cpus); + + return (cpu_i >= num_cpus || too_many_cpus); + }); + + if (done) + return too_many_cpus ? remap_failure() : true; + + /* assign remaining E-cores */ + done = for_all_cpus([&](auto &cpu, auto &kernel_cpu_id) { + if (kernel_cpu_id == boot_cpu) + return false; + + /* handle solely E-core */ + if (!cpu.e_core()) + return false; + + map_cpus[cpu_i++] = (uint16_t)kernel_cpu_id; + + too_many_cpus = !!(cpu_i >= max_cpus); + + return (cpu_i >= num_cpus || too_many_cpus); + }); + + return too_many_cpus ? remap_failure() : done; + } + + /** + * Iterate over all CPUs in a _ever_ _consistent_ order. + */ + bool for_all_cpus(auto const &fn) const + { + for (uint16_t package = 0; package <= 255; package++) { + for (uint16_t core = 0; core <= 255; core++) { + for (uint16_t thread = 0; thread <= 255; thread++) { for (unsigned i = 0; i < cpu_max(); i++) { - if (i == boot_cpu || !is_cpu_enabled(i)) + if (!is_cpu_enabled(i)) continue; - Cpu_desc const * const c = cpu_desc_of_cpu(i); - if (!c) + auto const cpu = cpu_desc_of_cpu(i); + if (!cpu) continue; - if (!(c->package == package && c->core == core && - c->thread == thread)) + if (!(cpu->package == package && cpu->core == core && + cpu->thread == thread)) continue; - map_cpus[cpu_i++] = (uint8_t)i; + bool done = fn(*cpu, i); cpu_numa_map[cpu_i++] = c->numa_id; - if (cpu_i >= num_cpus) - return true; + if (done) + return done; } } } @@ -217,14 +283,13 @@ namespace Nova { return false; } - template - void for_each_enabled_cpu(FUNC const &func) const + void for_each_enabled_cpu(auto const &fn) const { for (unsigned i = 0; i < cpu_max(); i++) { Cpu_desc const * cpu = cpu_desc_of_cpu(i); if (!is_cpu_enabled(i)) continue; if (!cpu) return; - func(*cpu, i); + fn(*cpu, i); } } @@ -246,6 +311,9 @@ namespace Nova { EC_RESCHEDULE = 3U, EC_MIGRATE = 4U, EC_TIME = 5U, + EC_GET_VCPU_STATE = 6U, + EC_SET_VCPU_STATE = 7U, + EC_MSR_ACCESS = 8U }; enum Sc_op { @@ -352,6 +420,7 @@ namespace Nova { SYSCALL_SWAPGS = 1U << 23, /* SYSCALL and SWAPGS MSRs */ TPR = 1U << 24, /* TPR and TPR threshold */ TSC_AUX = 1U << 25, /* IA32_TSC_AUX used by rdtscp */ + XSAVE = 1U << 26, /* XCR and XSS used with XSAVE */ FPU = 1U << 31, /* FPU state */ IRQ = EFL | STA | INJ | TSC, @@ -595,8 +664,8 @@ namespace Nova { #endif unsigned long long qual[2]; /* exit qualification */ unsigned ctrl[2]; - unsigned long long reserved; mword_t cr0, cr2, cr3, cr4; + unsigned long long xcr0, xss; mword_t pdpte[4]; #ifdef __x86_64__ mword_t cr8, efer; @@ -627,6 +696,8 @@ namespace Nova { #endif } gdtr, idtr; unsigned long long tsc_val, tsc_off, tsc_aux; + unsigned long long exit_reason; + uint8_t fpu[512]; } __attribute__((packed)); mword_t mr[(4096 - 4 * sizeof(mword_t)) / sizeof(mword_t)]; }; @@ -716,7 +787,7 @@ namespace Nova { * Calling this function has the side effect of removing all typed * message items from the message buffer. */ - void set_msg_word(unsigned num) { items = num; } + void set_msg_word(mword_t const num) { items = num; } /** * Return current number of message word in UTCB diff --git a/repos/base-nova/include/nova/util.h b/repos/base-nova/include/nova/util.h index f4b1e22837..752bee6789 100644 --- a/repos/base-nova/include/nova/util.h +++ b/repos/base-nova/include/nova/util.h @@ -18,14 +18,9 @@ #include __attribute__((always_inline)) -inline void nova_die(const char * text = 0) +inline void nova_die() { - /* - * If thread is de-constructed the sessions are already gone. - * Be careful when enabling printf here. - */ - while (1) - asm volatile ("ud2a" : : "a"(text)); + asm volatile ("ud2a"); } diff --git a/repos/base-nova/include/nova_native_cpu/nova_native_cpu.h b/repos/base-nova/include/nova_native_cpu/nova_native_cpu.h index 3c139369ed..6134b8f714 100644 --- a/repos/base-nova/include/nova_native_cpu/nova_native_cpu.h +++ b/repos/base-nova/include/nova_native_cpu/nova_native_cpu.h @@ -11,8 +11,8 @@ * under the terms of the GNU Affero General Public License version 3. */ -#ifndef _INCLUDE__NOVA_NATIVE_CPU__FOC_NATIVE_CPU_H_ -#define _INCLUDE__NOVA_NATIVE_CPU__FOC_NATIVE_CPU_H_ +#ifndef _INCLUDE__NOVA_NATIVE_CPU__NOVA_NATIVE_CPU_H_ +#define _INCLUDE__NOVA_NATIVE_CPU__NOVA_NATIVE_CPU_H_ #include #include @@ -40,4 +40,4 @@ struct Genode::Cpu_session::Native_cpu : Interface GENODE_RPC_INTERFACE(Rpc_thread_type); }; -#endif /* _INCLUDE__NOVA_NATIVE_CPU__FOC_NATIVE_CPU_H_ */ +#endif /* _INCLUDE__NOVA_NATIVE_CPU__NOVA_NATIVE_CPU_H_ */ diff --git a/repos/base-nova/include/spec/32bit/nova/syscalls.h b/repos/base-nova/include/spec/32bit/nova/syscalls.h index 6fb41d4fee..22de9e655f 100644 --- a/repos/base-nova/include/spec/32bit/nova/syscalls.h +++ b/repos/base-nova/include/spec/32bit/nova/syscalls.h @@ -405,7 +405,7 @@ namespace Nova { inline uint8_t lookup(Crd &crd) { mword_t crd_r; - uint8_t res = syscall_1(NOVA_LOOKUP, 0, 0, crd.value(), &crd_r); + uint8_t res = syscall_1(NOVA_MISC, 0, 0, crd.value(), &crd_r); crd = Crd(crd_r); return res; } @@ -414,7 +414,15 @@ namespace Nova { ALWAYS_INLINE inline uint8_t delegate(mword_t pd_snd, mword_t pd_dst, Crd crd_dst) { - return syscall_2(NOVA_LOOKUP, 1, pd_snd, crd_dst.value(), pd_dst); + return syscall_2(NOVA_MISC, 1, pd_snd, crd_dst.value(), pd_dst); + } + + + ALWAYS_INLINE + inline uint8_t acpi_suspend(mword_t sm_auth_acpi, mword_t sleep_state_a, + mword_t sleep_state_b) + { + return syscall_2(NOVA_MISC, 2, sm_auth_acpi, sleep_state_a, sleep_state_b); } diff --git a/repos/base-nova/include/spec/64bit/nova/syscalls.h b/repos/base-nova/include/spec/64bit/nova/syscalls.h index 9e8fa765fc..f116d73585 100644 --- a/repos/base-nova/include/spec/64bit/nova/syscalls.h +++ b/repos/base-nova/include/spec/64bit/nova/syscalls.h @@ -3,11 +3,12 @@ * \author Norman Feske * \author Sebastian Sumpf * \author Alexander Boettcher + * \author Benjamin Lamowski * \date 2012-06-06 */ /* - * Copyright (c) 2012 Genode Labs + * Copyright (c) 2012-2023 Genode Labs * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -342,7 +343,7 @@ namespace Nova { inline uint8_t lookup(Crd &crd) { mword_t crd_r; - uint8_t res = syscall_1(NOVA_LOOKUP, 0, 0, crd.value(), &crd_r); + uint8_t res = syscall_1(NOVA_MISC, 0, 0, crd.value(), &crd_r); crd = Crd(crd_r); return res; } @@ -351,10 +352,17 @@ namespace Nova { ALWAYS_INLINE inline uint8_t delegate(mword_t pd_snd, mword_t pd_dst, Crd crd_dst) { - return syscall_2(NOVA_LOOKUP, 1, pd_snd, crd_dst.value(), pd_dst); + return syscall_2(NOVA_MISC, 1, pd_snd, crd_dst.value(), pd_dst); } + ALWAYS_INLINE + inline uint8_t acpi_suspend(mword_t sm_auth_acpi, mword_t sleep_state_a, + mword_t sleep_state_b) + { + return syscall_2(NOVA_MISC, 2, sm_auth_acpi, sleep_state_a, sleep_state_b); + } + ALWAYS_INLINE inline uint8_t sm_ctrl(mword_t sm, Sem_op op, unsigned long long timeout = 0) { diff --git a/repos/base-nova/lib/mk/base-nova-common.mk b/repos/base-nova/lib/mk/base-nova-common.mk index 81ebc9f3d3..e990dc33f7 100644 --- a/repos/base-nova/lib/mk/base-nova-common.mk +++ b/repos/base-nova/lib/mk/base-nova-common.mk @@ -14,3 +14,8 @@ SRC_CC += stack_area_addr.cc SRC_CC += cap_map.cc SRC_CC += capability.cc SRC_CC += signal_transmitter.cc + +# +# Prevent the compiler from deleting null pointer checks related to 'this == 0' +# +CC_OPT += -fno-delete-null-pointer-checks diff --git a/repos/base-nova/lib/mk/base-nova.mk b/repos/base-nova/lib/mk/base-nova.mk index 3c8b8a4e53..e3a08dfb07 100644 --- a/repos/base-nova/lib/mk/base-nova.mk +++ b/repos/base-nova/lib/mk/base-nova.mk @@ -4,4 +4,9 @@ LIBS += base-nova-common cxx timeout SRC_CC += thread_start.cc SRC_CC += cache.cc SRC_CC += signal.cc -SRC_CC += platform.cc +SRC_CC += capability_slab.cc + +# +# Prevent the compiler from deleting null pointer checks related to 'this == 0' +# +CC_OPT += -fno-delete-null-pointer-checks diff --git a/repos/base-nova/lib/mk/core-nova.inc b/repos/base-nova/lib/mk/core-nova.inc index 9df0b67e8f..206f936546 100644 --- a/repos/base-nova/lib/mk/core-nova.inc +++ b/repos/base-nova/lib/mk/core-nova.inc @@ -45,7 +45,7 @@ SRC_CC += stack_area.cc \ vm_session_common.cc \ heartbeat.cc -INC_DIR = $(REP_DIR)/src/core/include \ +INC_DIR += $(REP_DIR)/src/core/include \ $(REP_DIR)/src/include \ $(BASE_DIR)/src/include \ $(GEN_CORE_DIR)/include diff --git a/repos/base-nova/lib/mk/spec/x86_32/core-nova.mk b/repos/base-nova/lib/mk/spec/x86_32/core-nova.mk index 7c08a9d1e7..a28dad3028 100644 --- a/repos/base-nova/lib/mk/spec/x86_32/core-nova.mk +++ b/repos/base-nova/lib/mk/spec/x86_32/core-nova.mk @@ -1,3 +1,5 @@ SRC_CC += spec/x86_32/pager.cc +INC_DIR += $(REP_DIR)/src/core/include/spec/x86_32 + include $(REP_DIR)/lib/mk/core-nova.inc diff --git a/repos/base-nova/lib/mk/spec/x86_64/core-nova.mk b/repos/base-nova/lib/mk/spec/x86_64/core-nova.mk index 0424e85c4f..7ecaebd8f7 100644 --- a/repos/base-nova/lib/mk/spec/x86_64/core-nova.mk +++ b/repos/base-nova/lib/mk/spec/x86_64/core-nova.mk @@ -1,3 +1,5 @@ SRC_CC += spec/x86_64/pager.cc +INC_DIR += $(REP_DIR)/src/core/include/spec/x86_64 + include $(REP_DIR)/lib/mk/core-nova.inc diff --git a/repos/base-nova/patches/allow_iommu_access.patch b/repos/base-nova/patches/allow_iommu_access.patch new file mode 100644 index 0000000000..a569a96d8e --- /dev/null +++ b/repos/base-nova/patches/allow_iommu_access.patch @@ -0,0 +1,14 @@ +diff --git a/src/iommu_intel.cpp b/src/iommu_intel.cpp +index 1441466..c07224e 100644 +--- a/src/iommu_intel.cpp ++++ b/src/iommu_intel.cpp +@@ -36,7 +36,8 @@ uint32 Dmar::gcmd = GCMD_TE; + + Dmar::Dmar (Paddr p) : List (list), reg_base ((hwdev_addr -= PAGE_SIZE) | (p & PAGE_MASK)), invq (static_cast(Buddy::allocator.alloc (ord, Pd::kern.quota, Buddy::FILL_0))), invq_idx (0) + { +- Pd::kern.Space_mem::delreg (Pd::kern.quota, Pd::kern.mdb_cache, p & ~PAGE_MASK); ++// XXX allow Genode platform driver to access device and take over control ++// Pd::kern.Space_mem::delreg (Pd::kern.quota, Pd::kern.mdb_cache, p & ~PAGE_MASK); + Pd::kern.Space_mem::insert (Pd::kern.quota, reg_base, 0, Hpt::HPT_NX | Hpt::HPT_G | Hpt::HPT_UC | Hpt::HPT_W | Hpt::HPT_P, p & ~PAGE_MASK); + + cap = read(REG_CAP); diff --git a/repos/base-nova/patches/syscall_msi.patch b/repos/base-nova/patches/syscall_msi.patch new file mode 100644 index 0000000000..b112ab71ed --- /dev/null +++ b/repos/base-nova/patches/syscall_msi.patch @@ -0,0 +1,13 @@ +diff --git a/src/syscall.cpp b/src/syscall.cpp +index 838bfee..5619293 100644 +--- a/src/syscall.cpp ++++ b/src/syscall.cpp +@@ -1205,7 +1205,7 @@ void Ec::sys_assign_gsi() + sys_finish(); + } + +- if (EXPECT_FALSE (!Gsi::gsi_table[gsi].ioapic && (!Pd::current->Space_mem::lookup (r->dev(), phys) || ((rid = Pci::phys_to_rid (phys)) == ~0U && (rid = Hpet::phys_to_rid (phys)) == ~0U)))) { ++ if (EXPECT_FALSE (!Gsi::gsi_table[gsi].ioapic && r->dev() && (!Pd::current->Space_mem::lookup (r->dev(), phys) || ((rid = Pci::phys_to_rid (phys)) == ~0U && (rid = Hpet::phys_to_rid (phys)) == ~0U)))) { + trace (TRACE_ERROR, "%s: Non-DEV CAP (%#lx)", __func__, r->dev()); + sys_finish(); + } diff --git a/repos/base-nova/ports/nova.hash b/repos/base-nova/ports/nova.hash index 26c3ed6a4b..321dbd6073 100644 --- a/repos/base-nova/ports/nova.hash +++ b/repos/base-nova/ports/nova.hash @@ -1 +1 @@ -9ad770935115d201863fd83924e4684b14b8b56f +e8997fb0870b6f8bdcb6da34a9b333ed4a304305 diff --git a/repos/base-nova/ports/nova.port b/repos/base-nova/ports/nova.port index a20fb070fb..736a144c68 100644 --- a/repos/base-nova/ports/nova.port +++ b/repos/base-nova/ports/nova.port @@ -4,7 +4,8 @@ DOWNLOADS := nova.git # r10 branch URL(nova) := https://github.com/alex-ab/NOVA.git -REV(nova) := a34076e7b8d48d08c2edee7754eadad8b6ea5312 +REV(nova) := bca1aa3553d8c5df4f4b6ed5a2ee72f69bdf7a7f DIR(nova) := src/kernel/nova PATCHES := $(sort $(wildcard $(REP_DIR)/patches/*.patch)) +PATCH_OPT := -p1 -d ${DIR(nova)} diff --git a/repos/base-nova/recipes/api/base-nova/hash b/repos/base-nova/recipes/api/base-nova/hash index bbdab0a29c..e82c972d7e 100644 --- a/repos/base-nova/recipes/api/base-nova/hash +++ b/repos/base-nova/recipes/api/base-nova/hash @@ -1 +1 @@ -2022-10-11 4458ea63a69ae070e19a3cb09a403137755d2cb0 +2024-08-28 80901e07dc386b2dcc259a85ea60fdd2bb4c1b6a diff --git a/repos/base-nova/recipes/src/base-nova/content.mk b/repos/base-nova/recipes/src/base-nova/content.mk index 41278a28a1..b147cab7ae 100644 --- a/repos/base-nova/recipes/src/base-nova/content.mk +++ b/repos/base-nova/recipes/src/base-nova/content.mk @@ -17,5 +17,5 @@ content: for spec in x86_32 x86_64; do \ mv lib/mk/spec/$$spec/ld-nova.mk lib/mk/spec/$$spec/ld.mk; \ done; - sed -i "s/nova_timer_drv/timer/" src/timer/nova/target.mk + sed -i "s/nova_timer/timer/" src/timer/nova/target.mk diff --git a/repos/base-nova/recipes/src/base-nova/hash b/repos/base-nova/recipes/src/base-nova/hash index c2b670f646..9957562e69 100644 --- a/repos/base-nova/recipes/src/base-nova/hash +++ b/repos/base-nova/recipes/src/base-nova/hash @@ -1 +1 @@ -2022-10-11 574204b7d442811236bba60e4fe3f79e34fe9985 +2024-08-28 2bdb13a64a152f7cb2601222245eb6f132d5325b diff --git a/repos/base-nova/run/nova.run b/repos/base-nova/run/nova.run new file mode 100644 index 0000000000..a304f23f49 --- /dev/null +++ b/repos/base-nova/run/nova.run @@ -0,0 +1,46 @@ +build { core init lib/ld test/nova } + +set check_pat 1 +if {[have_include power_on/qemu]} { + set check_pat 0 +} + +if {[get_cmd_switch --autopilot] && [have_spec x86_32]} { + # Disable test for our outdated nighly test machine for 32bit + set check_pat 0 +} + +create_boot_directory + +set config { + + + + + + + + + + + + + } + +append config " + " + +append config { + + +} + +install_config $config + +build_boot_image [build_artifacts] + +append qemu_args "-nographic -smp 2" + +run_genode_until {Test finished} 240 + +puts "\nTest succeeded" diff --git a/repos/base-nova/run/platform.run b/repos/base-nova/run/platform.run deleted file mode 100644 index 0adfbcd627..0000000000 --- a/repos/base-nova/run/platform.run +++ /dev/null @@ -1,46 +0,0 @@ -build "core init test/platform" - -set check_pat 1 -if {[have_include power_on/qemu]} { - set check_pat 0 -} - -if {[get_cmd_switch --autopilot] && [have_spec x86_32]} { - # Disable test for our outdated nighly test machine for 32bit - set check_pat 0 -} - -create_boot_directory - -set config { - - - - - - - - - - - - - } - -append config " - " - -append config { - - -} - -install_config $config - -build_boot_image "core ld.lib.so init test-platform" - -append qemu_args "-nographic -smp 2" - -run_genode_until {Test finished} 240 - -puts "\nTest succeeded" diff --git a/repos/base-nova/src/core/core_log_out.cc b/repos/base-nova/src/core/core_log_out.cc index 84c7c5264c..5eba5717cd 100644 --- a/repos/base-nova/src/core/core_log_out.cc +++ b/repos/base-nova/src/core/core_log_out.cc @@ -18,7 +18,7 @@ #include #include -void Genode::Core_log::out(char const c) +void Core::Core_log::out(char const c) { enum { CLOCK = 0, BAUDRATE = 115200 }; diff --git a/repos/base-nova/src/core/core_region_map.cc b/repos/base-nova/src/core/core_region_map.cc index 7bacb30091..30a3551434 100644 --- a/repos/base-nova/src/core/core_region_map.cc +++ b/repos/base-nova/src/core/core_region_map.cc @@ -11,9 +11,6 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* Genode includes */ -#include - /* core includes */ #include #include @@ -23,7 +20,8 @@ /* NOVA includes */ #include -using namespace Genode; +using namespace Core; + /** * Map dataspace core-locally @@ -51,58 +49,50 @@ static inline void * alloc_region(Dataspace_component &ds, const size_t size) return virt_addr; } -Region_map::Local_addr -Core_region_map::attach(Dataspace_capability ds_cap, size_t, - off_t offset, bool use_local_addr, - Region_map::Local_addr, - bool executable, bool writeable) +Region_map::Attach_result +Core_region_map::attach(Dataspace_capability ds_cap, Attr const &attr) { - auto lambda = [&] (Dataspace_component *ds_ptr) -> Local_addr { + return _ep.apply(ds_cap, [&] (Dataspace_component * const ds_ptr) -> Attach_result { + if (!ds_ptr) - throw Invalid_dataspace(); + return Attach_error::INVALID_DATASPACE; Dataspace_component &ds = *ds_ptr; - if (use_local_addr) { - error("Parameter 'use_local_addr' not supported within core"); - return nullptr; - } - - if (offset) { - error("Parameter 'offset' not supported within core"); - return nullptr; - } + /* attach attributes 'use_at' and 'offset' not supported within core */ + if (attr.use_at || attr.offset) + return Attach_error::REGION_CONFLICT; const size_t page_rounded_size = align_addr(ds.size(), get_page_size_log2()); /* allocate the virtual region contiguous for the dataspace */ void * virt_ptr = alloc_region(ds, page_rounded_size); if (!virt_ptr) - throw Out_of_ram(); + return Attach_error::OUT_OF_RAM; /* map it */ Nova::Utcb &utcb = *reinterpret_cast(Thread::myself()->utcb()); - const Nova::Rights rights(true, writeable && ds.writeable(), executable); + const Nova::Rights rights(true, attr.writeable && ds.writeable(), attr.executable); if (map_local(platform_specific().core_pd_sel(), utcb, ds.phys_addr(), reinterpret_cast(virt_ptr), page_rounded_size >> get_page_size_log2(), rights, true)) { platform().region_alloc().free(virt_ptr, page_rounded_size); - throw Out_of_ram(); + + return Attach_error::OUT_OF_RAM; } - return virt_ptr; - }; - return _ep.apply(ds_cap, lambda); + return Range { .start = addr_t(virt_ptr), .num_bytes = page_rounded_size }; + }); } -void Core_region_map::detach(Local_addr core_local_addr) +void Core_region_map::detach(addr_t core_local_addr) { - size_t size = platform_specific().region_alloc_size_at(core_local_addr); + size_t size = platform_specific().region_alloc_size_at((void *)core_local_addr); unmap_local(*reinterpret_cast(Thread::myself()->utcb()), core_local_addr, size >> get_page_size_log2()); - platform().region_alloc().free(core_local_addr); + platform().region_alloc().free((void *)core_local_addr); } diff --git a/repos/base-nova/src/core/core_rpc_cap_alloc.cc b/repos/base-nova/src/core/core_rpc_cap_alloc.cc index 395cabf125..a4b1c37613 100644 --- a/repos/base-nova/src/core/core_rpc_cap_alloc.cc +++ b/repos/base-nova/src/core/core_rpc_cap_alloc.cc @@ -14,17 +14,23 @@ /* Genode includes */ #include -/* core-local includes */ +/* core includes */ #include #include #include +/* base-internal includes */ +#include + using namespace Genode; -static Rpc_cap_factory &rpc_cap_factory() +void Genode::init_rpc_cap_alloc(Parent &) { } + + +static Core::Rpc_cap_factory &rpc_cap_factory() { - static Rpc_cap_factory inst(platform().core_mem_alloc()); + static Core::Rpc_cap_factory inst(Core::platform().core_mem_alloc()); return inst; } diff --git a/repos/base-nova/src/core/include/ipc_pager.h b/repos/base-nova/src/core/include/ipc_pager.h index 98d9d5307d..090be57c27 100644 --- a/repos/base-nova/src/core/include/ipc_pager.h +++ b/repos/base-nova/src/core/include/ipc_pager.h @@ -19,41 +19,41 @@ #include #include -/* core-local includes */ +/* core includes */ #include /* NOVA includes */ #include -namespace Genode { class Ipc_pager; } +namespace Core { class Ipc_pager; } -namespace Genode { enum { PAGE_SIZE_LOG2 = 12 }; } +namespace Core { enum { PAGE_SIZE_LOG2 = 12 }; } -static inline Nova::Rights nova_map_rights(Genode::Mapping const &mapping) +static inline Nova::Rights nova_map_rights(Core::Mapping const &mapping) { return Nova::Rights(true, mapping.writeable, mapping.executable); } -static inline Nova::Mem_crd nova_src_crd(Genode::Mapping const &mapping) +static inline Nova::Mem_crd nova_src_crd(Core::Mapping const &mapping) { - return Nova::Mem_crd(mapping.src_addr >> Genode::PAGE_SIZE_LOG2, - mapping.size_log2 - Genode::PAGE_SIZE_LOG2, + return Nova::Mem_crd(mapping.src_addr >> Core::PAGE_SIZE_LOG2, + mapping.size_log2 - Core::PAGE_SIZE_LOG2, nova_map_rights(mapping)); } -static inline Nova::Mem_crd nova_dst_crd(Genode::Mapping const &mapping) +static inline Nova::Mem_crd nova_dst_crd(Core::Mapping const &mapping) { - return Nova::Mem_crd(mapping.dst_addr >> Genode::PAGE_SIZE_LOG2, - mapping.size_log2 - Genode::PAGE_SIZE_LOG2, + return Nova::Mem_crd(mapping.dst_addr >> Core::PAGE_SIZE_LOG2, + mapping.size_log2 - Core::PAGE_SIZE_LOG2, nova_map_rights(mapping)); } -class Genode::Ipc_pager +class Core::Ipc_pager { private: diff --git a/repos/base-nova/src/core/include/irq_object.h b/repos/base-nova/src/core/include/irq_object.h index 869eeed784..5dd118a94c 100644 --- a/repos/base-nova/src/core/include/irq_object.h +++ b/repos/base-nova/src/core/include/irq_object.h @@ -15,9 +15,13 @@ #include /* Gsi_flags */ -namespace Genode { class Irq_object; class Irq_args; } +/* core includes */ +#include -class Genode::Irq_object +namespace Core { class Irq_object; class Irq_args; } + + +class Core::Irq_object { private: diff --git a/repos/base-nova/src/core/include/map_local.h b/repos/base-nova/src/core/include/map_local.h index b8ee65928f..a19afa4d79 100644 --- a/repos/base-nova/src/core/include/map_local.h +++ b/repos/base-nova/src/core/include/map_local.h @@ -20,7 +20,7 @@ /* core includes */ #include -namespace Genode { +namespace Core { /** * Map pages locally within core diff --git a/repos/base-nova/src/core/include/native_cpu_component.h b/repos/base-nova/src/core/include/native_cpu_component.h index 2a2ea83677..df1291fcd4 100644 --- a/repos/base-nova/src/core/include/native_cpu_component.h +++ b/repos/base-nova/src/core/include/native_cpu_component.h @@ -18,15 +18,18 @@ #include #include -namespace Genode { +/* core includes */ +#include + +namespace Core { class Cpu_session_component; class Native_cpu_component; } -class Genode::Native_cpu_component : public Rpc_object +class Core::Native_cpu_component : public Rpc_object { private: diff --git a/repos/base-nova/src/core/include/native_pd_component.h b/repos/base-nova/src/core/include/native_pd_component.h index 98c1fcdde9..93836c0c73 100644 --- a/repos/base-nova/src/core/include/native_pd_component.h +++ b/repos/base-nova/src/core/include/native_pd_component.h @@ -17,17 +17,17 @@ /* Genode includes */ #include -/* core-local includes */ +/* core includes */ #include -namespace Genode { +namespace Core { class Pd_session_component; class Native_pd_component; } -class Genode::Native_pd_component : public Rpc_object +class Core::Native_pd_component : public Rpc_object { private: diff --git a/repos/base-nova/src/core/include/nova_util.h b/repos/base-nova/src/core/include/nova_util.h index f5dca5ca15..f27fb32a05 100644 --- a/repos/base-nova/src/core/include/nova_util.h +++ b/repos/base-nova/src/core/include/nova_util.h @@ -16,15 +16,14 @@ #ifndef _CORE__INCLUDE__NOVA_UTIL_H_ #define _CORE__INCLUDE__NOVA_UTIL_H_ -/* Genode includes */ -#include - /* NOVA includes */ #include -/* local includes */ +/* core includes */ +#include #include + /** * Return boot CPU number. It is required if threads in core should be placed * on the same CPU as the main thread. @@ -71,7 +70,7 @@ static int map_local(Genode::addr_t const pd, Nova::Utcb &utcb, Nova::uint8_t res = Nova::delegate(pd, pd, dst_crd); if (res != Nova::NOVA_OK) { - typedef Genode::Hex Hex; + using Hex = Genode::Hex; error("map_local failed ", Hex(src_crd.addr()), ":", Hex(src_crd.order()), ":", Hex(src_crd.type()), "->", Hex(dst_crd.addr()), ":", Hex(dst_crd.order()), ":", Hex(dst_crd.type()), " - ", @@ -220,18 +219,17 @@ inline void unmap_local(Nova::Utcb &, Genode::addr_t start, } -template -inline Nova::uint8_t syscall_retry(Genode::Pager_object &pager, FUNC func) +inline Nova::uint8_t syscall_retry(Core::Pager_object &pager, auto const &fn) { Nova::uint8_t res; do { - res = func(); + res = fn(); } while (res == Nova::NOVA_PD_OOM && Nova::NOVA_OK == pager.handle_oom()); return res; } -inline Nova::uint8_t async_map(Genode::Pager_object &pager, +inline Nova::uint8_t async_map(Core::Pager_object &pager, Genode::addr_t const source_pd, Genode::addr_t const target_pd, Nova::Obj_crd const &source_initial_caps, @@ -246,12 +244,12 @@ inline Nova::uint8_t async_map(Genode::Pager_object &pager, (void)ok; return syscall_retry(pager, - [&]() { + [&] { return Nova::delegate(source_pd, target_pd, target_initial_caps); }); } -inline Nova::uint8_t map_vcpu_portals(Genode::Pager_object &pager, +inline Nova::uint8_t map_vcpu_portals(Core::Pager_object &pager, Genode::addr_t const source_exc_base, Genode::addr_t const target_exc_base, Nova::Utcb &utcb, @@ -267,7 +265,7 @@ inline Nova::uint8_t map_vcpu_portals(Genode::Pager_object &pager, source_initial_caps, target_initial_caps, utcb); } -inline Nova::uint8_t map_pagefault_portal(Genode::Pager_object &pager, +inline Nova::uint8_t map_pagefault_portal(Core::Pager_object &pager, Genode::addr_t const source_exc_base, Genode::addr_t const target_exc_base, Genode::addr_t const target_pd, @@ -276,7 +274,7 @@ inline Nova::uint8_t map_pagefault_portal(Genode::Pager_object &pager, using Nova::Obj_crd; using Nova::PT_SEL_PAGE_FAULT; - Genode::addr_t const source_pd = Genode::platform_specific().core_pd_sel(); + Genode::addr_t const source_pd = Core::platform_specific().core_pd_sel(); Obj_crd const source_initial_caps(source_exc_base + PT_SEL_PAGE_FAULT, 0); Obj_crd const target_initial_caps(target_exc_base + PT_SEL_PAGE_FAULT, 0); @@ -285,4 +283,14 @@ inline Nova::uint8_t map_pagefault_portal(Genode::Pager_object &pager, source_initial_caps, target_initial_caps, utcb); } +inline Nova::Hip const &kernel_hip() +{ + /** + * Initial value of esp register, saved by the crt0 startup code. + * This value contains the address of the hypervisor information page. + */ + extern Genode::addr_t __initial_sp; + return *reinterpret_cast(__initial_sp); +} + #endif /* _CORE__INCLUDE__NOVA_UTIL_H_ */ diff --git a/repos/base-nova/src/core/include/pager.h b/repos/base-nova/src/core/include/pager.h index 9b0d350324..db18f28bcd 100644 --- a/repos/base-nova/src/core/include/pager.h +++ b/repos/base-nova/src/core/include/pager.h @@ -25,383 +25,387 @@ /* NOVA includes */ #include -/* core-local includes */ +/* core includes */ #include #include - -namespace Genode { - - typedef Cpu_session::Thread_creation_failed Invalid_thread; +namespace Core { class Pager_entrypoint; class Pager_object; + class Exception_handlers; - class Exception_handlers - { - private: - - template - __attribute__((regparm(1))) static void _handler(Pager_object &); - - public: - - Exception_handlers(Pager_object &); - - template - void register_handler(Pager_object &, Nova::Mtd, - void (__attribute__((regparm(1)))*)(Pager_object &) = nullptr); - }; - - - class Pager_object : public Object_pool::Entry - { - private: - - unsigned long _badge; /* used for debugging */ - - /** - * User-level signal handler registered for this pager object via - * 'Cpu_session::exception_handler()'. - */ - Signal_context_capability _exception_sigh { }; - - /** - * selectors for - * - cleanup portal - * - semaphore used by caller used to notify paused state - * - semaphore used to block during page fault handling or pausing - */ - addr_t _selectors; - - addr_t _initial_esp = 0; - addr_t _initial_eip = 0; - addr_t _client_exc_pt_sel; - - Mutex _state_lock { }; - - struct - { - struct Thread_state thread; - addr_t sel_client_ec; - enum { - BLOCKED = 0x1U, - DEAD = 0x2U, - SINGLESTEP = 0x4U, - SIGNAL_SM = 0x8U, - DISSOLVED = 0x10U, - SUBMIT_SIGNAL = 0x20U, - BLOCKED_PAUSE_SM = 0x40U, - MIGRATE = 0x80U - }; - uint8_t _status; - bool modified; - - /* convenience function to access pause/recall state */ - inline bool blocked() { return _status & BLOCKED;} - inline void block() { _status |= BLOCKED; } - inline void unblock() { _status &= (uint8_t)(~BLOCKED); } - inline bool blocked_pause_sm() { return _status & BLOCKED_PAUSE_SM;} - inline void block_pause_sm() { _status |= (uint8_t)BLOCKED_PAUSE_SM; } - inline void unblock_pause_sm() { _status &= (uint8_t)(~BLOCKED_PAUSE_SM); } - - inline void mark_dead() { _status |= DEAD; } - inline bool is_dead() { return _status & DEAD; } - - inline bool singlestep() { return _status & SINGLESTEP; } - - inline void mark_signal_sm() { _status |= SIGNAL_SM; } - inline bool has_signal_sm() { return _status & SIGNAL_SM; } - - inline void mark_dissolved() { _status |= DISSOLVED; } - inline bool dissolved() { return _status & DISSOLVED; } - - inline bool to_submit() { return _status & SUBMIT_SIGNAL; } - inline void submit_signal() { _status |= SUBMIT_SIGNAL; } - inline void reset_submit() { _status &= (uint8_t)(~SUBMIT_SIGNAL); } - - bool migrate() const { return _status & MIGRATE; } - void reset_migrate() { _status &= (uint8_t)(~MIGRATE); } - void request_migrate() { _status |= MIGRATE; } - } _state { }; - - Cpu_session_capability _cpu_session_cap; - Thread_capability _thread_cap; - Affinity::Location _location; - Affinity::Location _next_location { }; - Exception_handlers _exceptions; - - addr_t _pd_target; - - void _copy_state_from_utcb(Nova::Utcb const &utcb); - void _copy_state_to_utcb(Nova::Utcb &utcb) const; - - uint8_t _unsynchronized_client_recall(bool get_state_and_block); - - addr_t sel_pt_cleanup() const { return _selectors; } - addr_t sel_sm_block_pause() const { return _selectors + 1; } - addr_t sel_sm_block_oom() const { return _selectors + 2; } - addr_t sel_oom_portal() const { return _selectors + 3; } - - __attribute__((regparm(1))) - static void _page_fault_handler(Pager_object &); - - __attribute__((regparm(1))) - static void _startup_handler(Pager_object &); - - __attribute__((regparm(1))) - static void _invoke_handler(Pager_object &); - - __attribute__((regparm(1))) - static void _recall_handler(Pager_object &); - - __attribute__((regparm(3))) - static void _oom_handler(addr_t, addr_t, addr_t); - - void _construct_pager(); - bool _migrate_thread(); - - public: - - Pager_object(Cpu_session_capability cpu_session_cap, - Thread_capability thread_cap, - unsigned long badge, Affinity::Location location, - Genode::Session_label const &, - Cpu_session::Name const &); - - virtual ~Pager_object(); - - unsigned long badge() const { return _badge; } - void reset_badge() - { - Genode::Mutex::Guard guard(_state_lock); - _badge = 0; - } - - const char * client_thread() const; - const char * client_pd() const; - - virtual int pager(Ipc_pager &ps) = 0; - - /** - * Assign user-level exception handler for the pager object - */ - void exception_handler(Signal_context_capability sigh) - { - _exception_sigh = sigh; - } - - Affinity::Location location() const { return _location; } - - void migrate(Affinity::Location); - - /** - * Assign PD selector to PD - */ - void assign_pd(addr_t pd_sel) { _pd_target = pd_sel; } - addr_t pd_sel() const { return _pd_target; } - - void exception(uint8_t exit_id); - - /** - * Return base of initial portal window - */ - addr_t exc_pt_sel_client() { return _client_exc_pt_sel; } - - /** - * Set initial stack pointer used by the startup handler - */ - addr_t initial_esp() { return _initial_esp; } - void initial_esp(addr_t esp) { _initial_esp = esp; } - - /** - * Set initial instruction pointer used by the startup handler - */ - void initial_eip(addr_t eip) { _initial_eip = eip; } - - /** - * Continue execution of pager object - */ - void wake_up(); - - /** - * Notify exception handler about the occurrence of an exception - */ - bool submit_exception_signal() - { - if (!_exception_sigh.valid()) return false; - - _state.reset_submit(); - - Signal_transmitter transmitter(_exception_sigh); - transmitter.submit(); - - return true; - } - - /** - * Copy thread state of recalled thread. - */ - bool copy_thread_state(Thread_state * state_dst) - { - Mutex::Guard _state_lock_guard(_state_lock); - - if (!state_dst || !_state.blocked()) - return false; - - *state_dst = _state.thread; - - return true; - } - - /* - * Copy thread state to recalled thread. - */ - bool copy_thread_state(Thread_state state_src) - { - Mutex::Guard _state_lock_guard(_state_lock); - - if (!_state.blocked()) - return false; - - _state.thread = state_src; - _state.modified = true; - - return true; - } - - uint8_t client_recall(bool get_state_and_block); - void client_set_ec(addr_t ec) { _state.sel_client_ec = ec; } - - inline void single_step(bool on) - { - _state_lock.acquire(); - - if (_state.is_dead() || !_state.blocked() || - (on && (_state._status & _state.SINGLESTEP)) || - (!on && !(_state._status & _state.SINGLESTEP))) { - _state_lock.release(); - return; - } - - if (on) - _state._status |= _state.SINGLESTEP; - else - _state._status &= (uint8_t)(~_state.SINGLESTEP); - - _state_lock.release(); - - /* force client in exit and thereby apply single_step change */ - client_recall(false); - } - - /** - * Return CPU session that was used to created the thread - */ - Cpu_session_capability cpu_session_cap() const { return _cpu_session_cap; } - - /** - * Return thread capability - * - * This function enables the destructor of the thread's - * address-space region map to kill the thread. - */ - Thread_capability thread_cap() const { return _thread_cap; } - - /** - * Note in the thread state that an unresolved page - * fault occurred. - */ - void unresolved_page_fault_occurred() - { - _state.thread.unresolved_page_fault = true; - } - - /** - * Make sure nobody is in the handler anymore by doing an IPC to a - * local cap pointing to same serving thread (if not running in the - * context of the serving thread). When the call returns - * we know that nobody is handled by this object anymore, because - * all remotely available portals had been revoked beforehand. - */ - void cleanup_call(); - - /** - * Portal called by thread that causes a out of memory in kernel. - */ - addr_t create_oom_portal(); - - enum Policy { - STOP = 1, - UPGRADE_CORE_TO_DST = 2, - UPGRADE_PREFER_SRC_TO_DST = 3, - }; - - enum Oom { - SEND = 1, REPLY = 2, SELF = 4, - SRC_CORE_PD = ~0UL, SRC_PD_UNKNOWN = 0, - NO_NOTIFICATION = 0 - }; - - /** - * Implements policy on how to react on out of memory in kernel. - * - * Used solely inside core. On Genode core creates all the out - * of memory portals per EC. If the PD of a EC runs out of kernel - * memory it causes a OOM portal traversal, which is handled - * by the pager object of the causing thread. - * - * /param pd_sel PD selector from where to transfer kernel memory - * resources. The PD of this pager_object is the - * target PD. - * /param pd debug feature - string of PD (transfer_from) - * /param thread debug feature - string of EC (transfer_from) - */ - uint8_t handle_oom(addr_t pd_sel = SRC_CORE_PD, - const char * pd = "core", - const char * thread = "unknown", - Policy = Policy::UPGRADE_CORE_TO_DST); - static uint8_t handle_oom(addr_t pd_from, addr_t pd_to, - char const * src_pd, - char const * src_thread, - Policy policy, - addr_t sm_notify = NO_NOTIFICATION, - char const * dst_pd = "unknown", - char const * dst_thread = "unknown"); - - void print(Output &out) const; - }; - - /** - * Paging entry point - * - * For a paging entry point can hold only one activation. So, paging is - * strictly serialized for one entry point. - */ - class Pager_entrypoint : public Object_pool - { - public: - - /** - * Constructor - * - * \param cap_factory factory for creating capabilities - * for the pager objects managed by this - * entry point - */ - Pager_entrypoint(Rpc_cap_factory &cap_factory); - - /** - * Associate Pager_object with the entry point - */ - Pager_capability manage(Pager_object &) { - return Pager_capability(); } - - /** - * Dissolve Pager_object from entry point - */ - void dissolve(Pager_object &obj); - }; + using Pager_capability = Capability; } + +class Core::Exception_handlers +{ + private: + + template + __attribute__((regparm(1))) static void _handler(Pager_object &); + + public: + + Exception_handlers(Pager_object &); + + template + void register_handler(Pager_object &, Nova::Mtd, + void (__attribute__((regparm(1)))*)(Pager_object &) = nullptr); +}; + + +class Core::Pager_object : public Object_pool::Entry +{ + private: + + unsigned long _badge; /* used for debugging */ + + /** + * User-level signal handler registered for this pager object via + * 'Cpu_session::exception_handler()'. + */ + Signal_context_capability _exception_sigh { }; + + /** + * selectors for + * - cleanup portal + * - semaphore used by caller used to notify paused state + * - semaphore used to block during page fault handling or pausing + */ + addr_t _selectors; + + addr_t _initial_esp = 0; + addr_t _initial_eip = 0; + addr_t _client_exc_pt_sel; + + Mutex _state_lock { }; + + struct + { + struct Thread_state thread; + addr_t sel_client_ec; + enum { + BLOCKED = 0x1U, + DEAD = 0x2U, + SINGLESTEP = 0x4U, + SIGNAL_SM = 0x8U, + DISSOLVED = 0x10U, + SUBMIT_SIGNAL = 0x20U, + BLOCKED_PAUSE_SM = 0x40U, + MIGRATE = 0x80U + }; + uint8_t _status; + bool modified; + + /* convenience function to access pause/recall state */ + inline bool blocked() { return _status & BLOCKED;} + inline void block() { _status |= BLOCKED; } + inline void unblock() { _status &= (uint8_t)(~BLOCKED); } + inline bool blocked_pause_sm() { return _status & BLOCKED_PAUSE_SM;} + inline void block_pause_sm() { _status |= (uint8_t)BLOCKED_PAUSE_SM; } + inline void unblock_pause_sm() { _status &= (uint8_t)(~BLOCKED_PAUSE_SM); } + + inline void mark_dead() { _status |= DEAD; } + inline bool is_dead() { return _status & DEAD; } + + inline bool singlestep() { return _status & SINGLESTEP; } + + inline void mark_signal_sm() { _status |= SIGNAL_SM; } + inline bool has_signal_sm() { return _status & SIGNAL_SM; } + + inline void mark_dissolved() { _status |= DISSOLVED; } + inline bool dissolved() { return _status & DISSOLVED; } + + inline bool to_submit() { return _status & SUBMIT_SIGNAL; } + inline void submit_signal() { _status |= SUBMIT_SIGNAL; } + inline void reset_submit() { _status &= (uint8_t)(~SUBMIT_SIGNAL); } + + bool migrate() const { return _status & MIGRATE; } + void reset_migrate() { _status &= (uint8_t)(~MIGRATE); } + void request_migrate() { _status |= MIGRATE; } + } _state { }; + + Cpu_session_capability _cpu_session_cap; + Thread_capability _thread_cap; + Affinity::Location _location; + Affinity::Location _next_location { }; + Exception_handlers _exceptions; + + addr_t _pd_target; + + void _copy_state_from_utcb(Nova::Utcb const &utcb); + void _copy_state_to_utcb(Nova::Utcb &utcb) const; + + uint8_t _unsynchronized_client_recall(bool get_state_and_block); + + addr_t sel_pt_cleanup() const { return _selectors; } + addr_t sel_sm_block_pause() const { return _selectors + 1; } + addr_t sel_sm_block_oom() const { return _selectors + 2; } + addr_t sel_oom_portal() const { return _selectors + 3; } + + __attribute__((regparm(1))) + static void _page_fault_handler(Pager_object &); + + __attribute__((regparm(1))) + static void _startup_handler(Pager_object &); + + __attribute__((regparm(1))) + static void _invoke_handler(Pager_object &); + + __attribute__((regparm(1))) + static void _recall_handler(Pager_object &); + + __attribute__((regparm(3))) + static void _oom_handler(addr_t, addr_t, addr_t); + + void _construct_pager(); + bool _migrate_thread(); + + public: + + Pager_object(Cpu_session_capability cpu_session_cap, + Thread_capability thread_cap, + unsigned long badge, Affinity::Location location, + Session_label const &, + Cpu_session::Name const &); + + virtual ~Pager_object(); + + unsigned long badge() const { return _badge; } + void reset_badge() + { + Mutex::Guard guard(_state_lock); + _badge = 0; + } + + const char * client_thread() const; + const char * client_pd() const; + + enum class Pager_result { STOP, CONTINUE }; + + virtual Pager_result pager(Ipc_pager &ps) = 0; + + /** + * Assign user-level exception handler for the pager object + */ + void exception_handler(Signal_context_capability sigh) + { + _exception_sigh = sigh; + } + + Affinity::Location location() const { return _location; } + + void migrate(Affinity::Location); + + /** + * Assign PD selector to PD + */ + void assign_pd(addr_t pd_sel) { _pd_target = pd_sel; } + addr_t pd_sel() const { return _pd_target; } + + void exception(uint8_t exit_id); + + /** + * Return base of initial portal window + */ + addr_t exc_pt_sel_client() { return _client_exc_pt_sel; } + + /** + * Set initial stack pointer used by the startup handler + */ + addr_t initial_esp() { return _initial_esp; } + void initial_esp(addr_t esp) { _initial_esp = esp; } + + /** + * Set initial instruction pointer used by the startup handler + */ + void initial_eip(addr_t eip) { _initial_eip = eip; } + + /** + * Continue execution of pager object + */ + void wake_up(); + + /** + * Notify exception handler about the occurrence of an exception + */ + bool submit_exception_signal() + { + if (!_exception_sigh.valid()) return false; + + _state.reset_submit(); + + Signal_transmitter transmitter(_exception_sigh); + transmitter.submit(); + + return true; + } + + /** + * Copy thread state of recalled thread. + */ + bool copy_thread_state(Thread_state * state_dst) + { + Mutex::Guard _state_lock_guard(_state_lock); + + if (!state_dst || !_state.blocked()) + return false; + + *state_dst = _state.thread; + + return true; + } + + /* + * Copy thread state to recalled thread. + */ + bool copy_thread_state(Thread_state state_src) + { + Mutex::Guard _state_lock_guard(_state_lock); + + if (!_state.blocked()) + return false; + + _state.thread = state_src; + _state.modified = true; + + return true; + } + + uint8_t client_recall(bool get_state_and_block); + void client_set_ec(addr_t ec) { _state.sel_client_ec = ec; } + + inline void single_step(bool on) + { + _state_lock.acquire(); + + if (_state.is_dead() || !_state.blocked() || + (on && (_state._status & _state.SINGLESTEP)) || + (!on && !(_state._status & _state.SINGLESTEP))) { + _state_lock.release(); + return; + } + + if (on) + _state._status |= _state.SINGLESTEP; + else + _state._status &= (uint8_t)(~_state.SINGLESTEP); + + _state_lock.release(); + + /* force client in exit and thereby apply single_step change */ + client_recall(false); + } + + /** + * Return CPU session that was used to created the thread + */ + Cpu_session_capability cpu_session_cap() const { return _cpu_session_cap; } + + /** + * Return thread capability + * + * This function enables the destructor of the thread's + * address-space region map to kill the thread. + */ + Thread_capability thread_cap() const { return _thread_cap; } + + /** + * Note in the thread state that an unresolved page + * fault occurred. + */ + void unresolved_page_fault_occurred() + { + _state.thread.state = Thread_state::State::PAGE_FAULT; + } + + /** + * Make sure nobody is in the handler anymore by doing an IPC to a + * local cap pointing to same serving thread (if not running in the + * context of the serving thread). When the call returns + * we know that nobody is handled by this object anymore, because + * all remotely available portals had been revoked beforehand. + */ + void cleanup_call(); + + /** + * Portal called by thread that causes a out of memory in kernel. + */ + addr_t create_oom_portal(); + + enum Policy { + STOP = 1, + UPGRADE_CORE_TO_DST = 2, + UPGRADE_PREFER_SRC_TO_DST = 3, + }; + + enum Oom { + SEND = 1, REPLY = 2, SELF = 4, + SRC_CORE_PD = ~0UL, SRC_PD_UNKNOWN = 0, + NO_NOTIFICATION = 0 + }; + + /** + * Implements policy on how to react on out of memory in kernel. + * + * Used solely inside core. On Genode core creates all the out + * of memory portals per EC. If the PD of a EC runs out of kernel + * memory it causes a OOM portal traversal, which is handled + * by the pager object of the causing thread. + * + * /param pd_sel PD selector from where to transfer kernel memory + * resources. The PD of this pager_object is the + * target PD. + * /param pd debug feature - string of PD (transfer_from) + * /param thread debug feature - string of EC (transfer_from) + */ + uint8_t handle_oom(addr_t pd_sel = SRC_CORE_PD, + const char * pd = "core", + const char * thread = "unknown", + Policy = Policy::UPGRADE_CORE_TO_DST); + static uint8_t handle_oom(addr_t pd_from, addr_t pd_to, + char const * src_pd, + char const * src_thread, + Policy policy, + addr_t sm_notify = NO_NOTIFICATION, + char const * dst_pd = "unknown", + char const * dst_thread = "unknown"); + + void print(Output &out) const; +}; + + +/** + * Paging entry point + * + * For a paging entry point can hold only one activation. So, paging is + * strictly serialized for one entry point. + */ +class Core::Pager_entrypoint : public Object_pool +{ + public: + + /** + * Constructor + * + * \param cap_factory factory for creating capabilities + * for the pager objects managed by this + * entry point + */ + Pager_entrypoint(Rpc_cap_factory &cap_factory); + + /** + * Associate Pager_object with the entry point + */ + Pager_capability manage(Pager_object &) { + return Pager_capability(); } + + /** + * Dissolve Pager_object from entry point + */ + void dissolve(Pager_object &obj); +}; + #endif /* _CORE__INCLUDE__PAGER_H_ */ diff --git a/repos/base-nova/src/core/include/platform.h b/repos/base-nova/src/core/include/platform.h index 975cb9d868..2b40e106d9 100644 --- a/repos/base-nova/src/core/include/platform.h +++ b/repos/base-nova/src/core/include/platform.h @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2009-2017 Genode Labs GmbH + * Copyright (C) 2009-2022 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -20,99 +20,100 @@ #include #include -namespace Genode { +namespace Core { class Platform; } - class Platform : public Platform_generic - { - public: - enum { MAX_SUPPORTED_CPUS = 64}; +class Core::Platform : public Platform_generic +{ + public: - private: + enum { MAX_SUPPORTED_CPUS = 64}; - Core_mem_allocator _core_mem_alloc { }; /* core-accessible memory */ - Phys_allocator _io_mem_alloc; /* MMIO allocator */ - Phys_allocator _io_port_alloc; /* I/O port allocator */ - Phys_allocator _irq_alloc; /* IRQ allocator */ - Rom_fs _rom_fs { }; /* ROM file system */ - unsigned _gsi_base_sel { 0 }; /* cap selector of 1st IRQ */ - unsigned _core_pd_sel { 0 }; /* cap selector of root PD */ - addr_t _core_phys_start { 0 }; + private: - /** - * Virtual address range usable by non-core processes - */ - const addr_t _vm_base; - size_t _vm_size; + Core_mem_allocator _core_mem_alloc { }; /* core-accessible memory */ + Phys_allocator _io_mem_alloc; /* MMIO allocator */ + Phys_allocator _io_port_alloc; /* I/O port allocator */ + Phys_allocator _irq_alloc; /* IRQ allocator */ + Rom_fs _rom_fs { }; /* ROM file system */ + unsigned _gsi_base_sel { 0 }; /* cap selector of 1st IRQ */ + unsigned _core_pd_sel { 0 }; /* cap selector of root PD */ + addr_t _core_phys_start { 0 }; - /* available CPUs */ - Affinity::Space _cpus; + /** + * Virtual address range usable by non-core processes + */ + const addr_t _vm_base; + size_t _vm_size; - /* map of virtual cpu ids in Genode to kernel cpu ids */ - uint8_t map_cpu_ids[MAX_SUPPORTED_CPUS]; + /* available CPUs */ + Affinity::Space _cpus; + + /* map of virtual cpu ids in Genode to kernel cpu ids */ + uint16_t map_cpu_ids[MAX_SUPPORTED_CPUS]; uint8_t cpu_numa_map[MAX_SUPPORTED_CPUS]; - addr_t _map_pages(addr_t phys_page, addr_t pages, - bool guard_page = false); + addr_t _map_pages(addr_t phys_page, addr_t pages, + bool guard_page = false); - size_t _max_caps = 0; + size_t _max_caps = 0; - void _init_rom_modules(); + void _init_rom_modules(); - addr_t _rom_module_phys(addr_t virt); + addr_t _rom_module_phys(addr_t virt); - public: + public: - /** - * Constructor - */ - Platform(); + /** + * Constructor + */ + Platform(); - /******************************** - ** Generic platform interface ** - ********************************/ + /******************************** + ** Generic platform interface ** + ********************************/ - Range_allocator &ram_alloc() override { return _core_mem_alloc.phys_alloc(); } - Range_allocator &io_mem_alloc() override { return _io_mem_alloc; } - Range_allocator &io_port_alloc() override { return _io_port_alloc; } - Range_allocator &irq_alloc() override { return _irq_alloc; } - Range_allocator ®ion_alloc() override { return _core_mem_alloc.virt_alloc(); } - Range_allocator &core_mem_alloc() override { return _core_mem_alloc; } - addr_t vm_start() const override { return _vm_base; } - size_t vm_size() const override { return _vm_size; } - Rom_fs &rom_fs() override { return _rom_fs; } - size_t max_caps() const override { return _max_caps; } - void wait_for_exit() override; + Range_allocator &ram_alloc() override { return _core_mem_alloc.phys_alloc(); } + Range_allocator &io_mem_alloc() override { return _io_mem_alloc; } + Range_allocator &io_port_alloc() override { return _io_port_alloc; } + Range_allocator &irq_alloc() override { return _irq_alloc; } + Range_allocator ®ion_alloc() override { return _core_mem_alloc.virt_alloc(); } + Range_allocator &core_mem_alloc() override { return _core_mem_alloc; } + addr_t vm_start() const override { return _vm_base; } + size_t vm_size() const override { return _vm_size; } + Rom_fs &rom_fs() override { return _rom_fs; } + size_t max_caps() const override { return _max_caps; } + void wait_for_exit() override; - bool supports_direct_unmap() const override { return true; } + bool supports_direct_unmap() const override { return true; } - Address_space &core_pd() { ASSERT_NEVER_CALLED; } + Address_space &core_pd() { ASSERT_NEVER_CALLED; } - Affinity::Space affinity_space() const override { return _cpus; } + Affinity::Space affinity_space() const override { return _cpus; } - /******************* - ** NOVA specific ** - *******************/ + /******************* + ** NOVA specific ** + *******************/ - /** - * Return capability selector of first global system interrupt - */ - int gsi_base_sel() const { return _gsi_base_sel; } + /** + * Return capability selector of first global system interrupt + */ + int gsi_base_sel() const { return _gsi_base_sel; } - /** - * Determine size of a core local mapping required for a - * core_rm_session detach(). - */ - size_t region_alloc_size_at(void * addr) - { - using Size_at_error = Allocator_avl::Size_at_error; + /** + * Determine size of a core local mapping required for a + * core_rm_session detach(). + */ + size_t region_alloc_size_at(void * addr) + { + using Size_at_error = Allocator_avl::Size_at_error; - return (_core_mem_alloc.virt_alloc())()->size_at(addr).convert( - [ ] (size_t s) { return s; }, - [ ] (Size_at_error) { return 0U; }); - } + return (_core_mem_alloc.virt_alloc())()->size_at(addr).convert( + [ ] (size_t s) { return s; }, + [ ] (Size_at_error) { return 0U; }); + } /** * Return kernel CPU ID for given Genode CPU @@ -124,28 +125,26 @@ namespace Genode { return cpu_numa_map[kernel_cpu_id]; } - Affinity::Location sanitize(Affinity::Location location) { - return Affinity::Location(location.xpos() % _cpus.width(), - location.ypos() % _cpus.height(), - location.width(), location.height()); - } + Affinity::Location sanitize(Affinity::Location location) { + return Affinity::Location(location.xpos() % _cpus.width(), + location.ypos() % _cpus.height(), + location.width(), location.height()); + } - /** - * PD kernel capability selector of core - */ - unsigned core_pd_sel() const { return _core_pd_sel; } + /** + * PD kernel capability selector of core + */ + unsigned core_pd_sel() const { return _core_pd_sel; } - template - void for_each_location(FUNC const &fn) - { - for (unsigned x = 0; x < _cpus.width(); x++) { - for (unsigned y = 0; y < _cpus.height(); y++) { - Affinity::Location location(x, y, 1, 1); - fn(location); - } + void for_each_location(auto const &fn) + { + for (unsigned x = 0; x < _cpus.width(); x++) { + for (unsigned y = 0; y < _cpus.height(); y++) { + Affinity::Location location(x, y, 1, 1); + fn(location); } } - }; -} + } +}; #endif /* _CORE__INCLUDE__PLATFORM_H_ */ diff --git a/repos/base-nova/src/core/include/platform_pd.h b/repos/base-nova/src/core/include/platform_pd.h index 3525b5de63..cb4ee59cc7 100644 --- a/repos/base-nova/src/core/include/platform_pd.h +++ b/repos/base-nova/src/core/include/platform_pd.h @@ -18,80 +18,71 @@ #include #include - -namespace Genode { +namespace Core { class Platform_thread; - class Platform_pd : public Address_space - { - private: - - Native_capability _parent { }; - int _thread_cnt; - addr_t const _pd_sel; - const char * _label; - - /* - * Noncopyable - */ - Platform_pd(Platform_pd const &); - Platform_pd &operator = (Platform_pd const &); - - public: - - /** - * Constructors - */ - Platform_pd(Allocator &md_alloc, char const *, - signed pd_id = -1, bool create = true); - - /** - * Destructor - */ - ~Platform_pd(); - - /** - * Bind thread to protection domain - */ - bool bind_thread(Platform_thread &thread); - - /** - * Unbind thread from protection domain - * - * Free the thread's slot and update thread object. - */ - void unbind_thread(Platform_thread &thread); - - /** - * Assign parent interface to protection domain - */ - void assign_parent(Native_capability parent); - - /** - * Return portal capability selector for parent interface - */ - addr_t parent_pt_sel() { return _parent.local_name(); } - - /** - * Capability selector of this task. - * - * \return PD selector - */ - addr_t pd_sel() const { return _pd_sel; } - - /** - * Label of this protection domain - * - * \return name of this protection domain - */ - const char * name() const { return _label; } - - /***************************** - ** Address-space interface ** - *****************************/ - - void flush(addr_t, size_t, Core_local_addr) override; - }; + class Platform_pd; } + +class Core::Platform_pd : public Address_space +{ + private: + + Native_capability _parent { }; + addr_t const _pd_sel; + const char * _label; + + /* + * Noncopyable + */ + Platform_pd(Platform_pd const &); + Platform_pd &operator = (Platform_pd const &); + + public: + + bool has_any_threads = false; + + /** + * Constructors + */ + Platform_pd(Allocator &md_alloc, char const *, + signed pd_id = -1, bool create = true); + + /** + * Destructor + */ + ~Platform_pd(); + + /** + * Assign parent interface to protection domain + */ + void assign_parent(Native_capability parent); + + /** + * Return portal capability selector for parent interface + */ + addr_t parent_pt_sel() { return _parent.local_name(); } + + /** + * Capability selector of this task. + * + * \return PD selector + */ + addr_t pd_sel() const { return _pd_sel; } + + /** + * Label of this protection domain + * + * \return name of this protection domain + */ + const char * name() const { return _label; } + + /***************************** + ** Address-space interface ** + *****************************/ + + void flush(addr_t, size_t, Core_local_addr) override; +}; + #endif /* _CORE__INCLUDE__PLATFORM_PD_H_ */ diff --git a/repos/base-nova/src/core/include/platform_thread.h b/repos/base-nova/src/core/include/platform_thread.h index 7b63fda5d9..2d0bb4ae41 100644 --- a/repos/base-nova/src/core/include/platform_thread.h +++ b/repos/base-nova/src/core/include/platform_thread.h @@ -28,198 +28,189 @@ #include #include -namespace Genode { +namespace Core { class Platform_pd; - class Platform_thread - { - private: - - Platform_pd *_pd; - Pager_object *_pager; - addr_t _id_base; - addr_t _sel_exc_base; - Affinity::Location _location; - - enum { - MAIN_THREAD = 0x1U, - VCPU = 0x2U, - WORKER = 0x4U, - SC_CREATED = 0x8U, - REMOTE_PD = 0x10U, - }; - uint8_t _features; - uint8_t _priority; - - Stack::Name _name; - - addr_t _sel_ec() const { return _id_base; } - addr_t _sel_pt_oom() const { return _id_base + 1; } - addr_t _sel_sc() const { return _id_base + 2; } - - /* convenience function to access _feature variable */ - inline bool main_thread() const { return _features & MAIN_THREAD; } - inline bool vcpu() const { return _features & VCPU; } - inline bool worker() const { return _features & WORKER; } - inline bool sc_created() const { return _features & SC_CREATED; } - inline bool remote_pd() const { return _features & REMOTE_PD; } - - /* - * Noncopyable - */ - Platform_thread(Platform_thread const &); - Platform_thread &operator = (Platform_thread const &); - - /** - * Create OOM portal and delegate it - */ - bool _create_and_map_oom_portal(Nova::Utcb &); - - public: - - /* mark as vcpu in remote pd if it is a vcpu */ - addr_t remote_vcpu() { - if (!vcpu()) - return Native_thread::INVALID_INDEX; - - _features |= Platform_thread::REMOTE_PD; - return _sel_exc_base; - } - - /** - * Constructor - */ - Platform_thread(size_t quota, char const *name, - unsigned priority, - Affinity::Location affinity, - addr_t utcb); - - /** - * Destructor - */ - ~Platform_thread(); - - /** - * Start thread - * - * \param ip instruction pointer to start at - * \param sp stack pointer to use - * - * \retval 0 successful - * \retval -1 thread/vCPU could not be started - */ - int start(void *ip, void *sp); - - /** - * Pause this thread - */ - void pause(); - - /** - * Enable/disable single stepping - */ - void single_step(bool); - - /** - * Resume this thread - */ - void resume(); - - /** - * Override thread state with 's' - * - * \throw Cpu_session::State_access_failed - */ - void state(Thread_state s); - - /** - * Read thread state - * - * \throw Cpu_session::State_access_failed - */ - Thread_state state(); - - /************************ - ** Accessor functions ** - ************************/ - - /** - * Set thread type and exception portal base - */ - void thread_type(Cpu_session::Native_cpu::Thread_type thread_type, - Cpu_session::Native_cpu::Exception_base exception_base); - - /** - * Set pager - */ - void pager(Pager_object &pager); - - /** - * Return pager object - */ - Pager_object &pager() - { - if (_pager) - return *_pager; - - ASSERT_NEVER_CALLED; - } - - /** - * Return identification of thread when faulting - */ - unsigned long pager_object_badge() { return (unsigned long)this; } - - /** - * Set the executing CPU for this thread - */ - void affinity(Affinity::Location location); - - /** - * Pager_object starts migration preparation and calls for - * finalization of the migration. - * The method delegates the new exception portals to - * the protection domain and set the new acknowledged location. - */ - void prepare_migration(); - void finalize_migration(Affinity::Location const location) { - _location = location; } - - /** - * Get the executing CPU for this thread - */ - Affinity::Location affinity() const { return _location; } - - /** - * Get thread name - */ - const char *name() const { return _name.string(); } - - /** - * Get pd name - */ - const char *pd_name() const; - - /** - * Associate thread with protection domain - */ - void bind_to_pd(Platform_pd *pd, bool main_thread) - { - _pd = pd; - - if (main_thread) _features |= MAIN_THREAD; - } - - /** - * Set CPU quota of the thread to 'quota' - */ - void quota(size_t const) { /* not supported*/ } - - /** - * Return execution time consumed by the thread - */ - Trace::Execution_time execution_time() const; - }; + class Platform_thread; } + +class Core::Platform_thread +{ + private: + + Platform_pd &_pd; + Pager_object *_pager; + addr_t _id_base; + addr_t _sel_exc_base; + Affinity::Location _location; + + enum { + MAIN_THREAD = 0x1U, + VCPU = 0x2U, + WORKER = 0x4U, + SC_CREATED = 0x8U, + REMOTE_PD = 0x10U, + }; + uint8_t _features; + uint8_t _priority; + + Stack::Name _name; + + addr_t _sel_ec() const { return _id_base; } + addr_t _sel_pt_oom() const { return _id_base + 1; } + addr_t _sel_sc() const { return _id_base + 2; } + + /* convenience function to access _feature variable */ + inline bool main_thread() const { return _features & MAIN_THREAD; } + inline bool vcpu() const { return _features & VCPU; } + inline bool worker() const { return _features & WORKER; } + inline bool sc_created() const { return _features & SC_CREATED; } + inline bool remote_pd() const { return _features & REMOTE_PD; } + + /* + * Noncopyable + */ + Platform_thread(Platform_thread const &); + Platform_thread &operator = (Platform_thread const &); + + /** + * Create OOM portal and delegate it + */ + bool _create_and_map_oom_portal(Nova::Utcb &); + + public: + + /* mark as vcpu in remote pd if it is a vcpu */ + addr_t remote_vcpu() { + if (!vcpu()) + return Native_thread::INVALID_INDEX; + + _features |= Platform_thread::REMOTE_PD; + return _sel_exc_base; + } + + /** + * Constructor + */ + Platform_thread(Platform_pd &, size_t quota, char const *name, + unsigned priority, + Affinity::Location affinity, + addr_t utcb); + + /** + * Destructor + */ + ~Platform_thread(); + + /** + * Return true if thread creation succeeded + */ + bool valid() const { return true; } + + /** + * Start thread + * + * \param ip instruction pointer to start at + * \param sp stack pointer to use + */ + void start(void *ip, void *sp); + + /** + * Pause this thread + */ + void pause(); + + /** + * Enable/disable single stepping + */ + void single_step(bool); + + /** + * Resume this thread + */ + void resume(); + + /** + * Override thread state with 's' + */ + void state(Thread_state s); + + /** + * Read thread state + */ + Thread_state state(); + + /************************ + ** Accessor functions ** + ************************/ + + /** + * Set thread type and exception portal base + */ + void thread_type(Cpu_session::Native_cpu::Thread_type thread_type, + Cpu_session::Native_cpu::Exception_base exception_base); + + /** + * Set pager + */ + void pager(Pager_object &pager); + + /** + * Return pager object + */ + Pager_object &pager() + { + if (_pager) + return *_pager; + + ASSERT_NEVER_CALLED; + } + + /** + * Return identification of thread when faulting + */ + unsigned long pager_object_badge() { return (unsigned long)this; } + + /** + * Set the executing CPU for this thread + */ + void affinity(Affinity::Location location); + + /** + * Pager_object starts migration preparation and calls for + * finalization of the migration. + * The method delegates the new exception portals to + * the protection domain and set the new acknowledged location. + */ + void prepare_migration(); + void finalize_migration(Affinity::Location const location) { + _location = location; } + + /** + * Get the executing CPU for this thread + */ + Affinity::Location affinity() const { return _location; } + + /** + * Get thread name + */ + const char *name() const { return _name.string(); } + + /** + * Get pd name + */ + const char *pd_name() const; + + /** + * Set CPU quota of the thread to 'quota' + */ + void quota(size_t const) { /* not supported*/ } + + /** + * Return execution time consumed by the thread + */ + Trace::Execution_time execution_time() const; +}; + #endif /* _CORE__INCLUDE__PLATFORM_THREAD_H_ */ diff --git a/repos/base-nova/src/core/include/rpc_cap_factory.h b/repos/base-nova/src/core/include/rpc_cap_factory.h index 25179eecfd..78b37267cd 100644 --- a/repos/base-nova/src/core/include/rpc_cap_factory.h +++ b/repos/base-nova/src/core/include/rpc_cap_factory.h @@ -19,18 +19,20 @@ #include #include #include -#include -namespace Genode { class Rpc_cap_factory; } +/* core includes */ +#include + +namespace Core { class Rpc_cap_factory; } -class Genode::Rpc_cap_factory +class Core::Rpc_cap_factory { private: struct Cap_object : List::Element { - Genode::addr_t _cap_sel; + addr_t _cap_sel; Cap_object(addr_t cap_sel) : _cap_sel(cap_sel) {} }; diff --git a/repos/base-nova/src/core/include/signal_broker.h b/repos/base-nova/src/core/include/signal_broker.h index b61ee82e9f..4d5892adb6 100644 --- a/repos/base-nova/src/core/include/signal_broker.h +++ b/repos/base-nova/src/core/include/signal_broker.h @@ -20,16 +20,15 @@ /* NOVA includes */ #include -/* core-local includes */ +/* core includes */ #include #include -#include #include -namespace Genode { class Signal_broker; } +namespace Core { class Signal_broker; } -class Genode::Signal_broker +class Core::Signal_broker { private: @@ -38,7 +37,7 @@ class Genode::Signal_broker Object_pool _obj_pool { }; Rpc_entrypoint &_context_ep; Signal_source_component _source; - Signal_source_capability _source_cap; + Capability _source_cap; Signal_context_slab _context_slab { _md_alloc }; public: @@ -66,15 +65,15 @@ class Genode::Signal_broker free_context(reinterpret_cap_cast(r->cap())); } - Signal_source_capability alloc_signal_source() { return _source_cap; } + Capability alloc_signal_source() { return _source_cap; } - void free_signal_source(Signal_source_capability) { } + void free_signal_source(Capability) { } /* * \throw Allocator::Out_of_memory */ Signal_context_capability - alloc_context(Signal_source_capability, unsigned long imprint) + alloc_context(Capability, unsigned long imprint) { /* * XXX For now, we ignore the signal-source argument as we diff --git a/repos/base-nova/src/core/include/signal_source_component.h b/repos/base-nova/src/core/include/signal_source_component.h index 5eccabb9e6..65f9042241 100644 --- a/repos/base-nova/src/core/include/signal_source_component.h +++ b/repos/base-nova/src/core/include/signal_source_component.h @@ -14,18 +14,21 @@ #ifndef _CORE__INCLUDE__SIGNAL_SOURCE_COMPONENT_H_ #define _CORE__INCLUDE__SIGNAL_SOURCE_COMPONENT_H_ +/* Genode includes */ #include + +/* core includes */ #include #include -namespace Genode { +namespace Core { class Signal_context_component; class Signal_source_component; } -struct Genode::Signal_context_component : Object_pool::Entry +struct Core::Signal_context_component : Object_pool::Entry { Signal_context_component(Signal_context_capability cap) : Object_pool::Entry(cap) { } @@ -34,8 +37,8 @@ struct Genode::Signal_context_component : Object_pool: }; -class Genode::Signal_source_component : public Rpc_object +class Core::Signal_source_component : public Rpc_object { private: diff --git a/repos/base-nova/src/core/include/spec/x86_32/nova_msr.h b/repos/base-nova/src/core/include/spec/x86_32/nova_msr.h new file mode 100644 index 0000000000..35e7768230 --- /dev/null +++ b/repos/base-nova/src/core/include/spec/x86_32/nova_msr.h @@ -0,0 +1,26 @@ +/* + * \brief Guarded MSR access on NOVA + * \author Alexander Boettcher + * \date 2023-10-03 + */ + +/* + * Copyright (C) 2023 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CORE__INCLUDE__SPEC_X86_32__NOVA_MSR_H_ +#define _CORE__INCLUDE__SPEC_X86_32__NOVA_MSR_H_ + +#include + +static Genode::Pd_session::Managing_system_state msr_access(Genode::Pd_session::Managing_system_state const &, + Nova::Utcb &, + Genode::addr_t const) +{ + return { }; /* not supported for now on x86_32 */ +} + +#endif /* _CORE__INCLUDE__SPEC_X86_32__NOVA_MSR_H_ */ diff --git a/repos/base-nova/src/core/include/spec/x86_64/nova_msr.h b/repos/base-nova/src/core/include/spec/x86_64/nova_msr.h new file mode 100644 index 0000000000..b374f1b010 --- /dev/null +++ b/repos/base-nova/src/core/include/spec/x86_64/nova_msr.h @@ -0,0 +1,55 @@ +/* + * \brief Guarded MSR access on NOVA + * \author Alexander Boettcher + * \date 2023-10-03 + */ + +/* + * Copyright (C) 2023 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CORE__INCLUDE__SPEC_X86_64__NOVA_MSR_H_ +#define _CORE__INCLUDE__SPEC_X86_64__NOVA_MSR_H_ + +#include + +static Genode::Pd_session::Managing_system_state msr_access(Genode::Pd_session::Managing_system_state const &state, + Nova::Utcb &utcb, + Genode::addr_t const msr_cap) +{ + Genode::Pd_session::Managing_system_state result { }; + + utcb.set_msg_word(state.ip); /* count */ + utcb.msg()[0] = state.r8; + utcb.msg()[1] = state.r9; + utcb.msg()[2] = state.r10; + utcb.msg()[3] = state.r11; + utcb.msg()[4] = state.r12; + utcb.msg()[5] = state.r13; + utcb.msg()[6] = state.r14; + utcb.msg()[7] = state.r15; + + auto const res = Nova::ec_ctrl(Nova::Ec_op::EC_MSR_ACCESS, msr_cap); + + result.trapno = (res == Nova::NOVA_OK) ? 1 : 0; + + if (res != Nova::NOVA_OK) + return result; + + result.ip = utcb.msg_words(); /* bitmap about valid returned words */ + result.r8 = utcb.msg()[0]; + result.r9 = utcb.msg()[1]; + result.r10 = utcb.msg()[2]; + result.r11 = utcb.msg()[3]; + result.r12 = utcb.msg()[4]; + result.r13 = utcb.msg()[5]; + result.r14 = utcb.msg()[6]; + result.r15 = utcb.msg()[7]; + + return result; +} + +#endif /* _CORE__INCLUDE__SPEC_X86_64__NOVA_MSR_H_ */ diff --git a/repos/base-nova/src/core/include/util.h b/repos/base-nova/src/core/include/util.h index a504ecbe22..833ac1c4c4 100644 --- a/repos/base-nova/src/core/include/util.h +++ b/repos/base-nova/src/core/include/util.h @@ -16,31 +16,28 @@ /* Genode includes */ #include -#include /* base-internal includes */ #include #include -namespace Genode { +namespace Core { constexpr size_t get_super_page_size_log2() { return 22; } constexpr size_t get_super_page_size() { return 1 << get_super_page_size_log2(); } template - inline T trunc_page(T addr) { return addr & _align_mask(get_page_size_log2()); } + inline T trunc_page(T addr) { return addr & _align_mask(size_t(get_page_size_log2())); } template inline T round_page(T addr) { return trunc_page(addr + get_page_size() - 1); } inline addr_t map_src_addr(addr_t /* core_local */, addr_t phys) { return phys; } - - inline size_t constrain_map_size_log2(size_t size_log2) + inline Log2 kernel_constrained_map_size(Log2 size) { /* Nova::Mem_crd order has 5 bits available and is in 4K page units */ - enum { MAX_MAP_LOG2 = (1U << 5) - 1 + 12 }; - return size_log2 > MAX_MAP_LOG2 ? (size_t)MAX_MAP_LOG2 : size_log2; + return { min(size.log2, uint8_t((1 << 5) - 1 + 12)) }; } inline unsigned scale_priority(unsigned const prio, char const * name) diff --git a/repos/base-nova/src/core/include/vm_session_component.h b/repos/base-nova/src/core/include/vm_session_component.h index 363e6a41c2..e86e6636b7 100644 --- a/repos/base-nova/src/core/include/vm_session_component.h +++ b/repos/base-nova/src/core/include/vm_session_component.h @@ -22,19 +22,23 @@ #include #include -namespace Genode { class Vm_session_component; } +/* core includes */ +#include -class Genode::Vm_session_component +namespace Core { class Vm_session_component; } + + +class Core::Vm_session_component : private Ram_quota_guard, private Cap_quota_guard, - public Rpc_object, - public Region_map_detach + public Rpc_object, + private Region_map_detach { private: - typedef Constrained_ram_allocator Con_ram_allocator; - typedef Allocator_avl_tpl Avl_region; + using Con_ram_allocator = Constrained_ram_allocator; + using Avl_region = Allocator_avl_tpl; class Vcpu : public Rpc_object, public Trace::Source::Info_accessor @@ -137,6 +141,7 @@ class Genode::Vm_session_component /* helpers for vm_session_common.cc */ void _attach_vm_memory(Dataspace_component &, addr_t, Attach_attr); void _detach_vm_memory(addr_t, size_t); + void _with_region(addr_t, auto const &); protected: @@ -153,13 +158,16 @@ class Genode::Vm_session_component Trace::Source_registry &); ~Vm_session_component(); + /********************************* ** Region_map_detach interface ** *********************************/ /* used on destruction of attached dataspaces */ - void detach(Region_map::Local_addr) override; /* vm_session_common.cc */ - void unmap_region(addr_t, size_t) override; /* vm_session_common.cc */ + void detach_at(addr_t) override; + void unmap_region(addr_t, size_t) override; + void reserve_and_flush(addr_t) override; + /************************** ** Vm session interface ** @@ -168,8 +176,8 @@ class Genode::Vm_session_component Capability create_vcpu(Thread_capability); void attach_pic(addr_t) override { /* unused on NOVA */ } - void attach(Dataspace_capability, addr_t, Attach_attr) override; /* vm_session_common.cc */ - void detach(addr_t, size_t) override; /* vm_session_common.cc */ + void attach(Dataspace_capability, addr_t, Attach_attr) override; + void detach(addr_t, size_t) override; }; diff --git a/repos/base-nova/src/core/io_mem_session_support.cc b/repos/base-nova/src/core/io_mem_session_support.cc index 92f7cc6b3b..4bba83ebdc 100644 --- a/repos/base-nova/src/core/io_mem_session_support.cc +++ b/repos/base-nova/src/core/io_mem_session_support.cc @@ -18,8 +18,9 @@ #include #include -using namespace Genode; +using namespace Core; -void Io_mem_session_component::_unmap_local(addr_t, size_t) { } + +void Io_mem_session_component::_unmap_local(addr_t, size_t, addr_t) { } addr_t Io_mem_session_component::_map_local(addr_t, size_t) { return 0; } diff --git a/repos/base-nova/src/core/ipc_pager.cc b/repos/base-nova/src/core/ipc_pager.cc index 7ca36b1a75..92f1419494 100644 --- a/repos/base-nova/src/core/ipc_pager.cc +++ b/repos/base-nova/src/core/ipc_pager.cc @@ -14,14 +14,13 @@ /* Genode includes */ #include -/* Core includes */ +/* core includes */ #include /* NOVA includes */ #include - -using namespace Genode; +using namespace Core; void Mapping::prepare_map_operation() const { } diff --git a/repos/base-nova/src/core/irq_session_component.cc b/repos/base-nova/src/core/irq_session_component.cc index 2d98d3f5bc..07db078422 100644 --- a/repos/base-nova/src/core/irq_session_component.cc +++ b/repos/base-nova/src/core/irq_session_component.cc @@ -13,9 +13,6 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* Genode includes */ -#include - /* core includes */ #include #include @@ -25,7 +22,7 @@ #include #include -using namespace Genode; +using namespace Core; static bool irq_ctrl(addr_t irq_sel, addr_t &msi_addr, addr_t &msi_data, @@ -67,6 +64,9 @@ static void deassociate(addr_t irq_sel) static bool associate_msi(addr_t irq_sel, addr_t phys_mem, addr_t &msi_addr, addr_t &msi_data, Signal_context_capability sig_cap) { + if (!phys_mem) + return irq_ctrl(irq_sel, msi_addr, msi_data, sig_cap.local_name(), Nova::Gsi_flags(), 0); + return platform().region_alloc().alloc_aligned(4096, 12).convert( [&] (void *virt_ptr) { @@ -118,7 +118,7 @@ void Irq_object::sigh(Signal_context_capability cap) /* associate GSI or MSI to device belonging to device_phys */ bool ok = false; - if (_device_phys) + if (_device_phys || (_msi_addr && _msi_data)) ok = associate_msi(irq_sel(), _device_phys, _msi_addr, _msi_data, cap); else ok = associate_gsi(irq_sel(), cap, _gsi_flags); @@ -176,10 +176,10 @@ void Irq_object::start(unsigned irq, addr_t const device_phys, Irq_args const &i /* associate GSI or MSI to device belonging to device_phys */ bool ok = false; - if (device_phys) - ok = associate_msi(irq_sel(), device_phys, _msi_addr, _msi_data, _sigh_cap); - else + if (irq_args.type() == Irq_session::TYPE_LEGACY) ok = associate_gsi(irq_sel(), _sigh_cap, _gsi_flags); + else + ok = associate_msi(irq_sel(), device_phys, _msi_addr, _msi_data, _sigh_cap); if (!ok) throw Service_denied(); @@ -212,17 +212,6 @@ Irq_object::~Irq_object() ***************************/ -static Nova::Hip const &kernel_hip() -{ - /** - * Initial value of esp register, saved by the crt0 startup code. - * This value contains the address of the hypervisor information page. - */ - extern addr_t __initial_sp; - return *reinterpret_cast(__initial_sp); -} - - Irq_session_component::Irq_session_component(Range_allocator &irq_alloc, const char *args) : @@ -231,8 +220,7 @@ Irq_session_component::Irq_session_component(Range_allocator &irq_alloc, Irq_args const irq_args(args); long irq_number = irq_args.irq_number(); - long device_phys = Arg_string::find_arg(args, "device_config_phys").long_value(0); - if (device_phys) { + if (irq_args.type() != Irq_session::TYPE_LEGACY) { if ((unsigned long)irq_number >= kernel_hip().sel_gsi) throw Service_denied(); @@ -250,6 +238,7 @@ Irq_session_component::Irq_session_component(Range_allocator &irq_alloc, _irq_number = (unsigned)irq_number; + long device_phys = Arg_string::find_arg(args, "device_config_phys").long_value(0); _irq_object.start(_irq_number, device_phys, irq_args); } diff --git a/repos/base-nova/src/core/native_cpu_component.cc b/repos/base-nova/src/core/native_cpu_component.cc index f40b38e385..a809117365 100644 --- a/repos/base-nova/src/core/native_cpu_component.cc +++ b/repos/base-nova/src/core/native_cpu_component.cc @@ -11,14 +11,11 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* Genode includes */ -#include - -/* core-local includes */ +/* core includes */ #include #include -using namespace Genode; +using namespace Core; void Native_cpu_component::thread_type(Thread_capability thread_cap, @@ -43,7 +40,7 @@ Native_cpu_component::Native_cpu_component(Cpu_session_component &cpu_session, c } -Genode::Native_cpu_component::~Native_cpu_component() +Core::Native_cpu_component::~Native_cpu_component() { _thread_ep.dissolve(this); } diff --git a/repos/base-nova/src/core/native_pd_component.cc b/repos/base-nova/src/core/native_pd_component.cc index 5de829aaee..79eb442af8 100644 --- a/repos/base-nova/src/core/native_pd_component.cc +++ b/repos/base-nova/src/core/native_pd_component.cc @@ -11,13 +11,12 @@ * under the terms of the GNU Affero General Public License version 3. */ +/* core includes */ #include #include - -/* core-local includes */ #include -using namespace Genode; +using namespace Core; Native_capability Native_pd_component::alloc_rpc_cap(Native_capability ep, diff --git a/repos/base-nova/src/core/pager.cc b/repos/base-nova/src/core/pager.cc index 231d4c918e..1f8c4c7820 100644 --- a/repos/base-nova/src/core/pager.cc +++ b/repos/base-nova/src/core/pager.cc @@ -19,7 +19,7 @@ /* base-internal includes */ #include -/* core-local includes */ +/* core includes */ #include #include #include @@ -34,21 +34,10 @@ static bool verbose_oom = false; -using namespace Genode; +using namespace Core; using namespace Nova; -static Nova::Hip const &kernel_hip() -{ - /** - * Initial value of esp register, saved by the crt0 startup code. - * This value contains the address of the hypervisor information page. - */ - extern addr_t __initial_sp; - return *reinterpret_cast(__initial_sp); -} - - /** * Pager threads - one thread per CPU */ @@ -66,25 +55,26 @@ struct Pager_thread: public Thread void entry() override { } }; -enum { PAGER_CPUS = Platform::MAX_SUPPORTED_CPUS }; +enum { PAGER_CPUS = Core::Platform::MAX_SUPPORTED_CPUS }; static Constructible pager_threads[PAGER_CPUS]; -static Pager_thread &pager_thread(Affinity::Location location, - Platform &platform) +static void with_pager_thread(Affinity::Location location, + Core::Platform &platform, auto const &fn) { unsigned const pager_index = platform.pager_index(location); unsigned const kernel_cpu_id = platform.kernel_cpu_id(location); if (kernel_hip().is_cpu_enabled(kernel_cpu_id) && - pager_index < PAGER_CPUS && pager_threads[pager_index].constructed()) - return *pager_threads[pager_index]; + pager_index < PAGER_CPUS && pager_threads[pager_index].constructed()) { + + fn(*pager_threads[pager_index]); + return; + } warning("invalid CPU parameter used in pager object: ", pager_index, "->", kernel_cpu_id, " location=", location.xpos(), "x", location.ypos(), " ", location.width(), "x", location.height()); - - throw Invalid_thread(); } @@ -142,15 +132,15 @@ void Pager_object::_page_fault_handler(Pager_object &obj) */ obj._state_lock.acquire(); - obj._state.thread.ip = ipc_pager.fault_ip(); - obj._state.thread.sp = 0; - obj._state.thread.trapno = PT_SEL_PAGE_FAULT; + obj._state.thread.cpu.ip = ipc_pager.fault_ip(); + obj._state.thread.cpu.sp = 0; + obj._state.thread.cpu.trapno = PT_SEL_PAGE_FAULT; obj._state.block(); obj._state.block_pause_sm(); /* lookup fault address and decide what to do */ - int error = obj.pager(ipc_pager); + unsigned error = (obj.pager(ipc_pager) == Pager_object::Pager_result::STOP); /* don't open receive window for pager threads */ if (utcb.crd_rcv.value()) @@ -194,10 +184,6 @@ void Pager_object::_page_fault_handler(Pager_object &obj) ipc_pager.fault_addr(), ipc_pager.sp(), (uint8_t)ipc_pager.fault_type()); - - /* region manager fault - to be handled */ - log("page fault, ", fault_info, " reason=", error); - obj._state_lock.release(); /* block the faulting thread until region manager is done */ @@ -223,7 +209,7 @@ void Pager_object::exception(uint8_t exit_id) _state_lock.acquire(); /* remember exception type for Cpu_session::state() calls */ - _state.thread.trapno = exit_id; + _state.thread.cpu.trapno = exit_id; if (_exception_sigh.valid()) { _state.submit_signal(); @@ -295,7 +281,7 @@ bool Pager_object::_migrate_thread() /* syscall to migrate */ unsigned const migrate_to = platform_specific().kernel_cpu_id(_location); - uint8_t res = syscall_retry(*this, [&]() { + uint8_t res = syscall_retry(*this, [&] { return ec_ctrl(EC_MIGRATE, _state.sel_client_ec, migrate_to, Obj_crd(EC_SEL_THREAD, 0, Obj_crd::RIGHT_EC_RECALL)); }); @@ -335,7 +321,7 @@ void Pager_object::_recall_handler(Pager_object &obj) utcb.mtd = 0; /* switch on/off single step */ - bool singlestep_state = obj._state.thread.eflags & 0x100UL; + bool singlestep_state = obj._state.thread.cpu.eflags & 0x100UL; if (obj._state.singlestep() && !singlestep_state) { utcb.flags |= 0x100UL; utcb.mtd |= Mtd::EFL; @@ -492,7 +478,7 @@ void Pager_object::wake_up() if (!_state.blocked()) return; - _state.thread.exception = false; + _state.thread.state = Thread_state::State::VALID; _state.unblock(); @@ -567,7 +553,7 @@ static uint8_t create_portal(addr_t pt, addr_t pd, addr_t ec, Mtd mtd, addr_t eip, Pager_object * oom_handler) { uint8_t res = syscall_retry(*oom_handler, - [&]() { return create_pt(pt, pd, ec, mtd, eip); }); + [&] { return create_pt(pt, pd, ec, mtd, eip); }); if (res != NOVA_OK) return res; @@ -592,14 +578,18 @@ template void Exception_handlers::register_handler(Pager_object &obj, Mtd mtd, void (* __attribute__((regparm(1))) func)(Pager_object &)) { - addr_t const ec_sel = pager_thread(obj.location(), platform_specific()).native_thread().ec_sel; + uint8_t res = !Nova::NOVA_OK; + with_pager_thread(obj.location(), platform_specific(), [&] (Pager_thread &pager_thread) { + addr_t const ec_sel = pager_thread.native_thread().ec_sel; + + /* compiler generates instance of exception entry if not specified */ + addr_t entry = func ? (addr_t)func : (addr_t)(&_handler); + res = create_portal(obj.exc_pt_sel_client() + EV, + platform_specific().core_pd_sel(), ec_sel, mtd, entry, &obj); + }); - /* compiler generates instance of exception entry if not specified */ - addr_t entry = func ? (addr_t)func : (addr_t)(&_handler); - uint8_t res = create_portal(obj.exc_pt_sel_client() + EV, - platform_specific().core_pd_sel(), ec_sel, mtd, entry, &obj); if (res != Nova::NOVA_OK) - throw Invalid_thread(); + error("failed to register exception handler"); } @@ -649,9 +639,6 @@ Exception_handlers::Exception_handlers(Pager_object &obj) void Pager_object::_construct_pager() { - addr_t const pd_sel = platform_specific().core_pd_sel(); - addr_t const ec_sel = pager_thread(_location, platform_specific()).native_thread().ec_sel; - /* create portal for page-fault handler - 14 */ _exceptions.register_handler<14>(*this, Mtd::QUAL | Mtd::ESP | Mtd::EIP, _page_fault_handler); @@ -662,25 +649,36 @@ void Pager_object::_construct_pager() _exceptions.register_handler(*this, mtd_recall, _recall_handler); - /* create portal for final cleanup call used during destruction */ - uint8_t res = create_portal(sel_pt_cleanup(), pd_sel, ec_sel, Mtd(0), - reinterpret_cast(_invoke_handler), - this); + addr_t const pd_sel = platform_specific().core_pd_sel(); + + uint8_t res = !Nova::NOVA_OK; + + with_pager_thread(_location, platform_specific(), [&] (Pager_thread &pager_thread) { + + addr_t const ec_sel = pager_thread.native_thread().ec_sel; + + /* create portal for final cleanup call used during destruction */ + res = create_portal(sel_pt_cleanup(), pd_sel, ec_sel, Mtd(0), + reinterpret_cast(_invoke_handler), + this); + }); if (res != Nova::NOVA_OK) { error("could not create pager cleanup portal, error=", res); - throw Invalid_thread(); + return; } /* semaphore used to block paged thread during recall */ res = Nova::create_sm(sel_sm_block_pause(), pd_sel, 0); if (res != Nova::NOVA_OK) { - throw Invalid_thread(); + error("failed to initialize sel_sm_block_pause, error=", res); + return; } /* semaphore used to block paged thread during OOM memory revoke */ res = Nova::create_sm(sel_sm_block_oom(), pd_sel, 0); if (res != Nova::NOVA_OK) { - throw Invalid_thread(); + error("failed to initialize sel_sm_block_oom, error=", res); + return; } } @@ -704,8 +702,10 @@ Pager_object::Pager_object(Cpu_session_capability cpu_session_cap, _state.block(); if (Native_thread::INVALID_INDEX == _selectors || - Native_thread::INVALID_INDEX == _client_exc_pt_sel) - throw Invalid_thread(); + Native_thread::INVALID_INDEX == _client_exc_pt_sel) { + error("failed to complete construction of pager object"); + return; + } _construct_pager(); @@ -722,7 +722,7 @@ Pager_object::Pager_object(Cpu_session_capability cpu_session_cap, uint8_t const res = Nova::create_sm(exc_pt_sel_client() + SM_SEL_EC, pd_sel, 0); if (res != Nova::NOVA_OK) - throw Invalid_thread(); + error("failed to create locking semaphore for pager object"); } @@ -955,18 +955,19 @@ void Pager_object::_oom_handler(addr_t pager_dst, addr_t pager_src, addr_t Pager_object::create_oom_portal() { - try { - addr_t const pt_oom = sel_oom_portal(); - addr_t const core_pd_sel = platform_specific().core_pd_sel(); - Pager_thread &thread = pager_thread(_location, platform_specific()); - addr_t const ec_sel = thread.native_thread().ec_sel; + uint8_t res = !Nova::NOVA_OK; - uint8_t res = create_portal(pt_oom, core_pd_sel, ec_sel, Mtd(0), - reinterpret_cast(_oom_handler), - this); - if (res == Nova::NOVA_OK) - return pt_oom; - } catch (...) { } + with_pager_thread(_location, platform_specific(), + [&] (Pager_thread &thread) { + addr_t const core_pd_sel = platform_specific().core_pd_sel(); + addr_t const ec_sel = thread.native_thread().ec_sel; + res = create_portal(sel_oom_portal(), core_pd_sel, ec_sel, Mtd(0), + reinterpret_cast(_oom_handler), + this); + }); + + if (res == Nova::NOVA_OK) + return sel_oom_portal(); error("creating portal for out of memory notification failed"); return 0; diff --git a/repos/base-nova/src/core/pd_session_support.cc b/repos/base-nova/src/core/pd_session_support.cc index 99b0726c4f..248038b390 100644 --- a/repos/base-nova/src/core/pd_session_support.cc +++ b/repos/base-nova/src/core/pd_session_support.cc @@ -11,60 +11,48 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* core */ +/* core includes */ #include #include -using namespace Genode; +#include /* kernel_hip */ +#include +using namespace Core; -bool Pd_session_component::assign_pci(addr_t pci_config_memory, uint16_t bdf) +inline Nova::uint8_t retry_syscall(addr_t pd_sel, auto const &fn) { - uint8_t res = Nova::NOVA_PD_OOM; + Nova::uint8_t res; do { - res = Nova::assign_pci(_pd->pd_sel(), pci_config_memory, bdf); + res = fn(); } while (res == Nova::NOVA_PD_OOM && Nova::NOVA_OK == Pager_object::handle_oom(Pager_object::SRC_CORE_PD, - _pd->pd_sel(), + pd_sel, "core", "ep", Pager_object::Policy::UPGRADE_CORE_TO_DST)); - return res == Nova::NOVA_OK; + return res; +} + +bool Pd_session_component::assign_pci(addr_t pci_config_memory, uint16_t bdf) +{ + return retry_syscall(_pd->pd_sel(), [&] { + return Nova::assign_pci(_pd->pd_sel(), pci_config_memory, bdf); + }) == Nova::NOVA_OK; } -void Pd_session_component::map(addr_t virt, addr_t size) +Pd_session::Map_result Pd_session_component::map(Pd_session::Virt_range const virt_range) { - Genode::addr_t const pd_core = platform_specific().core_pd_sel(); - Platform_pd &target_pd = *_pd; - Genode::addr_t const pd_dst = target_pd.pd_sel(); - Nova::Utcb &utcb = *reinterpret_cast(Thread::myself()->utcb()); + Platform_pd &target_pd = *_pd; + Nova::Utcb &utcb = *reinterpret_cast(Thread::myself()->utcb()); + addr_t const pd_core = platform_specific().core_pd_sel(); + addr_t const pd_dst = target_pd.pd_sel(); - auto lambda = [&] (Region_map_component *region_map, - Rm_region *region, - addr_t const ds_offset, - addr_t const region_offset, - addr_t const dst_region_size) -> addr_t + auto map_memory = [&] (Mapping const &mapping) { - Dataspace_component * dsc = region ? ®ion->dataspace() : nullptr; - if (!dsc) { - struct No_dataspace{}; - throw No_dataspace(); - } - if (!region_map) { - ASSERT_NEVER_CALLED; - } - - Mapping mapping = Region_map_component::create_map_item(region_map, - *region, - ds_offset, - region_offset, - *dsc, virt, - dst_region_size); - /* asynchronously map memory */ - uint8_t err = Nova::NOVA_PD_OOM; - do { + uint8_t err = retry_syscall(_pd->pd_sel(), [&] { utcb.set_msg_word(0); bool res = utcb.append_item(nova_src_crd(mapping), 0, true, false, @@ -75,38 +63,178 @@ void Pd_session_component::map(addr_t virt, addr_t size) /* one item ever fits on the UTCB */ (void)res; - err = Nova::delegate(pd_core, pd_dst, nova_dst_crd(mapping)); - - } while (err == Nova::NOVA_PD_OOM && - Nova::NOVA_OK == Pager_object::handle_oom(Pager_object::SRC_CORE_PD, - _pd->pd_sel(), - "core", "ep", - Pager_object::Policy::UPGRADE_CORE_TO_DST)); - - addr_t const map_size = 1UL << mapping.size_log2; - addr_t const mapped = mapping.dst_addr + map_size - virt; + return Nova::delegate(pd_core, pd_dst, nova_dst_crd(mapping)); + }); if (err != Nova::NOVA_OK) { - error("could not map memory ", - Hex_range(mapping.dst_addr, map_size) , " " - "eagerly error=", err); + error("could not eagerly map memory ", + Hex_range(mapping.dst_addr, 1UL << mapping.size_log2) , " " + "error=", err); } - - return mapped; }; + addr_t virt = virt_range.start; + size_t size = virt_range.num_bytes; try { while (size) { - addr_t mapped = _address_space.apply_to_dataspace(virt, lambda); - virt += mapped; - size = size < mapped ? size : size - mapped; + + Fault const artificial_fault { + .hotspot = { virt }, + .access = Access::READ, + .rwx = Rwx::rwx(), + .bounds = { .start = 0, .end = ~0UL }, + }; + + _address_space.with_mapping_for_fault(artificial_fault, + [&] (Mapping const &mapping) + { + map_memory(mapping); + + size_t const mapped_bytes = 1 << mapping.size_log2; + + virt += mapped_bytes; + size = size < mapped_bytes ? 0 : size - mapped_bytes; + }, + + [&] (Region_map_component &, Fault const &) { /* don't reflect */ } + ); } - } catch (...) { + } + catch (Out_of_ram) { return Map_result::OUT_OF_RAM; } + catch (Out_of_caps) { return Map_result::OUT_OF_CAPS; } + catch (...) { error(__func__, " failed ", Hex(virt), "+", Hex(size)); } + return Map_result::OK; } using State = Genode::Pd_session::Managing_system_state; -State Pd_session_component::managing_system(State const &) { return State(); } + +class System_control_component : public Genode::Rpc_object +{ + public: + + State system_control(State const &) override; +}; + + +class System_control_impl : public Core::System_control +{ + private: + + System_control_component objects [Core::Platform::MAX_SUPPORTED_CPUS] { }; + + auto with_location(auto const &location, auto const &fn) + { + unsigned const index = platform_specific().pager_index(location); + + if (index < Core::Platform::MAX_SUPPORTED_CPUS) + return fn (objects[index]); + + return Capability { }; + } + + auto with_location(auto const &location, auto const &fn) const + { + unsigned const index = platform_specific().pager_index(location); + + if (index < Core::Platform::MAX_SUPPORTED_CPUS) + return fn (objects[index]); + + return Capability { }; + } + + public: + + Capability control_cap(Affinity::Location const) const override; + + void manage(Rpc_entrypoint &ep, Affinity::Location const &location) + { + with_location(location, [&](auto &object) { + ep.manage(&object); + return object.cap(); + }); + } + +}; + + +static System_control_impl &system_instance() +{ + static System_control_impl system_control { }; + return system_control; +} + + +System_control & Core::init_system_control(Allocator &alloc, Rpc_entrypoint &) +{ + enum { ENTRYPOINT_STACK_SIZE = 20 * 1024 }; + + platform_specific().for_each_location([&](Affinity::Location const &location) { + + unsigned const kernel_cpu_id = platform_specific().kernel_cpu_id(location); + + if (!kernel_hip().is_cpu_enabled(kernel_cpu_id)) + return; + + auto ep = new (alloc) Rpc_entrypoint (nullptr, ENTRYPOINT_STACK_SIZE, + "system_control", location); + + system_instance().manage(*ep, location); + }); + + return system_instance(); +}; + + +Capability System_control_impl::control_cap(Affinity::Location const location) const +{ + return with_location(location, [&](auto &object) { + return object.cap(); + }); +} + + +static State acpi_suspend(State const &request) +{ + State respond { .trapno = 0 }; + + /* + * The trapno/ip/sp registers used below are just convention to transfer + * the intended sleep state S0 ... S5. The values are read out by an + * ACPI AML component and are of type TYP_SLPx as described in the + * ACPI specification, e.g. TYP_SLPa and TYP_SLPb. The values differ + * between different PC systems/boards. + * + * \note trapno/ip/sp registers are chosen because they exist in + * Managing_system_state for x86_32 and x86_64. + */ + uint8_t const sleep_type_a = uint8_t(request.ip); + uint8_t const sleep_type_b = uint8_t(request.sp); + + auto const cap_suspend = platform_specific().core_pd_sel() + 3; + auto const result = Nova::acpi_suspend(cap_suspend, sleep_type_a, + sleep_type_b); + + if (result == Nova::NOVA_OK) + respond.trapno = 1 /* success, which means we resumed already */; + + return respond; +} + + +State System_control_component::system_control(State const &request) +{ + if (request.trapno == State::ACPI_SUSPEND_REQUEST) + return acpi_suspend(request); + + if (request.trapno == State::MSR_ACCESS) { + auto const msr_cap = platform_specific().core_pd_sel() + 4; + Nova::Utcb &utcb = *reinterpret_cast(Thread::myself()->utcb()); + return msr_access(request, utcb, msr_cap); + } + + return State(); +} diff --git a/repos/base-nova/src/core/platform.cc b/repos/base-nova/src/core/platform.cc index 5f3fd0f711..ca974d40dd 100644 --- a/repos/base-nova/src/core/platform.cc +++ b/repos/base-nova/src/core/platform.cc @@ -7,7 +7,7 @@ */ /* - * Copyright (C) 2009-2017 Genode Labs GmbH + * Copyright (C) 2009-2022 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -40,7 +40,7 @@ #include #include -using namespace Genode; +using namespace Core; using namespace Nova; @@ -74,8 +74,8 @@ extern unsigned _prog_img_beg, _prog_img_end; * This function uses the virtual-memory region allocator to find a region * fitting the desired mapping. Other allocators are left alone. */ -addr_t Platform::_map_pages(addr_t const phys_addr, addr_t const pages, - bool guard_page) +addr_t Core::Platform::_map_pages(addr_t const phys_addr, addr_t const pages, + bool guard_page) { addr_t const size = pages << get_page_size_log2(); @@ -280,7 +280,7 @@ static Affinity::Space setup_affinity_space(Hip const &hip) { unsigned cpus = 0; unsigned ids_thread = 0; - Genode::Bit_array<1 << (sizeof(Hip::Cpu_desc::thread) * 8)> threads; + Bit_array<1 << (sizeof(Hip::Cpu_desc::thread) * 8)> threads; hip.for_each_enabled_cpu([&](Hip::Cpu_desc const &cpu, unsigned) { cpus ++; @@ -301,17 +301,19 @@ static Affinity::Space setup_affinity_space(Hip const &hip) ** Platform ** **************/ -Platform::Platform() +Core::Platform::Platform() : _io_mem_alloc(&core_mem_alloc()), _io_port_alloc(&core_mem_alloc()), _irq_alloc(&core_mem_alloc()), _vm_base(0x1000), _vm_size(0), _cpus(Affinity::Space(1,1)) { - Hip const &hip = *(Hip *)__initial_sp; - /* check for right API version */ - if (hip.api_version != 8) - nova_die(); + bool warn_reorder = false; + bool error_overlap = false; + Hip const &hip = *(Hip *)__initial_sp; + + + _cpus = setup_affinity_space(hip); /* register UTCB of main thread */ __main_thread_utcb = (Utcb *)(__initial_sp - get_page_size()); @@ -339,13 +341,6 @@ Platform::Platform() /* determine number of available CPUs */ _cpus = setup_affinity_space(hip); - /* - * Mark successful boot of hypervisor for automatic tests. This must be - * done before core_log is initialized to prevent unexpected-reboot - * detection. - */ - log("\nHypervisor ", String((char const *)&hip.signature), - " (API v", hip.api_version, ")"); /* * remap main utcb to default utcb address @@ -355,41 +350,20 @@ Platform::Platform() if (map_local(_core_pd_sel, *__main_thread_utcb, (addr_t)__main_thread_utcb, (addr_t)main_thread_utcb(), 1, Rights(true, true, false))) { error("could not remap utcb of main thread"); - nova_die(); } - /* sanity checks */ - if (hip.sel_exc + 3 > NUM_INITIAL_PT_RESERVED) { - error("configuration error (NUM_INITIAL_PT_RESERVED)"); - nova_die(); - } + /* + * Mark successful boot of hypervisor for automatic tests. This must be + * done before core_log is initialized to prevent unexpected-reboot + * detection. + */ + log("\nHypervisor ", String((char const *)&hip.signature), + " (API v", hip.api_version, ")"); /* init genode cpu ids based on kernel cpu ids (used for syscalls) */ - if (sizeof(map_cpu_ids) / sizeof(map_cpu_ids[0]) < hip.cpu_max()) { - error("number of max CPUs is larger than expected - ", hip.cpu_max(), - " vs ", sizeof(map_cpu_ids) / sizeof(map_cpu_ids[0])); - nova_die(); - } - if (!hip.remap_cpu_ids(map_cpu_ids, cpu_numa_map, (unsigned)boot_cpu())) { - error("re-ording cpu_id failed"); - nova_die(); - } - - /* map idle SCs */ - unsigned const log2cpu = log2(hip.cpu_max()); - if ((1U << log2cpu) != hip.cpu_max()) { - error("number of max CPUs is not of power of 2"); - nova_die(); - } - - addr_t sc_idle_base = cap_map().insert(log2cpu + 1); - if (sc_idle_base & ((1UL << log2cpu) - 1)) { - error("unaligned sc_idle_base value ", Hex(sc_idle_base)); - nova_die(); - } - if (map_local(_core_pd_sel, *__main_thread_utcb, Obj_crd(0, log2cpu), - Obj_crd(sc_idle_base, log2cpu), true)) - nova_die(); + warn_reorder = !hip.remap_cpu_ids(map_cpu_ids, + sizeof(map_cpu_ids) / sizeof(map_cpu_ids[0]), cpu_numa_map, + (unsigned)boot_cpu()); /* configure virtual address spaces */ #ifdef __x86_64__ @@ -423,16 +397,6 @@ Platform::Platform() size_t const core_size = binaries_beg - core_virt_beg; region_alloc().remove_range(core_virt_beg, core_size); - if (verbose_boot_info || binaries_end != core_virt_end) { - log("core image ", - Hex_range(core_virt_beg, core_virt_end - core_virt_beg)); - log("binaries region ", - Hex_range(binaries_beg, binaries_end - binaries_beg), - " free for reuse"); - } - if (binaries_end != core_virt_end) - nova_die(); - /* ROM modules are un-used by core - de-detach region */ addr_t const binaries_size = binaries_end - binaries_beg; unmap_local(*__main_thread_utcb, binaries_beg, binaries_size >> 12); @@ -466,7 +430,8 @@ Platform::Platform() Hex_range(stack_area_virtual_base(), stack_area_virtual_size()), " vs ", Hex(check[i])); - nova_die(); + + error_overlap = true; } } @@ -496,13 +461,6 @@ Platform::Platform() if (mem_desc->type != Hip::Mem_desc::AVAILABLE_MEMORY) continue; - if (verbose_boot_info) { - uint64_t const base = mem_desc->addr; - uint64_t const size = mem_desc->size; - log("detected physical memory: ", Hex(base, Hex::PREFIX, Hex::PAD), - " - size: ", Hex(size, Hex::PREFIX, Hex::PAD), " - node: ", mem_desc->domain, " type: ", static_cast(mem_desc->type)); - } - if (!mem_desc->size) continue; /* skip regions above 4G on 32 bit, no op on 64 bit */ @@ -516,10 +474,6 @@ Platform::Platform() else size = trunc_page(mem_desc->addr + mem_desc->size) - base; - if (verbose_boot_info) - log("use physical memory: ", Hex(base, Hex::PREFIX, Hex::PAD), - " - size: ", Hex(size, Hex::PREFIX, Hex::PAD)); - _io_mem_alloc.remove_range((addr_t)base, (size_t)size); ram_alloc().add_range((addr_t)base, (size_t)size); } @@ -552,10 +506,6 @@ Platform::Platform() size = pitch * height; } - if (verbose_boot_info) - log("reserved memory: ", Hex(mem_desc->addr), " - size: ", - Hex(size), " type=", (int)mem_desc->type); - /* skip regions above 4G on 32 bit, no op on 64 bit */ if (mem_desc->addr > ~0UL) continue; @@ -624,7 +574,8 @@ Platform::Platform() "(", (int)mem_desc->type, ") with ", Hex_range((addr_t)mem_d->addr, (size_t)mem_d->size), " " "(", (int)mem_d->type, ")"); - nova_die(); + + error_overlap = true; } } @@ -671,9 +622,8 @@ Platform::Platform() memset(core_local_ptr, 0, bytes); content_fn(core_local_ptr, bytes); - _rom_fs.insert(new (core_mem_alloc()) - Rom_module(phys_addr, bytes, rom_name)); - log("ROM succesfully inserted."); + new (core_mem_alloc()) + Rom_module(_rom_fs, rom_name, phys_addr, bytes); /* leave the ROM backing store mapped within core */ }, @@ -683,26 +633,22 @@ Platform::Platform() rom_name, " as ROM module"); }); }; - export_pages_as_rom_module("platform_info", 37, - [&](char *const ptr, size_t const size) - { - log("Exporting platform info as ROM module"); - Xml_generator xml(ptr, size, "platform_info", [&]() - { - log("Report kernel"); - xml.node("kernel", [&] () { + export_pages_as_rom_module("platform_info", 1 + (MAX_SUPPORTED_CPUS / 32), + [&] (char * const ptr, size_t const size) { + Xml_generator xml(ptr, size, "platform_info", [&] + { + xml.node("kernel", [&] { xml.attribute("name", "nova"); xml.attribute("acpi", true); xml.attribute("msi" , true); + xml.attribute("iommu", hip.has_feature_iommu()); }); - if (efi_sys_tab_phy) - { - log("Report EFI system table"); - xml.node("efi-system-table", [&] () { + if (efi_sys_tab_phy) { + xml.node("efi-system-table", [&] { xml.attribute("address", String<32>(Hex(efi_sys_tab_phy))); }); } - xml.node("acpi", [&] () { + xml.node("acpi", [&] { log("Report ACPI"); xml.attribute("revision", 2); /* XXX */ @@ -713,49 +659,49 @@ Platform::Platform() if (xsdt) xml.attribute("xsdt", String<32>(Hex(xsdt))); }); - - log("Report Affinity-space"); - xml.node("affinity-space", [&] () { + xml.node("affinity-space", [&] { xml.attribute("width", _cpus.width()); xml.attribute("height", _cpus.height()); }); - log("Report boot framebuffer"); - xml.node("boot", [&]() - { + xml.node("boot", [&] { if (!boot_fb) return; if (!efi_boot && (Resolution::Type::get(boot_fb->size) != Resolution::Type::VGA_TEXT)) return; - xml.node("framebuffer", [&] () { + xml.node("framebuffer", [&] { xml.attribute("phys", String<32>(Hex(boot_fb->addr))); xml.attribute("width", Resolution::Width::get(boot_fb->size)); xml.attribute("height", Resolution::Height::get(boot_fb->size)); xml.attribute("bpp", Resolution::Bpp::get(boot_fb->size)); xml.attribute("type", Resolution::Type::get(boot_fb->size)); xml.attribute("pitch", boot_fb->aux); - }); }); - log("Report Hardware"); - xml.node("hardware", [&] () { - log("Report HW features"); - xml.node("features", [&] () { + }); + }); + xml.node("hardware", [&] { + xml.node("features", [&] { xml.attribute("svm", hip.has_feature_svm()); xml.attribute("vmx", hip.has_feature_vmx()); }); - log("Report TSC"); - xml.node("tsc", [&] () { + xml.node("tsc", [&] { xml.attribute("invariant", cpuid_invariant_tsc()); xml.attribute("freq_khz" , hip.tsc_freq); }); - log("Report CPUs"); - xml.node("cpus", [&]() - { - hip.for_each_enabled_cpu([&](Hip::Cpu_desc const &cpu, unsigned i) - { - xml.node("cpu", [&]() - { - xml.attribute("id", i); + xml.node("cpus", [&] { + for_each_location([&](Affinity::Location &location) { + unsigned const kernel_cpu_id = Platform::kernel_cpu_id(location); + auto const cpu_ptr = hip.cpu_desc_of_cpu(kernel_cpu_id); + + if (!cpu_ptr) + return; + + auto const &cpu = *cpu_ptr; + + xml.node("cpu", [&] { + xml.attribute("xpos", location.xpos()); + xml.attribute("ypos", location.ypos()); + xml.attribute("id", kernel_cpu_id); xml.attribute("package", cpu.package); xml.attribute("core", cpu.core); xml.attribute("thread", cpu.thread); @@ -763,10 +709,16 @@ Platform::Platform() xml.attribute("model", String<5>(Hex(cpu.model))); xml.attribute("stepping", String<5>(Hex(cpu.stepping))); xml.attribute("platform", String<5>(Hex(cpu.platform))); - xml.attribute("patch", String<12>(Hex(cpu.patch))); }); }); }); - }); }); - log("Exported platform info, succesfully."); - }); + xml.attribute("patch", String<12>(Hex(cpu.patch))); + if (cpu.p_core()) xml.attribute("cpu_type", "P"); + if (cpu.e_core()) xml.attribute("cpu_type", "E"); + }); + }); + }); + }); + }); + } + ); export_pages_as_rom_module("core_log", 4, [&](char *const ptr, size_t const size) @@ -776,10 +728,33 @@ Platform::Platform() /* export hypervisor log memory */ if (hyp_log && hyp_log_size) - _rom_fs.insert(new (core_mem_alloc()) Rom_module(hyp_log, hyp_log_size, - "kernel_log")); + new (core_mem_alloc()) + Rom_module(_rom_fs, "kernel_log", hyp_log, hyp_log_size); + + /* show all warnings/errors after init_core_log setup core_log */ + if (warn_reorder) + warning("re-ordering of CPU ids for SMT and P/E cores failed"); + if (hip.api_version != 10) + error("running on a unsupported kernel API version ", hip.api_version); + if (binaries_end != core_virt_end) + error("mismatch in address layout of binaries with core"); + if (error_overlap) + error("memory overlap issues detected"); + if (hip.sel_exc + 3 > NUM_INITIAL_PT_RESERVED) + error("configuration error (NUM_INITIAL_PT_RESERVED)"); + + /* map idle SCs */ + auto const log2cpu = log2(hip.cpu_max()); + auto const sc_idle_base = cap_map().insert(log2cpu + 1); + + if (map_local(_core_pd_sel, *__main_thread_utcb, Obj_crd(0, log2cpu), + Obj_crd(sc_idle_base, log2cpu), true)) + error("idle SC information unavailable"); + if (verbose_boot_info) { + if (hip.has_feature_iommu()) + log("Hypervisor features IOMMU"); if (hip.has_feature_vmx()) log("Hypervisor features VMX"); if (hip.has_feature_svm()) @@ -798,11 +773,13 @@ Platform::Platform() Genode::String<16> text ("failure"); if (cpu) text = Genode::String<16>(cpu->package, ":", - cpu->core, ":", cpu->thread); + cpu->core, ":", cpu->thread, + cpu->e_core() ? " E" : + cpu->p_core() ? " P" : ""); log(" remap (", location.xpos(), "x", location.ypos(),") -> ", - kernel_cpu_id, " - ", text, " node: ", cpu->numa_id, ") ", - boot_cpu() == kernel_cpu_id ? "boot cpu" : ""); + kernel_cpu_id, " - ", text, " node: ", cpu->numa_id, + boot_cpu() == kernel_cpu_id ? " boot cpu" : ""); }); } @@ -979,13 +956,13 @@ Platform::Platform() } -addr_t Platform::_rom_module_phys(addr_t virt) +addr_t Core::Platform::_rom_module_phys(addr_t virt) { return virt - (addr_t)&_prog_img_beg + _core_phys_start; } -unsigned Platform::kernel_cpu_id(Affinity::Location location) const +unsigned Core::Platform::kernel_cpu_id(Affinity::Location location) const { unsigned const cpu_id = pager_index(location); @@ -998,7 +975,7 @@ unsigned Platform::kernel_cpu_id(Affinity::Location location) const } -unsigned Platform::pager_index(Affinity::Location location) const +unsigned Core::Platform::pager_index(Affinity::Location location) const { return (location.xpos() * _cpus.height() + location.ypos()) % (_cpus.width() * _cpus.height()); @@ -1013,7 +990,7 @@ bool Mapped_mem_allocator::_map_local(addr_t virt_addr, addr_t phys_addr, size_t { /* platform_specific()->core_pd_sel() deadlocks if called from platform constructor */ Hip const &hip = *(Hip const *)__initial_sp; - Genode::addr_t const core_pd_sel = hip.sel_exc; + addr_t const core_pd_sel = hip.sel_exc; map_local(core_pd_sel, *(Utcb *)Thread::myself()->utcb(), phys_addr, @@ -1035,5 +1012,5 @@ bool Mapped_mem_allocator::_unmap_local(addr_t virt_addr, addr_t, size_t size) ** Generic platform interface ** ********************************/ -void Platform::wait_for_exit() { sleep_forever(); } +void Core::Platform::wait_for_exit() { sleep_forever(); } diff --git a/repos/base-nova/src/core/platform_pd.cc b/repos/base-nova/src/core/platform_pd.cc index 705889e8e1..8277126acb 100644 --- a/repos/base-nova/src/core/platform_pd.cc +++ b/repos/base-nova/src/core/platform_pd.cc @@ -12,32 +12,13 @@ */ /* Genode includes */ -#include #include /* core includes */ #include #include -using namespace Genode; - - -/*************************** - ** Public object members ** - ***************************/ - -bool Platform_pd::bind_thread(Platform_thread &thread) -{ - thread.bind_to_pd(this, _thread_cnt == 0); - _thread_cnt++; - return true; -} - - -void Platform_pd::unbind_thread(Platform_thread &) -{ - warning(__func__, "not implemented"); -} +using namespace Core; void Platform_pd::assign_parent(Native_capability parent) @@ -48,7 +29,8 @@ void Platform_pd::assign_parent(Native_capability parent) Platform_pd::Platform_pd(Allocator &, char const *label, signed, bool) -: _thread_cnt(0), _pd_sel(cap_map().insert()), _label(label) +: + _pd_sel(cap_map().insert()), _label(label) { if (_pd_sel == Native_thread::INVALID_INDEX) { error("platform pd creation failed "); diff --git a/repos/base-nova/src/core/platform_services.cc b/repos/base-nova/src/core/platform_services.cc index 94b42c59dd..f0df7a79a5 100644 --- a/repos/base-nova/src/core/platform_services.cc +++ b/repos/base-nova/src/core/platform_services.cc @@ -20,10 +20,10 @@ /* * Add x86 specific services */ -void Genode::platform_add_local_services(Rpc_entrypoint &ep, - Sliced_heap &heap, - Registry &services, - Trace::Source_registry &trace_sources) +void Core::platform_add_local_services(Rpc_entrypoint &ep, + Sliced_heap &heap, + Registry &services, + Trace::Source_registry &trace_sources) { static Vm_root vm_root(ep, heap, core_env().ram_allocator(), core_env().local_rm(), trace_sources); diff --git a/repos/base-nova/src/core/platform_thread.cc b/repos/base-nova/src/core/platform_thread.cc index dede726d2e..5175812aae 100644 --- a/repos/base-nova/src/core/platform_thread.cc +++ b/repos/base-nova/src/core/platform_thread.cc @@ -13,9 +13,6 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* Genode includes */ -#include - /* core includes */ #include #include @@ -31,7 +28,7 @@ #include #include -using namespace Genode; +using namespace Core; static uint8_t map_thread_portals(Pager_object &pager, @@ -101,21 +98,20 @@ void Platform_thread::prepare_migration() } -int Platform_thread::start(void *ip, void *sp) +void Platform_thread::start(void *ip, void *sp) { using namespace Nova; if (!_pager) { error("pager undefined"); - return -1; + return; } Pager_object &pager = *_pager; - if (!_pd || (main_thread() && !vcpu() && - _pd->parent_pt_sel() == Native_thread::INVALID_INDEX)) { + if (main_thread() && !vcpu() && (_pd.parent_pt_sel() == Native_thread::INVALID_INDEX)) { error("protection domain undefined"); - return -2; + return; } Utcb &utcb = *reinterpret_cast(Thread::myself()->utcb()); @@ -124,7 +120,7 @@ int Platform_thread::start(void *ip, void *sp) if (!_create_and_map_oom_portal(utcb)) { error("setup of out-of-memory notification portal - failed"); - return -8; + return; } if (!main_thread()) { @@ -133,19 +129,19 @@ int Platform_thread::start(void *ip, void *sp) if (_sel_exc_base == Native_thread::INVALID_INDEX) { error("exception base not specified"); - return -3; + return; } uint8_t res = syscall_retry(pager, - [&]() { - return create_ec(_sel_ec(), _pd->pd_sel(), kernel_cpu_id, + [&] { + return create_ec(_sel_ec(), _pd.pd_sel(), kernel_cpu_id, utcb_addr, initial_sp, _sel_exc_base, !worker()); }); if (res != Nova::NOVA_OK) { error("creation of new thread failed ", res); - return -4; + return; } if (!vcpu()) @@ -154,7 +150,7 @@ int Platform_thread::start(void *ip, void *sp) if (res != NOVA_OK) { revoke(Obj_crd(_sel_ec(), 0)); error("creation of new thread/vcpu failed ", res); - return -3; + return; } if (worker()) { @@ -165,13 +161,12 @@ int Platform_thread::start(void *ip, void *sp) pager.initial_eip((addr_t)ip); pager.initial_esp(initial_sp); pager.client_set_ec(_sel_ec()); - - return 0; + return; } if (!vcpu() && _sel_exc_base != Native_thread::INVALID_INDEX) { error("thread already started"); - return -5; + return; } addr_t pd_utcb = 0; @@ -181,7 +176,7 @@ int Platform_thread::start(void *ip, void *sp) pd_utcb = stack_area_virtual_base() + stack_virtual_size() - get_page_size(); - addr_t remap_src[] = { _pd->parent_pt_sel() }; + addr_t remap_src[] = { _pd.parent_pt_sel() }; addr_t remap_dst[] = { PT_SEL_PARENT }; /* remap exception portals for first thread */ @@ -189,18 +184,18 @@ int Platform_thread::start(void *ip, void *sp) if (map_local(source_pd, utcb, Obj_crd(remap_src[i], 0), Obj_crd(pager.exc_pt_sel_client() + remap_dst[i], 0))) - return -6; + return; } } /* create first thread in task */ enum { THREAD_GLOBAL = true }; - uint8_t res = create_ec(_sel_ec(), _pd->pd_sel(), kernel_cpu_id, + uint8_t res = create_ec(_sel_ec(), _pd.pd_sel(), kernel_cpu_id, pd_utcb, 0, _sel_exc_base, THREAD_GLOBAL); if (res != NOVA_OK) { error("create_ec returned ", res); - return -7; + return; } pager.client_set_ec(_sel_ec()); @@ -214,9 +209,9 @@ int Platform_thread::start(void *ip, void *sp) if (res == NOVA_OK) { res = syscall_retry(pager, - [&]() { + [&] { /* let the thread run */ - return create_sc(_sel_sc(), _pd->pd_sel(), _sel_ec(), + return create_sc(_sel_sc(), _pd.pd_sel(), _sel_ec(), Qpd(Qpd::DEFAULT_QUANTUM, _priority)); }); } @@ -230,12 +225,10 @@ int Platform_thread::start(void *ip, void *sp) /* cap_selector free for _sel_ec is done in de-constructor */ revoke(Obj_crd(_sel_ec(), 0)); - return -8; + return; } _features |= SC_CREATED; - - return 0; } @@ -258,14 +251,14 @@ void Platform_thread::resume() return; } - if (!_pd || !_pager) { - error("protection domain undefined - resuming thread failed"); + if (!_pager) { + error("pager undefined - resuming thread failed"); return; } uint8_t res = syscall_retry(*_pager, - [&]() { - return create_sc(_sel_sc(), _pd->pd_sel(), _sel_ec(), + [&] { + return create_sc(_sel_sc(), _pd.pd_sel(), _sel_ec(), Qpd(Qpd::DEFAULT_QUANTUM, _priority)); }); @@ -278,26 +271,19 @@ void Platform_thread::resume() Thread_state Platform_thread::state() { - if (!_pager) throw Cpu_thread::State_access_failed(); - - Thread_state s; - - if (_pager->copy_thread_state(&s)) + Thread_state s { }; + if (_pager && _pager->copy_thread_state(&s)) return s; - throw Cpu_thread::State_access_failed(); + return { .state = Thread_state::State::UNAVAILABLE, .cpu = { } }; } void Platform_thread::state(Thread_state s) { - if (!_pager) throw Cpu_thread::State_access_failed(); - - if (!_pager->copy_thread_state(s)) - throw Cpu_thread::State_access_failed(); - - /* the new state is transferred to the kernel by the recall handler */ - _pager->client_recall(false); + if (_pager && _pager->copy_thread_state(s)) + /* the new state is transferred to the kernel by the recall handler */ + _pager->client_recall(false); } @@ -308,8 +294,8 @@ void Platform_thread::single_step(bool on) _pager->single_step(on); } -const char * Platform_thread::pd_name() const { - return _pd ? _pd->name() : "unknown"; } + +const char * Platform_thread::pd_name() const { return _pd.name(); } Trace::Execution_time Platform_thread::execution_time() const @@ -336,7 +322,7 @@ Trace::Execution_time Platform_thread::execution_time() const void Platform_thread::pager(Pager_object &pager) { _pager = &pager; - _pager->assign_pd(_pd->pd_sel()); + _pager->assign_pd(_pd.pd_sel()); } @@ -357,16 +343,21 @@ void Platform_thread::thread_type(Cpu_session::Native_cpu::Thread_type thread_ty } -Platform_thread::Platform_thread(size_t, const char *name, unsigned prio, - Affinity::Location affinity, addr_t) +Platform_thread::Platform_thread(Platform_pd &pd, size_t, const char *name, + unsigned prio, Affinity::Location affinity, addr_t) : - _pd(0), _pager(0), _id_base(cap_map().insert(2)), + _pd(pd), _pager(0), _id_base(cap_map().insert(2)), _sel_exc_base(Native_thread::INVALID_INDEX), _location(platform_specific().sanitize(affinity)), _features(0), _priority((uint8_t)(scale_priority(prio, name))), _name(name) -{ } +{ + if (!pd.has_any_threads) + _features |= MAIN_THREAD; + + pd.has_any_threads = true; +} Platform_thread::~Platform_thread() diff --git a/repos/base-nova/src/core/ram_dataspace_support.cc b/repos/base-nova/src/core/ram_dataspace_support.cc index a850892905..fbc0cb1c62 100644 --- a/repos/base-nova/src/core/ram_dataspace_support.cc +++ b/repos/base-nova/src/core/ram_dataspace_support.cc @@ -23,7 +23,7 @@ /* NOVA includes */ #include -using namespace Genode; +using namespace Core; void Ram_dataspace_factory::_revoke_ram_ds(Dataspace_component &) { } diff --git a/repos/base-nova/src/core/rpc_cap_factory.cc b/repos/base-nova/src/core/rpc_cap_factory.cc index d929b7aac4..8e77e6611d 100644 --- a/repos/base-nova/src/core/rpc_cap_factory.cc +++ b/repos/base-nova/src/core/rpc_cap_factory.cc @@ -11,14 +11,14 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* core-local includes */ +/* core includes */ #include #include /* NOVA includes */ #include -using namespace Genode; +using namespace Core; Native_capability Rpc_cap_factory::alloc(Native_capability ep, addr_t entry, addr_t mtd) diff --git a/repos/base-nova/src/core/spec/x86_32/pager.cc b/repos/base-nova/src/core/spec/x86_32/pager.cc index e0bb2652c4..176969fdfd 100644 --- a/repos/base-nova/src/core/spec/x86_32/pager.cc +++ b/repos/base-nova/src/core/spec/x86_32/pager.cc @@ -11,51 +11,52 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* Core includes */ +/* core includes */ #include /* NOVA includes */ #include -using namespace Genode; +using namespace Core; void Pager_object::_copy_state_from_utcb(Nova::Utcb const &utcb) { - _state.thread.eax = utcb.ax; - _state.thread.ecx = utcb.cx; - _state.thread.edx = utcb.dx; - _state.thread.ebx = utcb.bx; + _state.thread.cpu.eax = utcb.ax; + _state.thread.cpu.ecx = utcb.cx; + _state.thread.cpu.edx = utcb.dx; + _state.thread.cpu.ebx = utcb.bx; - _state.thread.ebp = utcb.bp; - _state.thread.esi = utcb.si; - _state.thread.edi = utcb.di; + _state.thread.cpu.ebp = utcb.bp; + _state.thread.cpu.esi = utcb.si; + _state.thread.cpu.edi = utcb.di; - _state.thread.sp = utcb.sp; - _state.thread.ip = utcb.ip; - _state.thread.eflags = utcb.flags; + _state.thread.cpu.sp = utcb.sp; + _state.thread.cpu.ip = utcb.ip; + _state.thread.cpu.eflags = utcb.flags; - _state.thread.exception = utcb.qual[0]; + _state.thread.state = utcb.qual[0] ? Thread_state::State::EXCEPTION + : Thread_state::State::VALID; } void Pager_object::_copy_state_to_utcb(Nova::Utcb &utcb) const { - utcb.ax = _state.thread.eax; - utcb.cx = _state.thread.ecx; - utcb.dx = _state.thread.edx; - utcb.bx = _state.thread.ebx; + utcb.ax = _state.thread.cpu.eax; + utcb.cx = _state.thread.cpu.ecx; + utcb.dx = _state.thread.cpu.edx; + utcb.bx = _state.thread.cpu.ebx; - utcb.bp = _state.thread.ebp; - utcb.si = _state.thread.esi; - utcb.di = _state.thread.edi; + utcb.bp = _state.thread.cpu.ebp; + utcb.si = _state.thread.cpu.esi; + utcb.di = _state.thread.cpu.edi; - utcb.sp = _state.thread.sp; - utcb.ip = _state.thread.ip; - utcb.flags = _state.thread.eflags; + utcb.sp = _state.thread.cpu.sp; + utcb.ip = _state.thread.cpu.ip; + utcb.flags = _state.thread.cpu.eflags; utcb.mtd = Nova::Mtd::ACDB | - Nova::Mtd::EBSD | - Nova::Mtd::ESP | - Nova::Mtd::EIP | - Nova::Mtd::EFL; + Nova::Mtd::EBSD | + Nova::Mtd::ESP | + Nova::Mtd::EIP | + Nova::Mtd::EFL; } diff --git a/repos/base-nova/src/core/spec/x86_64/pager.cc b/repos/base-nova/src/core/spec/x86_64/pager.cc index 68b7ad5559..2b43e676b2 100644 --- a/repos/base-nova/src/core/spec/x86_64/pager.cc +++ b/repos/base-nova/src/core/spec/x86_64/pager.cc @@ -11,65 +11,66 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* Core includes */ +/* core includes */ #include /* NOVA includes */ #include -using namespace Genode; +using namespace Core; void Pager_object::_copy_state_from_utcb(Nova::Utcb const &utcb) { - _state.thread.rax = utcb.ax; - _state.thread.rcx = utcb.cx; - _state.thread.rdx = utcb.dx; - _state.thread.rbx = utcb.bx; + _state.thread.cpu.rax = utcb.ax; + _state.thread.cpu.rcx = utcb.cx; + _state.thread.cpu.rdx = utcb.dx; + _state.thread.cpu.rbx = utcb.bx; - _state.thread.rbp = utcb.bp; - _state.thread.rsi = utcb.si; - _state.thread.rdi = utcb.di; + _state.thread.cpu.rbp = utcb.bp; + _state.thread.cpu.rsi = utcb.si; + _state.thread.cpu.rdi = utcb.di; - _state.thread.r8 = utcb.r8; - _state.thread.r9 = utcb.r9; - _state.thread.r10 = utcb.r10; - _state.thread.r11 = utcb.r11; - _state.thread.r12 = utcb.r12; - _state.thread.r13 = utcb.r13; - _state.thread.r14 = utcb.r14; - _state.thread.r15 = utcb.r15; + _state.thread.cpu.r8 = utcb.r8; + _state.thread.cpu.r9 = utcb.r9; + _state.thread.cpu.r10 = utcb.r10; + _state.thread.cpu.r11 = utcb.r11; + _state.thread.cpu.r12 = utcb.r12; + _state.thread.cpu.r13 = utcb.r13; + _state.thread.cpu.r14 = utcb.r14; + _state.thread.cpu.r15 = utcb.r15; - _state.thread.sp = utcb.sp; - _state.thread.ip = utcb.ip; - _state.thread.eflags = utcb.flags; + _state.thread.cpu.sp = utcb.sp; + _state.thread.cpu.ip = utcb.ip; + _state.thread.cpu.eflags = utcb.flags; - _state.thread.exception = utcb.qual[0]; + _state.thread.state = utcb.qual[0] ? Thread_state::State::EXCEPTION + : Thread_state::State::VALID; } void Pager_object::_copy_state_to_utcb(Nova::Utcb &utcb) const { - utcb.ax = _state.thread.rax; - utcb.cx = _state.thread.rcx; - utcb.dx = _state.thread.rdx; - utcb.bx = _state.thread.rbx; + utcb.ax = _state.thread.cpu.rax; + utcb.cx = _state.thread.cpu.rcx; + utcb.dx = _state.thread.cpu.rdx; + utcb.bx = _state.thread.cpu.rbx; - utcb.bp = _state.thread.rbp; - utcb.si = _state.thread.rsi; - utcb.di = _state.thread.rdi; + utcb.bp = _state.thread.cpu.rbp; + utcb.si = _state.thread.cpu.rsi; + utcb.di = _state.thread.cpu.rdi; - utcb.r8 = _state.thread.r8; - utcb.r9 = _state.thread.r9; - utcb.r10 = _state.thread.r10; - utcb.r11 = _state.thread.r11; - utcb.r12 = _state.thread.r12; - utcb.r13 = _state.thread.r13; - utcb.r14 = _state.thread.r14; - utcb.r15 = _state.thread.r15; + utcb.r8 = _state.thread.cpu.r8; + utcb.r9 = _state.thread.cpu.r9; + utcb.r10 = _state.thread.cpu.r10; + utcb.r11 = _state.thread.cpu.r11; + utcb.r12 = _state.thread.cpu.r12; + utcb.r13 = _state.thread.cpu.r13; + utcb.r14 = _state.thread.cpu.r14; + utcb.r15 = _state.thread.cpu.r15; - utcb.sp = _state.thread.sp; - utcb.ip = _state.thread.ip; - utcb.flags = _state.thread.eflags; + utcb.sp = _state.thread.cpu.sp; + utcb.ip = _state.thread.cpu.ip; + utcb.flags = _state.thread.cpu.eflags; utcb.mtd = Nova::Mtd::ACDB | Nova::Mtd::EBSD | diff --git a/repos/base-nova/src/core/thread_start.cc b/repos/base-nova/src/core/thread_start.cc index e600464c91..16a9e4721b 100644 --- a/repos/base-nova/src/core/thread_start.cc +++ b/repos/base-nova/src/core/thread_start.cc @@ -15,7 +15,6 @@ /* Genode includes */ #include -#include /* base-internal includes */ #include @@ -28,7 +27,7 @@ #include #include -using namespace Genode; +using namespace Core; void Thread::_init_platform_thread(size_t, Type type) @@ -58,12 +57,10 @@ void Thread::_init_platform_thread(size_t, Type type) native_thread().exc_pt_sel = cap_map().insert(NUM_INITIAL_PT_LOG2); /* create running semaphore required for locking */ - addr_t rs_sel =native_thread().exc_pt_sel + SM_SEL_EC; + addr_t rs_sel = native_thread().exc_pt_sel + SM_SEL_EC; uint8_t res = create_sm(rs_sel, platform_specific().core_pd_sel(), 0); - if (res != NOVA_OK) { - error("create_sm returned ", res); - throw Cpu_session::Thread_creation_failed(); - } + if (res != NOVA_OK) + error("Thread::_init_platform_thread: create_sm returned ", res); } @@ -82,7 +79,7 @@ void Thread::_deinit_platform_thread() } -void Thread::start() +Thread::Start_result Thread::start() { /* * On NOVA, core almost never starts regular threads. This simply creates a @@ -100,8 +97,8 @@ void Thread::start() platform_specific().core_pd_sel(), kernel_cpu_id, (mword_t)&utcb, sp, native_thread().exc_pt_sel, LOCAL_THREAD); if (res != NOVA_OK) { - error("create_ec returned ", res); - throw Cpu_session::Thread_creation_failed(); + error("Thread::start: create_ec returned ", res); + return Start_result::DENIED; } /* default: we don't accept any mappings or translations */ @@ -112,13 +109,13 @@ void Thread::start() *reinterpret_cast(Thread::myself()->utcb()), Obj_crd(PT_SEL_PAGE_FAULT, 0), Obj_crd(native_thread().exc_pt_sel + PT_SEL_PAGE_FAULT, 0))) { - error("could not create page fault portal"); - throw Cpu_session::Thread_creation_failed(); + error("Thread::start: failed to create page-fault portal"); + return Start_result::DENIED; } - struct Core_trace_source : public Trace::Source::Info_accessor, - private Trace::Control, - private Trace::Source + struct Core_trace_source : public Core::Trace::Source::Info_accessor, + private Core::Trace::Control, + private Core::Trace::Source { Thread &thread; @@ -137,15 +134,17 @@ void Thread::start() Trace::Execution_time(ec_time, 0), thread._affinity }; } - Core_trace_source(Trace::Source_registry ®istry, Thread &t) + Core_trace_source(Core::Trace::Source_registry ®istry, Thread &t) : - Trace::Control(), - Trace::Source(*this, *this), thread(t) + Core::Trace::Control(), + Core::Trace::Source(*this, *this), thread(t) { registry.insert(this); } }; new (platform().core_mem_alloc()) - Core_trace_source(Trace::sources(), *this); + Core_trace_source(Core::Trace::sources(), *this); + + return Start_result::OK; } diff --git a/repos/base-nova/src/core/vm_session_component.cc b/repos/base-nova/src/core/vm_session_component.cc index 7d3d72c3e1..b137080ecd 100644 --- a/repos/base-nova/src/core/vm_session_component.cc +++ b/repos/base-nova/src/core/vm_session_component.cc @@ -12,13 +12,13 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* Base includes */ +/* Genode includes */ #include #include #include #include -/* Core includes */ +/* core includes */ #include #include #include @@ -32,7 +32,7 @@ /* NOVA includes */ #include -using namespace Genode; +using namespace Core; enum { CAP_RANGE_LOG2 = 2, CAP_RANGE = 1 << CAP_RANGE_LOG2 }; @@ -66,13 +66,12 @@ static Nova::uint8_t kernel_quota_upgrade(addr_t const pd_target) } -template static uint8_t _with_kernel_quota_upgrade(addr_t const pd_target, - FUNC const &func) + auto const &fn) { uint8_t res; do { - res = func(); + res = fn(); } while (res == Nova::NOVA_PD_OOM && Nova::NOVA_OK == kernel_quota_upgrade(pd_target)); return res; @@ -83,7 +82,7 @@ static uint8_t _with_kernel_quota_upgrade(addr_t const pd_target, ** Vm_session_component::Vcpu ** ********************************/ -Trace::Source::Info Vm_session_component::Vcpu::trace_source_info() const +Core::Trace::Source::Info Vm_session_component::Vcpu::trace_source_info() const { uint64_t ec_time = 0; uint64_t sc_time = 0; @@ -408,7 +407,7 @@ Vm_session_component::~Vm_session_component() if (!_map.any_block_addr(&out_addr)) break; - detach(out_addr); + detach_at(out_addr); } if (_pd_sel && _pd_sel != invalid_sel()) diff --git a/repos/base-nova/src/include/signal_source/client.h b/repos/base-nova/src/include/signal_source/client.h index 5a0159cbd6..ac64d000c8 100644 --- a/repos/base-nova/src/include/signal_source/client.h +++ b/repos/base-nova/src/include/signal_source/client.h @@ -23,6 +23,7 @@ /* Genode includes */ #include +#include #include /* base-internal includes */ @@ -49,7 +50,7 @@ namespace Genode { /** * Constructor */ - Signal_source_client(Capability cap) + Signal_source_client(Cpu_session &, Capability cap) : Rpc_client(static_cap_cast(cap)) { /* request mapping of semaphore capability selector */ diff --git a/repos/base-nova/src/kernel/nova/target.mk b/repos/base-nova/src/kernel/nova/target.mk index bbaeb9b126..16ab2533f4 100644 --- a/repos/base-nova/src/kernel/nova/target.mk +++ b/repos/base-nova/src/kernel/nova/target.mk @@ -3,7 +3,7 @@ include $(call select_from_repositories,mk/spec/nova.mk) TARGET = hypervisor REQUIRES = x86 nova NOVA_BUILD_DIR = $(BUILD_BASE_DIR)/kernel -NOVA_SRC_DIR = $(call select_from_ports,nova)/src/kernel/nova +NOVA_SRC_DIR := $(call select_from_ports,nova)/src/kernel/nova SRC_CC = $(sort $(notdir $(wildcard $(NOVA_SRC_DIR)/src/*.cpp))) SRC_S = $(sort $(notdir $(wildcard $(NOVA_SRC_DIR)/src/*.S))) INC_DIR = $(NOVA_SRC_DIR)/include @@ -31,12 +31,10 @@ CC_OPT += -DCONFIG_MEMORY_DYN_MIN=0x1c00000 \ CC_OPT_PIC := ifeq ($(filter-out $(SPECS),32bit),) override CC_MARCH = -m32 -CC_WARN += -Wframe-larger-than=104 CC_OPT += -mpreferred-stack-boundary=2 -mregparm=3 else ifeq ($(filter-out $(SPECS),64bit),) override CC_MARCH = -m64 -CC_WARN += -Wframe-larger-than=256 CC_OPT += -mpreferred-stack-boundary=4 -mcmodel=kernel -mno-red-zone else $(error Unsupported environment) @@ -47,7 +45,8 @@ endif CC_CXX_WARN_STRICT = -Wextra -Weffc++ -Werror git_version = $(shell cd $(NOVA_SRC_DIR) && (git rev-parse HEAD 2>/dev/null || echo 0) | cut -c1-7) -CXX_LINK_OPT = -Wl,--gc-sections -Wl,--warn-common -Wl,-static -Wl,-n -Wl,--defsym=GIT_VER=0x$(call git_version) +CXX_LINK_OPT = -Wl,--gc-sections -Wl,--warn-common -Wl,-static -Wl,-n -Wl,--defsym=GIT_VER=0x$(call git_version) \ + -Wl,--no-warn-rwx-segments LD_TEXT_ADDR = # 0xc000000000 - when setting this 64bit compile fails because of relocation issues!! LD_SCRIPT_STATIC = hypervisor.o diff --git a/repos/base-nova/src/lib/base/region_map_client.cc b/repos/base-nova/src/lib/base/region_map_client.cc index 36ffeb0a37..404c805f7f 100644 --- a/repos/base-nova/src/lib/base/region_map_client.cc +++ b/repos/base-nova/src/lib/base/region_map_client.cc @@ -21,25 +21,22 @@ Region_map_client::Region_map_client(Capability session) : Rpc_client(session) { } -Region_map::Local_addr -Region_map_client::attach(Dataspace_capability ds, size_t size, off_t offset, - bool use_local_addr, Local_addr local_addr, - bool executable, bool writeable) +Region_map::Attach_result +Region_map_client::attach(Dataspace_capability ds, Attr const &attr) { - return call(ds, size, offset, use_local_addr, local_addr, - executable, writeable); + return call(ds, attr); } -void Region_map_client::detach(Local_addr local_addr) { - call(local_addr); } +void Region_map_client::detach(addr_t at) { + call(at); } void Region_map_client::fault_handler(Signal_context_capability cap) { call(cap); } -Region_map::State Region_map_client::state() { return call(); } +Region_map::Fault Region_map_client::fault() { return call(); } Dataspace_capability Region_map_client::dataspace() diff --git a/repos/base-nova/src/lib/base/rpc_cap_alloc.cc b/repos/base-nova/src/lib/base/rpc_cap_alloc.cc index 8f0e0ad97c..d5bd988ab9 100644 --- a/repos/base-nova/src/lib/base/rpc_cap_alloc.cc +++ b/repos/base-nova/src/lib/base/rpc_cap_alloc.cc @@ -16,7 +16,6 @@ #include #include #include -#include /* base-internal includes */ #include @@ -27,6 +26,20 @@ using namespace Genode; +static Parent *_parent_ptr; +static Parent &_parent() +{ + if (_parent_ptr) + return *_parent_ptr; + + error("missing call of init_rpc_cap_alloc"); + for (;;); +} + + +void Genode::init_rpc_cap_alloc(Parent &parent) { _parent_ptr = &parent; } + + Native_capability Rpc_entrypoint::_alloc_rpc_cap(Pd_session &pd, Native_capability ep, addr_t entry) { @@ -48,9 +61,9 @@ Native_capability Rpc_entrypoint::_alloc_rpc_cap(Pd_session &pd, Native_capabili catch (Out_of_ram) { ram_upgrade = Ram_quota { 2*1024*sizeof(long) }; } catch (Out_of_caps) { cap_upgrade = Cap_quota { 4 }; } - env_deprecated()->parent()->upgrade(Parent::Env::pd(), - String<100>("ram_quota=", ram_upgrade, ", " - "cap_quota=", cap_upgrade).string()); + _parent().upgrade(Parent::Env::pd(), + String<100>("ram_quota=", ram_upgrade, ", " + "cap_quota=", cap_upgrade).string()); } } diff --git a/repos/base-nova/src/lib/base/rpc_entrypoint.cc b/repos/base-nova/src/lib/base/rpc_entrypoint.cc index 408798f3ee..eea468eac2 100644 --- a/repos/base-nova/src/lib/base/rpc_entrypoint.cc +++ b/repos/base-nova/src/lib/base/rpc_entrypoint.cc @@ -48,7 +48,7 @@ Untyped_capability Rpc_entrypoint::_manage(Rpc_object_base *obj) if (native_thread().ec_sel != Native_thread::INVALID_INDEX) ec_cap = Capability_space::import(native_thread().ec_sel); else - ec_cap = _thread_cap; + ec_cap = Thread::cap(); Untyped_capability obj_cap = _alloc_rpc_cap(_pd_session, ec_cap, (addr_t)&_activation_entry); @@ -157,7 +157,8 @@ void Rpc_entrypoint::_activation_entry() } /* atomically lookup and lock referenced object */ - auto lambda = [&] (Rpc_object_base *obj) { + auto lambda = [&] (Rpc_object_base *obj) + { if (!obj) { error("could not look up server object, return from call id_pt=", id_pt); return; @@ -165,8 +166,7 @@ void Rpc_entrypoint::_activation_entry() /* dispatch request */ ep._snd_buf.reset(); - try { exc = obj->dispatch(opcode, unmarshaller, ep._snd_buf); } - catch (Blocking_canceled) { } + exc = obj->dispatch(opcode, unmarshaller, ep._snd_buf); }; ep.apply(id_pt, lambda); @@ -214,20 +214,22 @@ Rpc_entrypoint::Rpc_entrypoint(Pd_session *pd_session, size_t stack_size, _cap = _alloc_rpc_cap(_pd_session, Capability_space::import(native_thread().ec_sel), (addr_t)_activation_entry); - if (!_cap.valid()) - throw Cpu_session::Thread_creation_failed(); + if (!_cap.valid()) { + error("failed to allocate RPC cap for new entrypoint"); + return; + } Receive_window &rcv_window = Thread::native_thread().server_rcv_window; /* prepare portal receive window of new thread */ if (!rcv_window.prepare_rcv_window(*(Nova::Utcb *)&_stack->utcb())) - throw Cpu_session::Thread_creation_failed(); + error("failed to prepare receive window for RPC entrypoint"); } Rpc_entrypoint::~Rpc_entrypoint() { - typedef Object_pool Pool; + using Pool = Object_pool; Pool::remove_all([&] (Rpc_object_base *obj) { warning("object pool not empty in ", __func__); diff --git a/repos/base-nova/src/lib/base/stack.cc b/repos/base-nova/src/lib/base/stack.cc index ae5be5605e..313974d42a 100644 --- a/repos/base-nova/src/lib/base/stack.cc +++ b/repos/base-nova/src/lib/base/stack.cc @@ -22,6 +22,7 @@ #include /* base-internal includes */ +#include #include #include #include @@ -72,10 +73,8 @@ Initial_cap_range &initial_cap_range() ** Startup library support ** *****************************/ -void prepare_init_main_thread() +void Genode::prepare_init_main_thread() { - using namespace Genode; - cap_map().insert(initial_cap_range()); /* for Core we can't perform the following code so early */ diff --git a/repos/base-nova/src/lib/base/thread_start.cc b/repos/base-nova/src/lib/base/thread_start.cc index c7cfd29d83..1717227a34 100644 --- a/repos/base-nova/src/lib/base/thread_start.cc +++ b/repos/base-nova/src/lib/base/thread_start.cc @@ -22,7 +22,6 @@ #include #include #include -#include /* base-internal includes */ #include @@ -37,6 +36,20 @@ using namespace Genode; +static Capability pd_session_cap(Capability pd_cap = { }) +{ + static Capability cap = pd_cap; /* defined once by 'init_thread_start' */ + return cap; +} + + +static Thread_capability main_thread_cap(Thread_capability main_cap = { }) +{ + static Thread_capability cap = main_cap; + return cap; +} + + /** * Entry point entered by new threads */ @@ -105,17 +118,19 @@ void Thread::_init_platform_thread(size_t weight, Type type) revoke(Mem_crd(utcb >> 12, 0, rwx)); native_thread().exc_pt_sel = cap_map().insert(NUM_INITIAL_PT_LOG2); - if (native_thread().exc_pt_sel == Native_thread::INVALID_INDEX) - throw Cpu_session::Thread_creation_failed(); - + if (native_thread().exc_pt_sel == Native_thread::INVALID_INDEX) { + error("failed allocate exception-portal selector for new thread"); + return; + } _init_cpu_session_and_trace_control(); /* create thread at core */ - _thread_cap = _cpu_session->create_thread(env_deprecated()->pd_session_cap(), name(), - _affinity, Weight(weight)); - if (!_thread_cap.valid()) - throw Cpu_session::Thread_creation_failed(); + _cpu_session->create_thread(pd_session_cap(), name(), + _affinity, Weight(weight)).with_result( + [&] (Thread_capability cap) { _thread_cap = cap; }, + [&] (Cpu_session::Create_thread_error) { + error("failed to create new thread for local PD"); }); } @@ -128,22 +143,28 @@ void Thread::_deinit_platform_thread() } /* de-announce thread */ - if (_thread_cap.valid()) - _cpu_session->kill_thread(_thread_cap); + _thread_cap.with_result( + [&] (Thread_capability cap) { _cpu_session->kill_thread(cap); }, + [&] (Cpu_session::Create_thread_error) { }); cap_map().remove(native_thread().exc_pt_sel, NUM_INITIAL_PT_LOG2); } -void Thread::start() +Thread::Start_result Thread::start() { - if (native_thread().ec_sel < Native_thread::INVALID_INDEX - 1) - throw Cpu_session::Thread_creation_failed(); + if (native_thread().ec_sel < Native_thread::INVALID_INDEX - 1) { + error("Thread::start failed due to invalid exception portal selector"); + return Start_result::DENIED; + } + + if (_thread_cap.failed()) + return Start_result::DENIED; /* * Default: create global thread - ec.sel == INVALID_INDEX * create local thread - ec.sel == INVALID_INDEX - 1 - */ + */ bool global = native_thread().ec_sel == Native_thread::INVALID_INDEX; using namespace Genode; @@ -161,13 +182,16 @@ void Thread::start() Cpu_session::Native_cpu::Exception_base exception_base { native_thread().exc_pt_sel }; Nova_native_cpu_client native_cpu(_cpu_session->native_cpu()); - native_cpu.thread_type(_thread_cap, thread_type, exception_base); - } catch (...) { throw Cpu_session::Thread_creation_failed(); } + native_cpu.thread_type(cap(), thread_type, exception_base); + } catch (...) { + error("Thread::start failed to set thread type"); + return Start_result::DENIED; + } /* local thread have no start instruction pointer - set via portal entry */ addr_t thread_ip = global ? reinterpret_cast(_thread_start) : native_thread().initial_ip; - Cpu_thread_client cpu_thread(_thread_cap); + Cpu_thread_client cpu_thread(cap()); cpu_thread.start(thread_ip, _stack->top()); /* request native EC thread cap */ @@ -190,4 +214,18 @@ void Thread::start() if (global) /* request creation of SC to let thread run*/ cpu_thread.resume(); + + return Start_result::OK; +} + + +void Genode::init_thread_start(Capability pd_cap) +{ + pd_session_cap(pd_cap); +} + + +void Genode::init_thread_bootstrap(Cpu_session &, Thread_capability main_cap) +{ + main_thread_cap(main_cap); } diff --git a/repos/base-nova/src/lib/base/vm.cc b/repos/base-nova/src/lib/base/vm.cc index 767cb4ae4e..bd2c407ded 100644 --- a/repos/base-nova/src/lib/base/vm.cc +++ b/repos/base-nova/src/lib/base/vm.cc @@ -2,11 +2,12 @@ * \brief NOVA-specific VM-connection implementation * \author Alexander Boettcher * \author Christian Helmuth + * \author Benjamin Lamowski * \date 2018-08-27 */ /* - * Copyright (C) 2018-2021 Genode Labs GmbH + * Copyright (C) 2018-2023 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -16,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +35,7 @@ using namespace Genode; using Exit_config = Vm_connection::Exit_config; +using Call_with_state = Vm_connection::Call_with_state; /****************************** @@ -43,7 +46,9 @@ struct Nova_vcpu : Rpc_client, Noncopyable { private: - typedef Id_space Vcpu_space; + enum { VM_EXIT_STARTUP = 0xfe, VM_EXIT_RECALL = 0xff }; + + using Vcpu_space = Id_space; static Vcpu_space &_vcpu_space() { @@ -59,19 +64,12 @@ struct Nova_vcpu : Rpc_client, Noncopyable Allocator &_alloc; void *_ep_handler { nullptr }; void *_dispatching { nullptr }; - bool _block { true }; - bool _use_guest_fpu { false }; + bool _resume { false }; + bool _last_resume { true }; Vcpu_state _vcpu_state __attribute__((aligned(0x10))) { }; - enum Remote_state_requested { - NONE = 0, - PAUSE = 1, - RUN = 2 - } _remote { NONE }; - - inline void _read_nova_state(Nova::Utcb &, unsigned exit_reason, - uint8_t const &); + inline void _read_nova_state(Nova::Utcb &); inline void _write_nova_state(Nova::Utcb &); @@ -81,8 +79,7 @@ struct Nova_vcpu : Rpc_client, Noncopyable addr_t _ec_sel() const { return _sm_sel() + 1; } /** - * NOVA badge with 15-bit exit reason, 1-bit fpu usage and - * 16-bit artificial vCPU I + * NOVA badge with 16-bit exit reason and 16-bit artificial vCPU ID */ struct Badge { @@ -91,19 +88,15 @@ struct Nova_vcpu : Rpc_client, Noncopyable Badge(unsigned long value) : _value((uint32_t)value) { } - Badge(uint16_t vcpu_id, uint16_t exit_reason, bool fpu_usage) - : _value((uint32_t)(vcpu_id << 16) | - (exit_reason & 0x7fffu) | - (fpu_usage ? 0x8000u : 0u) - ) { } + Badge(uint16_t vcpu_id, uint16_t exit_reason) + : _value((uint32_t)(vcpu_id << 16) | (exit_reason & 0xffffu)) { } - uint16_t exit_reason() const { return (uint16_t)( _value & 0x7fff); } + uint16_t exit_reason() const { return (uint16_t)( _value & 0xffff); } uint16_t vcpu_id() const { return (uint16_t)((_value >> 16) & 0xffff); } - bool fpu_usage() const { return _value & 0x8000; } uint32_t value() const { return _value; } }; - bool _handle_exit(Nova::Utcb &, uint16_t exit_reason, uint8_t const &); + void _handle_exit(Nova::Utcb &); __attribute__((regparm(1))) static void _exit_entry(addr_t badge); @@ -141,8 +134,7 @@ struct Nova_vcpu : Rpc_client, Noncopyable mtd |= Nova::Mtd::SYSCALL_SWAPGS; mtd |= Nova::Mtd::TPR; mtd |= Nova::Mtd::QUAL; - - _use_guest_fpu = true; + mtd |= Nova::Mtd::XSAVE; mtd |= Nova::Mtd::FPU; return Nova::Mtd(mtd); @@ -155,7 +147,6 @@ struct Nova_vcpu : Rpc_client, Noncopyable uint16_t vcpu_id, uint16_t exit_reason, Nova::Mtd mtd); - /* * Noncopyable */ @@ -167,182 +158,187 @@ struct Nova_vcpu : Rpc_client, Noncopyable Nova_vcpu(Env &env, Vm_connection &vm, Allocator &alloc, Vcpu_handler_base &handler, Exit_config const &exit_config); - void run(); + void startup() + { + call(); + } - void pause(); - - Vcpu_state & state() { return _vcpu_state; } + void with_state(Call_with_state &cw); }; -void Nova_vcpu::_read_nova_state(Nova::Utcb &utcb, unsigned exit_reason, - uint8_t const &fpu_at_exit) +void Nova_vcpu::_read_nova_state(Nova::Utcb &utcb) { - typedef Genode::Vcpu_state::Segment Segment; - typedef Genode::Vcpu_state::Range Range; + using Segment = Genode::Vcpu_state::Segment; + using Range = Genode::Vcpu_state::Range; - state().discharge(); - state().exit_reason = exit_reason; + _vcpu_state.discharge(); + _vcpu_state.exit_reason = static_cast(utcb.exit_reason); if (utcb.mtd & Nova::Mtd::FPU) { - state().fpu.charge([&] (Vcpu_state::Fpu::State &fpu) { - memcpy(&fpu, &fpu_at_exit, sizeof(fpu)); + _vcpu_state.fpu.charge([&] (Vcpu_state::Fpu::State &fpu) { + memcpy(&fpu, utcb.fpu, sizeof(fpu)); }); } if (utcb.mtd & Nova::Mtd::ACDB) { - state().ax.charge(utcb.ax); - state().cx.charge(utcb.cx); - state().dx.charge(utcb.dx); - state().bx.charge(utcb.bx); + _vcpu_state.ax.charge(utcb.ax); + _vcpu_state.cx.charge(utcb.cx); + _vcpu_state.dx.charge(utcb.dx); + _vcpu_state.bx.charge(utcb.bx); } if (utcb.mtd & Nova::Mtd::EBSD) { - state().di.charge(utcb.di); - state().si.charge(utcb.si); - state().bp.charge(utcb.bp); + _vcpu_state.di.charge(utcb.di); + _vcpu_state.si.charge(utcb.si); + _vcpu_state.bp.charge(utcb.bp); } - if (utcb.mtd & Nova::Mtd::EFL) state().flags.charge(utcb.flags); - if (utcb.mtd & Nova::Mtd::ESP) state().sp.charge(utcb.sp); - if (utcb.mtd & Nova::Mtd::DR) state().dr7.charge(utcb.dr7); + if (utcb.mtd & Nova::Mtd::EFL) _vcpu_state.flags.charge(utcb.flags); + if (utcb.mtd & Nova::Mtd::ESP) _vcpu_state.sp.charge(utcb.sp); + if (utcb.mtd & Nova::Mtd::DR) _vcpu_state.dr7.charge(utcb.dr7); if (utcb.mtd & Nova::Mtd::EIP) { - state().ip.charge(utcb.ip); - state().ip_len.charge(utcb.instr_len); + _vcpu_state.ip.charge(utcb.ip); + _vcpu_state.ip_len.charge(utcb.instr_len); } if (utcb.mtd & Nova::Mtd::R8_R15) { - state(). r8.charge(utcb.read_r8()); - state(). r9.charge(utcb.read_r9()); - state().r10.charge(utcb.read_r10()); - state().r11.charge(utcb.read_r11()); - state().r12.charge(utcb.read_r12()); - state().r13.charge(utcb.read_r13()); - state().r14.charge(utcb.read_r14()); - state().r15.charge(utcb.read_r15()); + _vcpu_state. r8.charge(utcb.read_r8()); + _vcpu_state. r9.charge(utcb.read_r9()); + _vcpu_state.r10.charge(utcb.read_r10()); + _vcpu_state.r11.charge(utcb.read_r11()); + _vcpu_state.r12.charge(utcb.read_r12()); + _vcpu_state.r13.charge(utcb.read_r13()); + _vcpu_state.r14.charge(utcb.read_r14()); + _vcpu_state.r15.charge(utcb.read_r15()); } if (utcb.mtd & Nova::Mtd::CR) { - state().cr0.charge(utcb.cr0); - state().cr2.charge(utcb.cr2); - state().cr3.charge(utcb.cr3); - state().cr4.charge(utcb.cr4); + _vcpu_state.cr0.charge(utcb.cr0); + _vcpu_state.cr2.charge(utcb.cr2); + _vcpu_state.cr3.charge(utcb.cr3); + _vcpu_state.cr4.charge(utcb.cr4); } if (utcb.mtd & Nova::Mtd::CSSS) { - state().cs.charge(Segment { .sel = utcb.cs.sel, + _vcpu_state.cs.charge(Segment { .sel = utcb.cs.sel, .ar = utcb.cs.ar, .limit = utcb.cs.limit, .base = utcb.cs.base }); - state().ss.charge(Segment { .sel = utcb.ss.sel, + _vcpu_state.ss.charge(Segment { .sel = utcb.ss.sel, .ar = utcb.ss.ar, .limit = utcb.ss.limit, .base = utcb.ss.base }); } if (utcb.mtd & Nova::Mtd::ESDS) { - state().es.charge(Segment { .sel = utcb.es.sel, + _vcpu_state.es.charge(Segment { .sel = utcb.es.sel, .ar = utcb.es.ar, .limit = utcb.es.limit, .base = utcb.es.base }); - state().ds.charge(Segment { .sel = utcb.ds.sel, + _vcpu_state.ds.charge(Segment { .sel = utcb.ds.sel, .ar = utcb.ds.ar, .limit = utcb.ds.limit, .base = utcb.ds.base }); } if (utcb.mtd & Nova::Mtd::FSGS) { - state().fs.charge(Segment { .sel = utcb.fs.sel, + _vcpu_state.fs.charge(Segment { .sel = utcb.fs.sel, .ar = utcb.fs.ar, .limit = utcb.fs.limit, .base = utcb.fs.base }); - state().gs.charge(Segment { .sel = utcb.gs.sel, + _vcpu_state.gs.charge(Segment { .sel = utcb.gs.sel, .ar = utcb.gs.ar, .limit = utcb.gs.limit, .base = utcb.gs.base }); } if (utcb.mtd & Nova::Mtd::TR) { - state().tr.charge(Segment { .sel = utcb.tr.sel, + _vcpu_state.tr.charge(Segment { .sel = utcb.tr.sel, .ar = utcb.tr.ar, .limit = utcb.tr.limit, .base = utcb.tr.base }); } if (utcb.mtd & Nova::Mtd::LDTR) { - state().ldtr.charge(Segment { .sel = utcb.ldtr.sel, + _vcpu_state.ldtr.charge(Segment { .sel = utcb.ldtr.sel, .ar = utcb.ldtr.ar, .limit = utcb.ldtr.limit, .base = utcb.ldtr.base }); } if (utcb.mtd & Nova::Mtd::GDTR) { - state().gdtr.charge(Range { .limit = utcb.gdtr.limit, + _vcpu_state.gdtr.charge(Range { .limit = utcb.gdtr.limit, .base = utcb.gdtr.base }); } if (utcb.mtd & Nova::Mtd::IDTR) { - state().idtr.charge(Range { .limit = utcb.idtr.limit, + _vcpu_state.idtr.charge(Range { .limit = utcb.idtr.limit, .base = utcb.idtr.base }); } if (utcb.mtd & Nova::Mtd::SYS) { - state().sysenter_cs.charge(utcb.sysenter_cs); - state().sysenter_sp.charge(utcb.sysenter_sp); - state().sysenter_ip.charge(utcb.sysenter_ip); + _vcpu_state.sysenter_cs.charge(utcb.sysenter_cs); + _vcpu_state.sysenter_sp.charge(utcb.sysenter_sp); + _vcpu_state.sysenter_ip.charge(utcb.sysenter_ip); } if (utcb.mtd & Nova::Mtd::QUAL) { - state().qual_primary.charge(utcb.qual[0]); - state().qual_secondary.charge(utcb.qual[1]); + _vcpu_state.qual_primary.charge(utcb.qual[0]); + _vcpu_state.qual_secondary.charge(utcb.qual[1]); } if (utcb.mtd & Nova::Mtd::CTRL) { - state().ctrl_primary.charge(utcb.ctrl[0]); - state().ctrl_secondary.charge(utcb.ctrl[1]); + _vcpu_state.ctrl_primary.charge(utcb.ctrl[0]); + _vcpu_state.ctrl_secondary.charge(utcb.ctrl[1]); } if (utcb.mtd & Nova::Mtd::INJ) { - state().inj_info.charge(utcb.inj_info); - state().inj_error.charge(utcb.inj_error); + _vcpu_state.inj_info.charge(utcb.inj_info); + _vcpu_state.inj_error.charge(utcb.inj_error); } if (utcb.mtd & Nova::Mtd::STA) { - state().intr_state.charge(utcb.intr_state); - state().actv_state.charge(utcb.actv_state); + _vcpu_state.intr_state.charge(utcb.intr_state); + _vcpu_state.actv_state.charge(utcb.actv_state); } if (utcb.mtd & Nova::Mtd::TSC) { - state().tsc.charge(utcb.tsc_val); - state().tsc_offset.charge(utcb.tsc_off); + _vcpu_state.tsc.charge(utcb.tsc_val); + _vcpu_state.tsc_offset.charge(utcb.tsc_off); } if (utcb.mtd & Nova::Mtd::TSC_AUX) { - state().tsc_aux.charge(utcb.tsc_aux); + _vcpu_state.tsc_aux.charge(utcb.tsc_aux); } if (utcb.mtd & Nova::Mtd::EFER) { - state().efer.charge(utcb.read_efer()); + _vcpu_state.efer.charge(utcb.read_efer()); } if (utcb.mtd & Nova::Mtd::PDPTE) { - state().pdpte_0.charge(utcb.pdpte[0]); - state().pdpte_1.charge(utcb.pdpte[1]); - state().pdpte_2.charge(utcb.pdpte[2]); - state().pdpte_3.charge(utcb.pdpte[3]); + _vcpu_state.pdpte_0.charge(utcb.pdpte[0]); + _vcpu_state.pdpte_1.charge(utcb.pdpte[1]); + _vcpu_state.pdpte_2.charge(utcb.pdpte[2]); + _vcpu_state.pdpte_3.charge(utcb.pdpte[3]); } if (utcb.mtd & Nova::Mtd::SYSCALL_SWAPGS) { - state().star.charge(utcb.read_star()); - state().lstar.charge(utcb.read_lstar()); - state().cstar.charge(utcb.read_cstar()); - state().fmask.charge(utcb.read_fmask()); - state().kernel_gs_base.charge(utcb.read_kernel_gs_base()); + _vcpu_state.star.charge(utcb.read_star()); + _vcpu_state.lstar.charge(utcb.read_lstar()); + _vcpu_state.cstar.charge(utcb.read_cstar()); + _vcpu_state.fmask.charge(utcb.read_fmask()); + _vcpu_state.kernel_gs_base.charge(utcb.read_kernel_gs_base()); } if (utcb.mtd & Nova::Mtd::TPR) { - state().tpr.charge(utcb.read_tpr()); - state().tpr_threshold.charge(utcb.read_tpr_threshold()); + _vcpu_state.tpr.charge(utcb.read_tpr()); + _vcpu_state.tpr_threshold.charge(utcb.read_tpr_threshold()); + } + + if (utcb.mtd & Nova::Mtd::XSAVE) { + _vcpu_state.xcr0.charge(utcb.xcr0); + _vcpu_state.xss.charge(utcb.xss); } } @@ -352,291 +348,241 @@ void Nova_vcpu::_write_nova_state(Nova::Utcb &utcb) utcb.items = 0; utcb.mtd = 0; - if (state().ax.charged() || state().cx.charged() || - state().dx.charged() || state().bx.charged()) { + if (_vcpu_state.ax.charged() || _vcpu_state.cx.charged() || + _vcpu_state.dx.charged() || _vcpu_state.bx.charged()) { utcb.mtd |= Nova::Mtd::ACDB; - utcb.ax = state().ax.value(); - utcb.cx = state().cx.value(); - utcb.dx = state().dx.value(); - utcb.bx = state().bx.value(); + utcb.ax = _vcpu_state.ax.value(); + utcb.cx = _vcpu_state.cx.value(); + utcb.dx = _vcpu_state.dx.value(); + utcb.bx = _vcpu_state.bx.value(); } - if (state().bp.charged() || state().di.charged() || state().si.charged()) { + if (_vcpu_state.bp.charged() || _vcpu_state.di.charged() || _vcpu_state.si.charged()) { utcb.mtd |= Nova::Mtd::EBSD; - utcb.di = state().di.value(); - utcb.si = state().si.value(); - utcb.bp = state().bp.value(); + utcb.di = _vcpu_state.di.value(); + utcb.si = _vcpu_state.si.value(); + utcb.bp = _vcpu_state.bp.value(); } - if (state().flags.charged()) { + if (_vcpu_state.flags.charged()) { utcb.mtd |= Nova::Mtd::EFL; - utcb.flags = state().flags.value(); + utcb.flags = _vcpu_state.flags.value(); } - if (state().sp.charged()) { + if (_vcpu_state.sp.charged()) { utcb.mtd |= Nova::Mtd::ESP; - utcb.sp = state().sp.value(); + utcb.sp = _vcpu_state.sp.value(); } - if (state().ip.charged()) { + if (_vcpu_state.ip.charged()) { utcb.mtd |= Nova::Mtd::EIP; - utcb.ip = state().ip.value(); - utcb.instr_len = state().ip_len.value(); + utcb.ip = _vcpu_state.ip.value(); + utcb.instr_len = _vcpu_state.ip_len.value(); } - if (state().dr7.charged()) { + if (_vcpu_state.dr7.charged()) { utcb.mtd |= Nova::Mtd::DR; - utcb.dr7 = state().dr7.value(); + utcb.dr7 = _vcpu_state.dr7.value(); } - if (state().r8 .charged() || state().r9 .charged() || - state().r10.charged() || state().r11.charged() || - state().r12.charged() || state().r13.charged() || - state().r14.charged() || state().r15.charged()) { + if (_vcpu_state.r8 .charged() || _vcpu_state.r9 .charged() || + _vcpu_state.r10.charged() || _vcpu_state.r11.charged() || + _vcpu_state.r12.charged() || _vcpu_state.r13.charged() || + _vcpu_state.r14.charged() || _vcpu_state.r15.charged()) { utcb.mtd |= Nova::Mtd::R8_R15; - utcb.write_r8 (state().r8.value()); - utcb.write_r9 (state().r9.value()); - utcb.write_r10(state().r10.value()); - utcb.write_r11(state().r11.value()); - utcb.write_r12(state().r12.value()); - utcb.write_r13(state().r13.value()); - utcb.write_r14(state().r14.value()); - utcb.write_r15(state().r15.value()); + utcb.write_r8 (_vcpu_state.r8.value()); + utcb.write_r9 (_vcpu_state.r9.value()); + utcb.write_r10(_vcpu_state.r10.value()); + utcb.write_r11(_vcpu_state.r11.value()); + utcb.write_r12(_vcpu_state.r12.value()); + utcb.write_r13(_vcpu_state.r13.value()); + utcb.write_r14(_vcpu_state.r14.value()); + utcb.write_r15(_vcpu_state.r15.value()); } - if (state().cr0.charged() || state().cr2.charged() || - state().cr3.charged() || state().cr4.charged()) { + if (_vcpu_state.cr0.charged() || _vcpu_state.cr2.charged() || + _vcpu_state.cr3.charged() || _vcpu_state.cr4.charged()) { utcb.mtd |= Nova::Mtd::CR; - utcb.cr0 = state().cr0.value(); - utcb.cr2 = state().cr2.value(); - utcb.cr3 = state().cr3.value(); - utcb.cr4 = state().cr4.value(); + utcb.cr0 = _vcpu_state.cr0.value(); + utcb.cr2 = _vcpu_state.cr2.value(); + utcb.cr3 = _vcpu_state.cr3.value(); + utcb.cr4 = _vcpu_state.cr4.value(); } - if (state().cs.charged() || state().ss.charged()) { + if (_vcpu_state.cs.charged() || _vcpu_state.ss.charged()) { utcb.mtd |= Nova::Mtd::CSSS; - utcb.cs.sel = state().cs.value().sel; - utcb.cs.ar = state().cs.value().ar; - utcb.cs.limit = state().cs.value().limit; - utcb.cs.base = state().cs.value().base; + utcb.cs.sel = _vcpu_state.cs.value().sel; + utcb.cs.ar = _vcpu_state.cs.value().ar; + utcb.cs.limit = _vcpu_state.cs.value().limit; + utcb.cs.base = _vcpu_state.cs.value().base; - utcb.ss.sel = state().ss.value().sel; - utcb.ss.ar = state().ss.value().ar; - utcb.ss.limit = state().ss.value().limit; - utcb.ss.base = state().ss.value().base; + utcb.ss.sel = _vcpu_state.ss.value().sel; + utcb.ss.ar = _vcpu_state.ss.value().ar; + utcb.ss.limit = _vcpu_state.ss.value().limit; + utcb.ss.base = _vcpu_state.ss.value().base; } - if (state().es.charged() || state().ds.charged()) { + if (_vcpu_state.es.charged() || _vcpu_state.ds.charged()) { utcb.mtd |= Nova::Mtd::ESDS; - utcb.es.sel = state().es.value().sel; - utcb.es.ar = state().es.value().ar; - utcb.es.limit = state().es.value().limit; - utcb.es.base = state().es.value().base; + utcb.es.sel = _vcpu_state.es.value().sel; + utcb.es.ar = _vcpu_state.es.value().ar; + utcb.es.limit = _vcpu_state.es.value().limit; + utcb.es.base = _vcpu_state.es.value().base; - utcb.ds.sel = state().ds.value().sel; - utcb.ds.ar = state().ds.value().ar; - utcb.ds.limit = state().ds.value().limit; - utcb.ds.base = state().ds.value().base; + utcb.ds.sel = _vcpu_state.ds.value().sel; + utcb.ds.ar = _vcpu_state.ds.value().ar; + utcb.ds.limit = _vcpu_state.ds.value().limit; + utcb.ds.base = _vcpu_state.ds.value().base; } - if (state().fs.charged() || state().gs.charged()) { + if (_vcpu_state.fs.charged() || _vcpu_state.gs.charged()) { utcb.mtd |= Nova::Mtd::FSGS; - utcb.fs.sel = state().fs.value().sel; - utcb.fs.ar = state().fs.value().ar; - utcb.fs.limit = state().fs.value().limit; - utcb.fs.base = state().fs.value().base; + utcb.fs.sel = _vcpu_state.fs.value().sel; + utcb.fs.ar = _vcpu_state.fs.value().ar; + utcb.fs.limit = _vcpu_state.fs.value().limit; + utcb.fs.base = _vcpu_state.fs.value().base; - utcb.gs.sel = state().gs.value().sel; - utcb.gs.ar = state().gs.value().ar; - utcb.gs.limit = state().gs.value().limit; - utcb.gs.base = state().gs.value().base; + utcb.gs.sel = _vcpu_state.gs.value().sel; + utcb.gs.ar = _vcpu_state.gs.value().ar; + utcb.gs.limit = _vcpu_state.gs.value().limit; + utcb.gs.base = _vcpu_state.gs.value().base; } - if (state().tr.charged()) { + if (_vcpu_state.tr.charged()) { utcb.mtd |= Nova::Mtd::TR; - utcb.tr.sel = state().tr.value().sel; - utcb.tr.ar = state().tr.value().ar; - utcb.tr.limit = state().tr.value().limit; - utcb.tr.base = state().tr.value().base; + utcb.tr.sel = _vcpu_state.tr.value().sel; + utcb.tr.ar = _vcpu_state.tr.value().ar; + utcb.tr.limit = _vcpu_state.tr.value().limit; + utcb.tr.base = _vcpu_state.tr.value().base; } - if (state().ldtr.charged()) { + if (_vcpu_state.ldtr.charged()) { utcb.mtd |= Nova::Mtd::LDTR; - utcb.ldtr.sel = state().ldtr.value().sel; - utcb.ldtr.ar = state().ldtr.value().ar; - utcb.ldtr.limit = state().ldtr.value().limit; - utcb.ldtr.base = state().ldtr.value().base; + utcb.ldtr.sel = _vcpu_state.ldtr.value().sel; + utcb.ldtr.ar = _vcpu_state.ldtr.value().ar; + utcb.ldtr.limit = _vcpu_state.ldtr.value().limit; + utcb.ldtr.base = _vcpu_state.ldtr.value().base; } - if (state().gdtr.charged()) { + if (_vcpu_state.gdtr.charged()) { utcb.mtd |= Nova::Mtd::GDTR; - utcb.gdtr.limit = state().gdtr.value().limit; - utcb.gdtr.base = state().gdtr.value().base; + utcb.gdtr.limit = _vcpu_state.gdtr.value().limit; + utcb.gdtr.base = _vcpu_state.gdtr.value().base; } - if (state().idtr.charged()) { + if (_vcpu_state.idtr.charged()) { utcb.mtd |= Nova::Mtd::IDTR; - utcb.idtr.limit = state().idtr.value().limit; - utcb.idtr.base = state().idtr.value().base; + utcb.idtr.limit = _vcpu_state.idtr.value().limit; + utcb.idtr.base = _vcpu_state.idtr.value().base; } - if (state().sysenter_cs.charged() || state().sysenter_sp.charged() || - state().sysenter_ip.charged()) { + if (_vcpu_state.sysenter_cs.charged() || _vcpu_state.sysenter_sp.charged() || + _vcpu_state.sysenter_ip.charged()) { utcb.mtd |= Nova::Mtd::SYS; - utcb.sysenter_cs = state().sysenter_cs.value(); - utcb.sysenter_sp = state().sysenter_sp.value(); - utcb.sysenter_ip = state().sysenter_ip.value(); + utcb.sysenter_cs = _vcpu_state.sysenter_cs.value(); + utcb.sysenter_sp = _vcpu_state.sysenter_sp.value(); + utcb.sysenter_ip = _vcpu_state.sysenter_ip.value(); } - if (state().ctrl_primary.charged() || state().ctrl_secondary.charged()) { + if (_vcpu_state.ctrl_primary.charged() || _vcpu_state.ctrl_secondary.charged()) { utcb.mtd |= Nova::Mtd::CTRL; - utcb.ctrl[0] = state().ctrl_primary.value(); - utcb.ctrl[1] = state().ctrl_secondary.value(); + utcb.ctrl[0] = _vcpu_state.ctrl_primary.value(); + utcb.ctrl[1] = _vcpu_state.ctrl_secondary.value(); } - if (state().inj_info.charged() || state().inj_error.charged()) { + if (_vcpu_state.inj_info.charged() || _vcpu_state.inj_error.charged()) { utcb.mtd |= Nova::Mtd::INJ; - utcb.inj_info = state().inj_info.value(); - utcb.inj_error = state().inj_error.value(); + utcb.inj_info = _vcpu_state.inj_info.value(); + utcb.inj_error = _vcpu_state.inj_error.value(); } - if (state().intr_state.charged() || state().actv_state.charged()) { + if (_vcpu_state.intr_state.charged() || _vcpu_state.actv_state.charged()) { utcb.mtd |= Nova::Mtd::STA; - utcb.intr_state = state().intr_state.value(); - utcb.actv_state = state().actv_state.value(); + utcb.intr_state = _vcpu_state.intr_state.value(); + utcb.actv_state = _vcpu_state.actv_state.value(); } - if (state().tsc.charged() || state().tsc_offset.charged()) { + if (_vcpu_state.tsc.charged() || _vcpu_state.tsc_offset.charged()) { utcb.mtd |= Nova::Mtd::TSC; - utcb.tsc_val = state().tsc.value(); - utcb.tsc_off = state().tsc_offset.value(); + utcb.tsc_val = _vcpu_state.tsc.value(); + utcb.tsc_off = _vcpu_state.tsc_offset.value(); } - if (state().tsc_aux.charged()) { + if (_vcpu_state.tsc_aux.charged()) { utcb.mtd |= Nova::Mtd::TSC_AUX; - utcb.tsc_aux = state().tsc_aux.value(); + utcb.tsc_aux = _vcpu_state.tsc_aux.value(); } - if (state().efer.charged()) { + if (_vcpu_state.efer.charged()) { utcb.mtd |= Nova::Mtd::EFER; - utcb.write_efer(state().efer.value()); + utcb.write_efer(_vcpu_state.efer.value()); } - if (state().pdpte_0.charged() || state().pdpte_1.charged() || - state().pdpte_2.charged() || state().pdpte_3.charged()) { + if (_vcpu_state.pdpte_0.charged() || _vcpu_state.pdpte_1.charged() || + _vcpu_state.pdpte_2.charged() || _vcpu_state.pdpte_3.charged()) { utcb.mtd |= Nova::Mtd::PDPTE; - utcb.pdpte[0] = (Nova::mword_t)state().pdpte_0.value(); - utcb.pdpte[1] = (Nova::mword_t)state().pdpte_1.value(); - utcb.pdpte[2] = (Nova::mword_t)state().pdpte_2.value(); - utcb.pdpte[3] = (Nova::mword_t)state().pdpte_3.value(); + utcb.pdpte[0] = (Nova::mword_t)_vcpu_state.pdpte_0.value(); + utcb.pdpte[1] = (Nova::mword_t)_vcpu_state.pdpte_1.value(); + utcb.pdpte[2] = (Nova::mword_t)_vcpu_state.pdpte_2.value(); + utcb.pdpte[3] = (Nova::mword_t)_vcpu_state.pdpte_3.value(); } - if (state().star.charged() || state().lstar.charged() || - state().cstar.charged() || state().fmask.charged() || - state().kernel_gs_base.charged()) { + if (_vcpu_state.star.charged() || _vcpu_state.lstar.charged() || + _vcpu_state.cstar.charged() || _vcpu_state.fmask.charged() || + _vcpu_state.kernel_gs_base.charged()) { utcb.mtd |= Nova::Mtd::SYSCALL_SWAPGS; - utcb.write_star (state().star.value()); - utcb.write_lstar(state().lstar.value()); - utcb.write_cstar(state().cstar.value()); - utcb.write_fmask(state().fmask.value()); - utcb.write_kernel_gs_base(state().kernel_gs_base.value()); + utcb.write_star (_vcpu_state.star.value()); + utcb.write_lstar(_vcpu_state.lstar.value()); + utcb.write_cstar(_vcpu_state.cstar.value()); + utcb.write_fmask(_vcpu_state.fmask.value()); + utcb.write_kernel_gs_base(_vcpu_state.kernel_gs_base.value()); } - if (state().tpr.charged() || state().tpr_threshold.charged()) { + if (_vcpu_state.tpr.charged() || _vcpu_state.tpr_threshold.charged()) { utcb.mtd |= Nova::Mtd::TPR; - utcb.write_tpr(state().tpr.value()); - utcb.write_tpr_threshold(state().tpr_threshold.value()); + utcb.write_tpr(_vcpu_state.tpr.value()); + utcb.write_tpr_threshold(_vcpu_state.tpr_threshold.value()); } - if (state().fpu.charged()) { + if (_vcpu_state.xcr0.charged() || _vcpu_state.xss.charged()) { + utcb.xcr0 = _vcpu_state.xcr0.value(); + utcb.xss = _vcpu_state.xss.value(); + + utcb.mtd |= Nova::Mtd::XSAVE; + } + + if (_vcpu_state.fpu.charged()) { utcb.mtd |= Nova::Mtd::FPU; - state().fpu.with_state([] (Vcpu_state::Fpu::State const &fpu) { - asm volatile ("fxrstor %0" : : "m" (fpu) : "memory"); + _vcpu_state.fpu.with_state([&] (Vcpu_state::Fpu::State const &fpu) { + memcpy(utcb.fpu, &fpu, sizeof(fpu)); }); } } -void Nova_vcpu::run() -{ - if (!_ep_handler) { - /* not started yet - trigger startup of native vCPU */ - call(); - return; - } - - Thread * const current = Thread::myself(); - - if (_dispatching == current) { - _block = false; - return; - } - - if ((_ep_handler == current) && !_block) - return; - - if (_ep_handler != current) - _remote = RUN; - - Nova::ec_ctrl(Nova::EC_RECALL, _ec_sel()); - Nova::sm_ctrl(_sm_sel(), Nova::SEMAPHORE_UP); -} - - /* * Do not touch the UTCB before _read_nova_state() and after * _write_nova_state(), particularly not by logging diagnostics. */ -bool Nova_vcpu::_handle_exit(Nova::Utcb &utcb, uint16_t exit_reason, uint8_t const &fpu) +void Nova_vcpu::_handle_exit(Nova::Utcb &utcb) { - /* reset blocking state */ - bool const previous_blocked = _block; - _block = true; - - /* NOVA specific exit reasons */ - enum { VM_EXIT_STARTUP = 0xfe, VM_EXIT_RECALL = 0xff }; - - if (exit_reason == VM_EXIT_STARTUP) - _ep_handler = Thread::myself(); - - /* transform state from NOVA to Genode */ - if (exit_reason != VM_EXIT_RECALL || !previous_blocked) - _read_nova_state(utcb, exit_reason, fpu); - - if (exit_reason == VM_EXIT_RECALL) { - if (previous_blocked) - state().exit_reason = exit_reason; - - /* consume potential multiple sem ups */ - Nova::sm_ctrl(_sm_sel(), Nova::SEMAPHORE_UP); - Nova::sm_ctrl(_sm_sel(), Nova::SEMAPHORE_DOWNZERO); - - if (_remote == PAUSE) { - _remote = NONE; - } else { - if (_remote == RUN) { - _remote = NONE; - if (!previous_blocked) { - /* still running - reply without state transfer */ - _block = false; - utcb.items = 0; - utcb.mtd = 0; - return false; - } - } - - if (previous_blocked) { - /* resume vCPU - with vCPU state update */ - _block = false; - _write_nova_state(utcb); - return false; - } - } + if (utcb.exit_reason == VM_EXIT_RECALL) { + /* + * A recall exit is only requested from an asynchronous Signal to the + * vCPU Handler. In that case, VM_EXIT_RECALL has already been processed + * asynchronously by getting and setting the state via system calls and + * the regular exit does not need to be processed. + */ + utcb.mtd = 0; + utcb.items = 0; + return; } + _read_nova_state(utcb); + try { _dispatching = Thread::myself(); /* call dispatch handler */ @@ -647,84 +593,99 @@ bool Nova_vcpu::_handle_exit(Nova::Utcb &utcb, uint16_t exit_reason, uint8_t con throw; } - if (_block) { - /* block vCPU in kernel - no vCPU state update */ - utcb.items = 0; - utcb.mtd = 0; - return true; - } - /* reply to NOVA and transfer vCPU state */ _write_nova_state(utcb); - return false; +} + + +void Nova_vcpu::with_state(Call_with_state &cw) +{ + Thread *myself = Thread::myself(); + bool remote = (_dispatching != myself); + Nova::Utcb &utcb = *reinterpret_cast(myself->utcb()); + + if (remote) { + if (Thread::myself() != _ep_handler) { + error("vCPU state requested outside of vcpu_handler EP"); + sleep_forever(); + }; + + Exit_config config { }; + Nova::Mtd mtd = _portal_mtd(0, config); + + uint8_t res = Nova::ec_ctrl(Nova::EC_GET_VCPU_STATE, _ec_sel(), mtd.value()); + + if (res != Nova::NOVA_OK) { + error("Getting vCPU state failed with: ", res); + sleep_forever(); + }; + + _read_nova_state(utcb); + } + + _resume = cw.call_with_state(_vcpu_state); + + if (remote) { + _write_nova_state(utcb); + /* + * A recall is needed + * a) when the vCPU should be stopped or + * b) when the vCPU should be resumed from a stopped state. + */ + bool recall = !(_resume && _last_resume); + + uint8_t res = Nova::ec_ctrl(Nova::EC_SET_VCPU_STATE, _ec_sel(), recall); + + if (res != Nova::NOVA_OK) { + error("Setting vCPU state failed with: ", res); + sleep_forever(); + }; + + /* + * Resume the vCPU and indicate to the next exit if state + * needs to be synced or not. + */ + if (_resume) + Nova::sm_ctrl(_sm_sel(), Nova::SEMAPHORE_UP); + } +} + + +static void nova_reply(Thread &myself, Nova::Utcb &utcb, auto &&... args) +{ + Receive_window &rcv_window = myself.native_thread().server_rcv_window; + + /* reset receive window to values expected by RPC server code */ + rcv_window.prepare_rcv_window(utcb); + + Nova::reply(myself.stack_top(), args...); } void Nova_vcpu::_exit_entry(addr_t badge) { - uint8_t _fpu_at_exit[512] __attribute__((aligned(0x10))); - if (Badge(badge).fpu_usage()) - asm volatile ("fxsave %0" : "=m" (*_fpu_at_exit) :: "memory"); - Thread &myself = *Thread::myself(); Nova::Utcb &utcb = *reinterpret_cast(myself.utcb()); - uint16_t const exit_reason { Badge(badge).exit_reason() }; Vcpu_space::Id const vcpu_id { Badge(badge).vcpu_id() }; - try { - _vcpu_space().apply(vcpu_id, [&] (Nova_vcpu &vcpu) - { - bool const block = vcpu._handle_exit(utcb, exit_reason, - *_fpu_at_exit); + _vcpu_space().apply(vcpu_id, + [&] (Nova_vcpu &vcpu) { + vcpu._handle_exit(utcb); - if (block) { - Nova::reply(myself.stack_top(), vcpu._sm_sel()); + vcpu._last_resume = vcpu._resume; + if (vcpu._resume) { + nova_reply(myself, utcb); } else { - Nova::reply(myself.stack_top()); + nova_reply(myself, utcb, vcpu._sm_sel()); } + }, + [&] /* missing */ { + /* somebody called us directly ? ... ignore/deny */ + utcb.items = 0; + utcb.mtd = 0; + nova_reply(myself, utcb); }); - - } catch (Vcpu_space::Unknown_id &) { - - /* somebody called us directly ? ... ignore/deny */ - utcb.items = 0; - utcb.mtd = 0; - Nova::reply(myself.stack_top()); - } -} - - -void Nova_vcpu::pause() -{ - Thread * const current = Thread::myself(); - - if (_dispatching == current) { - /* current thread is already dispatching */ - if (_block) - /* issue pause exit next time - fall through */ - _block = false; - else { - _block = true; - return; - } - } - - if ((_ep_handler == current) && _block) { - _remote = PAUSE; - /* already blocked */ - } - - if (_ep_handler != current) - _remote = PAUSE; - - if (!_ep_handler) { - /* not started yet - let startup handler issue the recall */ - return; - } - - Nova::ec_ctrl(Nova::EC_RECALL, _ec_sel()); - Nova::sm_ctrl(_sm_sel(), Nova::SEMAPHORE_UP); } @@ -743,7 +704,7 @@ Signal_context_capability Nova_vcpu::_create_exit_handler(Pd_session &pd, Native_capability vm_exit_cap = native_pd.alloc_rpc_cap(thread_cap, (addr_t)Nova_vcpu::_exit_entry, mtd.value()); - Badge const badge { vcpu_id, exit_reason, !!(mtd.value() & Nova::Mtd::FPU) }; + Badge const badge { vcpu_id, exit_reason }; native_pd.imprint_rpc_cap(vm_exit_cap, badge.value()); return reinterpret_cap_cast(vm_exit_cap); @@ -755,7 +716,7 @@ Capability Nova_vcpu::_create_vcpu(Vm_connection &v { Thread &tep { *reinterpret_cast(&handler.rpc_ep()) }; - return vm.with_upgrade([&] () { + return vm.with_upgrade([&] { return vm.call(tep.cap()); }); } @@ -773,6 +734,8 @@ Nova_vcpu::Nova_vcpu(Env &env, Vm_connection &vm, Allocator &alloc, if (_id_elem.id().value > 0xffff) throw Vcpu_id_space_exhausted(); + _ep_handler = reinterpret_cast(&handler.rpc_ep()); + uint16_t const vcpu_id = (uint16_t)_id_elem.id().value; Signal_context_capability dontcare_exit = @@ -797,14 +760,13 @@ Nova_vcpu::Nova_vcpu(Env &env, Vm_connection &vm, Allocator &alloc, ** vCPU API ** **************/ -void Vm_connection::Vcpu::run() { static_cast(_native_vcpu).run(); } -void Vm_connection::Vcpu::pause() { static_cast(_native_vcpu).pause(); } -Vcpu_state & Vm_connection::Vcpu::state() { return static_cast(_native_vcpu).state(); } +void Vm_connection::Vcpu::_with_state(Call_with_state &cw) { static_cast(_native_vcpu).with_state(cw); } Vm_connection::Vcpu::Vcpu(Vm_connection &vm, Allocator &alloc, Vcpu_handler_base &handler, Exit_config const &exit_config) : _native_vcpu(*new (alloc) Nova_vcpu(vm._env, vm, alloc, handler, exit_config)) -{ } - +{ + static_cast(_native_vcpu).startup(); +} diff --git a/repos/base-nova/src/test/platform/ipc.cc b/repos/base-nova/src/test/nova/ipc.cc similarity index 100% rename from repos/base-nova/src/test/platform/ipc.cc rename to repos/base-nova/src/test/nova/ipc.cc diff --git a/repos/base-nova/src/test/nova/main.cc b/repos/base-nova/src/test/nova/main.cc new file mode 100644 index 0000000000..2408639b82 --- /dev/null +++ b/repos/base-nova/src/test/nova/main.cc @@ -0,0 +1,754 @@ +/* + * \brief Some platform tests for the base-nova + * \author Alexander Boettcher + * \date 2015-01-02 + * + */ + +/* + * Copyright (C) 2015-2020 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#include "server.h" + +static unsigned failed = 0; + +static unsigned check_pat = 1; + +using namespace Genode; + +void test_translate(Genode::Env &env) +{ + enum { STACK_SIZE = 4096 }; + static Rpc_entrypoint ep(&env.pd(), STACK_SIZE, "rpc_ep_translate", + Affinity::Location()); + + Test::Component component; + Test::Capability session_cap = ep.manage(&component); + Test::Client client(session_cap); + + Genode::addr_t local_name = Native_thread::INVALID_INDEX; + + long rpc = Test::cap_void_manual(session_cap, session_cap, local_name); + if (rpc != Genode::Rpc_exception_code::SUCCESS || + local_name == (addr_t)session_cap.local_name() || + local_name == (addr_t)Native_thread::INVALID_INDEX) + { + failed ++; + error(__func__, ": ipc call failed ", Hex(rpc)); + ep.dissolve(&component); + return; + } + + Genode::Native_capability copy1 = Capability_space::import(local_name); + + rpc = Test::cap_void_manual(session_cap, copy1, local_name); + if (rpc != Genode::Rpc_exception_code::SUCCESS || + local_name == (addr_t)copy1.local_name() || + local_name == (addr_t)Native_thread::INVALID_INDEX) + { + failed ++; + error(__func__, ": ipc call failed ", Hex(rpc)); + ep.dissolve(&component); + return; + } + + Genode::Native_capability copy2 = Capability_space::import(local_name); + + log("delegation session_cap->copy1->copy2 ", + session_cap, "->", copy1, "->", copy2); + + /* sanity checks translate which must work */ + Genode::Native_capability got_cap = client.cap_cap(copy2.local_name()); + if (got_cap.local_name() != copy1.local_name()) { + failed ++; + error(__LINE__, ":", __func__, " translate failed"); + ep.dissolve(&component); + return; + } + + got_cap = client.cap_cap(copy1.local_name()); + if (got_cap.local_name() != session_cap.local_name()) { + failed ++; + error(__LINE__, ":", __func__, " translate failed"); + ep.dissolve(&component); + return; + } + + got_cap = client.cap_cap(session_cap.local_name()); + if (got_cap.local_name() != session_cap.local_name()) { + failed ++; + error(__LINE__, ":", __func__, " translate failed"); + ep.dissolve(&component); + return; + } + + /** + * Test special revoke by make the intermediate cap (copy1) inaccessible + * and check that translate of copy2 get the right results. + */ + + Nova::Obj_crd crd_ses(copy1.local_name(), 0); + enum { SELF = true, LOCAL_REVOKE = false, LOCAL_PD = 0, NO_BLOCKING = 0, KEEP_IN_MDB = true }; + Nova::revoke(crd_ses, SELF, LOCAL_REVOKE, LOCAL_PD, NO_BLOCKING, KEEP_IN_MDB); + + crd_ses = Nova::Obj_crd(copy1.local_name(), 0); + Genode::uint8_t res = Nova::lookup(crd_ses); + if (res != Nova::NOVA_OK || !crd_ses.is_null()) { + failed ++; + error(__LINE__, " - lookup call failed err=", Hex(res)); + ep.dissolve(&component); + return; + } + + /* copy1 should be skipped and session_cap is the valid response */ + got_cap = client.cap_cap(copy2.local_name()); + if (got_cap.local_name() != session_cap.local_name()) { + failed ++; + error(__LINE__, ":", __func__, " translate failed"); + ep.dissolve(&component); + return; + } + + ep.dissolve(&component); +} + +void test_revoke(Genode::Env &env) +{ + enum { STACK_SIZE = 4096 }; + static Rpc_entrypoint ep(&env.pd(), STACK_SIZE, "rpc_ep_revoke", + Affinity::Location()); + + Test::Component component; + Test::Capability session_cap = ep.manage(&component); + Test::Client client(session_cap); + + Genode::addr_t local_name = Native_thread::INVALID_INDEX; + + long rpc = Test::cap_void_manual(session_cap, session_cap, local_name); + if (rpc != Genode::Rpc_exception_code::SUCCESS || + local_name == (addr_t)session_cap.local_name() || + local_name == (addr_t)Native_thread::INVALID_INDEX) + { + failed ++; + error("test_revoke ipc call failed ", Hex(rpc)); + ep.dissolve(&component); + return; + } + + Genode::Native_capability copy_session_cap = Capability_space::import(local_name); + + local_name = Native_thread::INVALID_INDEX; + rpc = Test::cap_void_manual(copy_session_cap, copy_session_cap, local_name); + if (rpc != Genode::Rpc_exception_code::SUCCESS || + local_name == (addr_t)copy_session_cap.local_name() || + local_name == (addr_t)Native_thread::INVALID_INDEX || + local_name == (addr_t)session_cap.local_name()) + { + failed ++; + error("test_revoke ipc call failed ", Hex(rpc)); + ep.dissolve(&component); + return; + } + + Nova::Obj_crd crd_dst(local_name, 0); + Genode::uint8_t res = Nova::lookup(crd_dst); + if (res != Nova::NOVA_OK || crd_dst.base() != local_name || crd_dst.type() != 3 || + crd_dst.order() != 0) { + failed ++; + error(__LINE__, " - lookup call failed ", Hex(res)); + ep.dissolve(&component); + return; + } + + Nova::Obj_crd crd_ses(copy_session_cap.local_name(), 0); + res = Nova::lookup(crd_ses); + if (res != Nova::NOVA_OK || crd_ses.base() != (addr_t)copy_session_cap.local_name() + || crd_ses.type() != 3 || crd_ses.order() != 0) { + failed ++; + error(__LINE__, " - lookup call failed err=", Hex(res), " is_null=", crd_ses.is_null()); + ep.dissolve(&component); + return; + } + + res = Nova::lookup(crd_dst); + if (res != Nova::NOVA_OK || crd_dst.base() != local_name || crd_dst.type() != 3 || + crd_dst.order() != 0) { + failed ++; + error(__LINE__, " - lookup call failed err=", Hex(res), " is_null=", crd_dst.is_null()); + ep.dissolve(&component); + return; + } + + crd_ses = Nova::Obj_crd(copy_session_cap.local_name(), 0); + enum { SELF = true, LOCAL_REVOKE = false, LOCAL_PD = 0, NO_BLOCKING = 0, KEEP_IN_MDB = true }; + Nova::revoke(crd_ses, SELF, LOCAL_REVOKE, LOCAL_PD, NO_BLOCKING, KEEP_IN_MDB); + + crd_ses = Nova::Obj_crd(copy_session_cap.local_name(), 0); + res = Nova::lookup(crd_ses); + if (res != Nova::NOVA_OK || !crd_ses.is_null()) { + failed ++; + error(__LINE__, " - lookup call failed err=", Hex(res)); + ep.dissolve(&component); + return; + } + + res = Nova::lookup(crd_dst); + if (res != Nova::NOVA_OK || crd_dst.base() != local_name || crd_dst.type() != 3 || + crd_dst.order() != 0) { + failed ++; + error(__LINE__, " - lookup call failed err=", Hex(res), " is_null=", crd_dst.is_null()); + ep.dissolve(&component); + return; + } + + /* + * Request some other capability and place it on very same selector + * as used before by copy_session_cap + */ + Genode::Thread * myself = Genode::Thread::myself(); + request_native_ec_cap(myself->native_thread().exc_pt_sel + Nova::PT_SEL_PAGE_FAULT, + copy_session_cap.local_name()); + + /* check whether the requested cap before is valid and placed well */ + crd_ses = Nova::Obj_crd(copy_session_cap.local_name(), 0); + res = Nova::lookup(crd_ses); + if (res != Nova::NOVA_OK || crd_ses.base() != (addr_t)copy_session_cap.local_name() || + crd_ses.type() != 3 || crd_ses.order() != 0) { + failed ++; + error(__LINE__, " - lookup call failed err=", Hex(res), " is_null=", crd_ses.is_null()); + ep.dissolve(&component); + return; + } + + /* revoke it */ + Nova::revoke(crd_ses, SELF, LOCAL_REVOKE, LOCAL_PD, NO_BLOCKING); + + /* the delegated cap to the client should still be there */ + res = Nova::lookup(crd_dst); + if (res != Nova::NOVA_OK || crd_dst.base() != local_name || crd_dst.type() != 3 || + crd_dst.order() != 0) { + failed ++; + error(__LINE__, " - lookup call failed err=", Hex(res), " is_null=", crd_dst.is_null()); + ep.dissolve(&component); + return; + } + + /* kill the original session capability */ + ep.dissolve(&component); + /* manually: cap.free_rpc_cap(session_cap); */ + + /* the delegated cap to the client should be now invalid */ + res = Nova::lookup(crd_dst); + if (res != Nova::NOVA_OK || !crd_dst.is_null()) { + failed ++; + error(__LINE__, " - lookup call failed err=", Hex(res), " is_null=", crd_dst.is_null()); + return; + } +} + +static void portal_entry() +{ + Genode::Thread &myself = *Genode::Thread::myself(); + Nova::Utcb &utcb = *reinterpret_cast(myself.utcb()); + + Nova::Crd const snd_crd(utcb.msg()[0]); + + enum { + HOTSPOT = 0, USER_PD = false, HOST_PGT = false, SOLELY_MAP = false, + NO_DMA = false, EVILLY_DONT_WRITE_COMBINE = false + }; + + utcb.set_msg_word(0); + bool ok = utcb.append_item(snd_crd, HOTSPOT, USER_PD, HOST_PGT, + SOLELY_MAP, NO_DMA, EVILLY_DONT_WRITE_COMBINE); + (void)ok; + + Nova::reply(myself.stack_top()); +} + +void test_pat(Genode::Env &env) +{ + Genode::Thread &myself = *Genode::Thread::myself(); + Nova::Utcb &utcb = *reinterpret_cast(myself.utcb()); + + /* read out the tsc frequenzy once */ + Attached_rom_dataspace const platform_info (env, "platform_info"); + Xml_node const hardware = platform_info.xml().sub_node("hardware"); + uint64_t const tsc_freq = hardware.sub_node("tsc").attribute_value("freq_khz", 1ULL); + + enum { DS_ORDER = 12, PAGE_4K = 12 }; + + Attached_dataspace ds { env.rm(), env.ram().alloc (1 << (DS_ORDER + PAGE_4K), + WRITE_COMBINED) }; + addr_t const map_addr = addr_t(ds.local_addr()); + + enum { STACK_SIZE = 4096 }; + + static Rpc_entrypoint ep(&env.pd(), STACK_SIZE, "rpc_ep_pat", + Affinity::Location()); + + Genode::Rm_connection rm(env); + Genode::Region_map_client rm_free_area(rm.create(1 << (DS_ORDER + PAGE_4K))); + + Attached_dataspace remap { env.rm(), rm_free_area.dataspace() }; + + addr_t const remap_addr = addr_t(remap.local_addr()); + + /* trigger mapping of whole area */ + for (addr_t i = map_addr; i < map_addr + (1 << (DS_ORDER + PAGE_4K)); i += (1 << PAGE_4K)) + touch_read(reinterpret_cast(map_addr)); + + /* + * Establish memory mapping with evilly wrong mapping attributes + */ + Nova_native_pd_client native_pd { env.pd().native_pd() }; + Thread * thread = reinterpret_cast(&ep); + Native_capability const thread_cap + = Capability_space::import(thread->native_thread().ec_sel); + + Untyped_capability const pt = + native_pd.alloc_rpc_cap(thread_cap, (addr_t)portal_entry, 0 /* MTD */); + + Nova::Rights const all(true, true, true); + Nova::Mem_crd const rcv_crd(remap_addr >> PAGE_4K, DS_ORDER, all); + Nova::Mem_crd const snd_crd(map_addr >> PAGE_4K, DS_ORDER, all); + Nova::Crd const old_crd = utcb.crd_rcv; + + utcb.crd_rcv = rcv_crd; + utcb.set_msg_word(1); + utcb.msg()[0] = snd_crd.value(); + + uint8_t const res = Nova::call(pt.local_name()); + utcb.crd_rcv = old_crd; + + if (res != Nova::NOVA_OK) { + Genode::error("establishing memory failed ", res); + failed++; + } + + /* sanity check - touch re-mapped area */ + for (addr_t i = remap_addr; i < remap_addr + (1 << (DS_ORDER + PAGE_4K)); i += (1 << PAGE_4K)) + touch_read(reinterpret_cast(remap_addr)); + + /* + * measure time to write to the memory + */ + memset(reinterpret_cast(map_addr), 0, 1 << (DS_ORDER + PAGE_4K)); + Trace::Timestamp map_start = Trace::timestamp(); + memset(reinterpret_cast(map_addr), 0, 1 << (DS_ORDER + PAGE_4K)); + Trace::Timestamp map_end = Trace::timestamp(); + + memset(reinterpret_cast(remap_addr), 0, 1 << (DS_ORDER + PAGE_4K)); + Trace::Timestamp remap_start = Trace::timestamp(); + memset(reinterpret_cast(remap_addr), 0, 1 << (DS_ORDER + PAGE_4K)); + Trace::Timestamp remap_end = Trace::timestamp(); + + Trace::Timestamp map_run = map_end - map_start; + Trace::Timestamp remap_run = remap_end - remap_start; + + Trace::Timestamp diff_run = map_run > remap_run ? map_run - remap_run : remap_run - map_run; + + if (check_pat && diff_run * 100 / tsc_freq) { + failed ++; + + error("map=", Hex(map_run), " remap=", Hex(remap_run), " --> " + "diff=", Hex(diff_run), " freq_tsc=", tsc_freq, " ", + diff_run * 1000 / tsc_freq, " us"); + } + + Nova::revoke(Nova::Mem_crd(remap_addr >> PAGE_4K, DS_ORDER, all)); +} + +void test_server_oom(Genode::Env &env) +{ + using namespace Genode; + + enum { STACK_SIZE = 4096 }; + + static Rpc_entrypoint ep(&env.pd(), STACK_SIZE, "rpc_ep_oom", + Affinity::Location()); + + Test::Component component; + Test::Capability session_cap = ep.manage(&component); + Test::Client client(session_cap); + + /* case that during reply we get oom */ + for (unsigned i = 0; i < 20000; i++) { + Genode::Native_capability got_cap = client.void_cap(); + + if (!got_cap.valid()) { + error(i, " cap id ", Hex(got_cap.local_name()), " invalid"); + failed ++; + break; + } + + /* be evil and keep this cap by manually incrementing the ref count */ + Cap_index idx(cap_map().find(got_cap.local_name())); + idx.inc(); + + if (i % 5000 == 4999) + log("received ", i, ". cap"); + } + + /* XXX this code does does no longer work since the removal of 'solely_map' */ +#if 0 + + /* case that during send we get oom */ + for (unsigned i = 0; i < 20000; i++) { + /* be evil and switch translation off - server ever uses a new selector */ + Genode::Native_capability send_cap = session_cap; + send_cap.solely_map(); + + if (!client.cap_void(send_cap)) { + error("sending ", i, ". cap failed"); + failed ++; + break; + } + + if (i % 5000 == 4999) + log("sent ", i, ". cap"); + } +#endif + + ep.dissolve(&component); +} + +class Pager : private Genode::Thread { + + private: + + Native_capability _call_to_map { }; + Attached_ram_dataspace _ds; + static addr_t _ds_mem; + + void entry() override { } + + static void page_fault() + { + Thread * myself = Thread::myself(); + Nova::Utcb * utcb = reinterpret_cast(myself->utcb()); + + if (utcb->msg_words() != 1) { + Genode::error("unexpected"); + while (1) { } + } + + Genode::addr_t map_from = utcb->msg()[0]; +// Genode::error("pager: got map request ", Genode::Hex(map_from)); + + utcb->set_msg_word(0); + utcb->mtd = 0; + + Nova::Mem_crd crd_map(map_from >> 12, 0, Nova::Rights(true, true, true)); + bool res = utcb->append_item(crd_map, 0); + (void)res; + + Nova::reply(myself->stack_top()); + } + + public: + + Pager(Genode::Env &env, Location location) + : + Thread(env, "pager", 0x1000, location, Weight(), env.cpu()), + _ds(env.ram(), env.rm(), 4096) + { + _ds_mem = addr_t(_ds.local_addr()); + + touch_read(reinterpret_cast(_ds_mem)); + + /* request creation of a 'local' EC */ + Thread::native_thread().ec_sel = Native_thread::INVALID_INDEX - 1; + Thread::start(); + + Genode::warning("pager: created"); + + Native_capability thread_cap = + Capability_space::import(Thread::native_thread().ec_sel); + + Genode::Nova_native_pd_client native_pd(env.pd().native_pd()); + Nova::Mtd mtd (Nova::Mtd::QUAL | Nova::Mtd::EIP | Nova::Mtd::ESP); + Genode::addr_t entry = reinterpret_cast(page_fault); + + _call_to_map = native_pd.alloc_rpc_cap(thread_cap, entry, + mtd.value()); + } + + Native_capability call_to_map() { return _call_to_map; } + addr_t mem_st() { return _ds_mem; } +}; + +addr_t Pager::_ds_mem; + +class Cause_mapping : public Genode::Thread { + + private: + + Native_capability _call_to_map { }; + Rm_connection _rm; + Region_map_client _sub_rm; + Attached_dataspace _mem_ds; + addr_t _mem_nd = addr_t(_mem_ds.local_addr()); + addr_t _mem_st; + Nova::Rights const _mapping_rwx = {true, true, true}; + + public: + + unsigned volatile called = 0; + + Cause_mapping(Genode::Env &env, Native_capability call_to_map, + Genode::addr_t mem_st, Location location) + : + Thread(env, "mapper", 0x1000, location, Weight(), env.cpu()), + _call_to_map(call_to_map), + _rm(env), + _sub_rm(_rm.create(0x2000)), + _mem_ds(env.rm(), _sub_rm.dataspace()), + _mem_st(mem_st) + { } + + void entry() override + { + log("mapper: hello"); + + Nova::Utcb * nova_utcb = reinterpret_cast(utcb()); + + while (true) { + called = called + 1; +// log("mapper: request mapping ", Hex(_mem_nd), " ", called); + + Nova::Crd old = nova_utcb->crd_rcv; + +// touch_read((unsigned char *)_mem_st); + + nova_utcb->msg()[0] = _mem_st; + nova_utcb->set_msg_word(1); + nova_utcb->crd_rcv = Nova::Mem_crd(_mem_nd >> 12, 0, + _mapping_rwx); + Nova::call(_call_to_map.local_name()); + //touch_read((unsigned char *)_mem_nd); + + nova_utcb->msg()[0] = _mem_nd; + nova_utcb->set_msg_word(1); + nova_utcb->crd_rcv = Nova::Mem_crd((_mem_nd + 0x1000) >> 12, 0, + _mapping_rwx); + Nova::call(_call_to_map.local_name()); +// touch_read((unsigned char *)_mem_nd + 0x1000); + + nova_utcb->crd_rcv = old; + } + } + + void revoke_remote() + { + Nova::revoke(Nova::Mem_crd(_mem_nd >> 12, 0, _mapping_rwx), true); + } +}; + +void test_delegate_revoke_smp(Genode::Env &env) +{ + Affinity::Space cpus = env.cpu().affinity_space(); + Genode::log("detected ", cpus.width(), "x", cpus.height(), " " + "CPU", cpus.total() > 1 ? "s." : "."); + + Pager pager(env, cpus.location_of_index(1)); + Cause_mapping mapper(env, pager.call_to_map(), pager.mem_st(), + cpus.location_of_index(1)); + mapper.start(); + + for (unsigned i = 0; i < 2000; i++) { + mapper.revoke_remote(); + if (i % 1000 == 0) + Genode::log("main ", i, " ", mapper.called); + } +} + +class Greedy : public Genode::Thread { + + private: + + Genode::Env &_env; + + public: + + Greedy(Genode::Env &env) + : + Thread(env, "greedy", 0x1000), + _env(env) + { } + + void entry() override + { + log("starting"); + + enum { SUB_RM_SIZE = 1280 * 1024 * 1024 }; + + Genode::Ram_dataspace_capability ds = _env.ram().alloc(4096); + + Nova::Rights const mapping_rwx(true, true, true); + + log("cause mappings"); + + for (unsigned i = 0; i < SUB_RM_SIZE / 4096; i++) { + + addr_t const map_to = _env.rm().attach(ds, { }).convert( + [&] (Region_map::Range r) { return r.start; }, + [&] (Region_map::Attach_error) { + error("Greedy: failed to attach RAM dataspace"); + return 0UL; + } + ); + + /* check that we really got the mapping */ + touch_read(reinterpret_cast(map_to)); + + /* print status information in interval of 32M */ + if (i % 8192 == 0) { + log(Hex(i * 4096)); + /* trigger some work to see quota in kernel decreasing */ +// Nova::Rights rwx(true, true, true); +// Nova::revoke(Nova::Mem_crd((map_to - 32 * 1024 * 1024) >> 12, 12, rwx)); + } + } + log("still alive - done"); + } +}; + + +void check(uint8_t res, auto &&... args) +{ + String<128> msg(args...); + + if (res == Nova::NOVA_OK) { + error("res=", res, " ", msg, " - TEST FAILED"); + failed++; + } + else + log("res=", res, " ", msg); +} + + +struct Main +{ + Genode::Env &env; + Genode::Heap heap { env.ram(), env.rm() }; + + Main(Env &env); +}; + + +Main::Main(Env &env) : env(env) +{ + log("testing base-nova platform"); + + { + Attached_rom_dataspace config(env, "config"); + if (!config.xml().has_attribute("check_pat")) { + Genode::error("no check_pat attribute found"); + env.parent().exit(-__LINE__); + return; + } + check_pat = config.xml().attribute_value("check_pat", check_pat); + } + + Thread * myself = Thread::myself(); + if (!myself) { + env.parent().exit(-__LINE__); + return; + } + + /* upgrade available capability indices for this process */ + addr_t index = 512 * 1024; + static char local[128][sizeof(Cap_range)]; + + for (addr_t i = 0; i < sizeof(local) / sizeof (local[0]); i++) { + Cap_range &range = *construct_at(local[i], index); + + cap_map().insert(range); + + index = range.base() + range.elements(); + }; + + addr_t sel_pd = cap_map().insert(); + addr_t sel_ec = myself->native_thread().ec_sel; + addr_t sel_cap = cap_map().insert(); + addr_t handler = 0UL; + uint8_t res = 0; + + Nova::Mtd mtd(Nova::Mtd::ALL); + + if (sel_cap == ~0UL || sel_ec == ~0UL || sel_cap == ~0UL) { + env.parent().exit(-__LINE__); + return; + } + + /* negative syscall tests - they should not succeed */ + res = Nova::create_pt(sel_cap, sel_pd, sel_ec, mtd, handler); + check(res, "create_pt"); + + res = Nova::create_sm(sel_cap, sel_pd, 0); + check(res, "create_sm"); + + /* changing the badge of one of the portal must fail */ + for (unsigned i = 0; i < (1U << Nova::NUM_INITIAL_PT_LOG2); i++) { + addr_t sel_exc = myself->native_thread().exc_pt_sel + i; + res = Nova::pt_ctrl(sel_exc, 0xbadbad); + check(res, "pt_ctrl ", i); + } + + /* test PAT kernel feature */ + test_pat(env); + + /* test special revoke */ + test_revoke(env); + + /* test translate together with special revoke */ + test_translate(env); + + /* test SMP delegate/revoke - skip it on Qemu which takes too long */ + if (check_pat) + test_delegate_revoke_smp(env); + + /** + * Test to provoke out of memory during capability transfer of + * server/client. + * + * Set in hypervisor.ld the memory to a low value of about 1M to let + * trigger the test. + */ + test_server_oom(env); + + /* Test to provoke out of memory in kernel during interaction with core */ + static Greedy core_pagefault_oom(env); + core_pagefault_oom.start(); + core_pagefault_oom.join(); + + if (!failed) + log("Test finished"); + + env.parent().exit(-__LINE__); +} + + +void Component::construct(Genode::Env &env) { static Main main(env); } diff --git a/repos/base-nova/src/test/platform/server.h b/repos/base-nova/src/test/nova/server.h similarity index 97% rename from repos/base-nova/src/test/platform/server.h rename to repos/base-nova/src/test/nova/server.h index cf0651e88f..e17c29a932 100644 --- a/repos/base-nova/src/test/platform/server.h +++ b/repos/base-nova/src/test/nova/server.h @@ -74,7 +74,7 @@ struct Test::Component : Genode::Rpc_object Genode::Native_capability cap_cap(Genode::addr_t); }; -namespace Test { typedef Genode::Capability Capability; } +namespace Test { using Capability = Genode::Capability; } /** * Session implementation diff --git a/repos/base-nova/src/test/nova/target.mk b/repos/base-nova/src/test/nova/target.mk new file mode 100644 index 0000000000..fa8d9717c3 --- /dev/null +++ b/repos/base-nova/src/test/nova/target.mk @@ -0,0 +1,3 @@ +TARGET = test-nova +SRC_CC = main.cc ipc.cc +LIBS = base-nova diff --git a/repos/base-nova/src/test/platform/main.cc b/repos/base-nova/src/test/platform/main.cc deleted file mode 100644 index e8748b667a..0000000000 --- a/repos/base-nova/src/test/platform/main.cc +++ /dev/null @@ -1,748 +0,0 @@ -/* - * \brief Some platform tests for the base-nova - * \author Alexander Boettcher - * \date 2015-01-02 - * - */ - -/* - * Copyright (C) 2015-2020 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include - -#include -#include - -#include "server.h" - -static unsigned failed = 0; - -static unsigned check_pat = 1; - -using namespace Genode; - -void test_translate(Genode::Env &env) -{ - enum { STACK_SIZE = 4096 }; - static Rpc_entrypoint ep(&env.pd(), STACK_SIZE, "rpc_ep_translate", - Affinity::Location()); - - Test::Component component; - Test::Capability session_cap = ep.manage(&component); - Test::Client client(session_cap); - - Genode::addr_t local_name = Native_thread::INVALID_INDEX; - - long rpc = Test::cap_void_manual(session_cap, session_cap, local_name); - if (rpc != Genode::Rpc_exception_code::SUCCESS || - local_name == (addr_t)session_cap.local_name() || - local_name == (addr_t)Native_thread::INVALID_INDEX) - { - failed ++; - error(__func__, ": ipc call failed ", Hex(rpc)); - ep.dissolve(&component); - return; - } - - Genode::Native_capability copy1 = Capability_space::import(local_name); - - rpc = Test::cap_void_manual(session_cap, copy1, local_name); - if (rpc != Genode::Rpc_exception_code::SUCCESS || - local_name == (addr_t)copy1.local_name() || - local_name == (addr_t)Native_thread::INVALID_INDEX) - { - failed ++; - error(__func__, ": ipc call failed ", Hex(rpc)); - ep.dissolve(&component); - return; - } - - Genode::Native_capability copy2 = Capability_space::import(local_name); - - log("delegation session_cap->copy1->copy2 ", - session_cap, "->", copy1, "->", copy2); - - /* sanity checks translate which must work */ - Genode::Native_capability got_cap = client.cap_cap(copy2.local_name()); - if (got_cap.local_name() != copy1.local_name()) { - failed ++; - error(__LINE__, ":", __func__, " translate failed"); - ep.dissolve(&component); - return; - } - - got_cap = client.cap_cap(copy1.local_name()); - if (got_cap.local_name() != session_cap.local_name()) { - failed ++; - error(__LINE__, ":", __func__, " translate failed"); - ep.dissolve(&component); - return; - } - - got_cap = client.cap_cap(session_cap.local_name()); - if (got_cap.local_name() != session_cap.local_name()) { - failed ++; - error(__LINE__, ":", __func__, " translate failed"); - ep.dissolve(&component); - return; - } - - /** - * Test special revoke by make the intermediate cap (copy1) inaccessible - * and check that translate of copy2 get the right results. - */ - - Nova::Obj_crd crd_ses(copy1.local_name(), 0); - enum { SELF = true, LOCAL_REVOKE = false, LOCAL_PD = 0, NO_BLOCKING = 0, KEEP_IN_MDB = true }; - Nova::revoke(crd_ses, SELF, LOCAL_REVOKE, LOCAL_PD, NO_BLOCKING, KEEP_IN_MDB); - - crd_ses = Nova::Obj_crd(copy1.local_name(), 0); - Genode::uint8_t res = Nova::lookup(crd_ses); - if (res != Nova::NOVA_OK || !crd_ses.is_null()) { - failed ++; - error(__LINE__, " - lookup call failed err=", Hex(res)); - ep.dissolve(&component); - return; - } - - /* copy1 should be skipped and session_cap is the valid response */ - got_cap = client.cap_cap(copy2.local_name()); - if (got_cap.local_name() != session_cap.local_name()) { - failed ++; - error(__LINE__, ":", __func__, " translate failed"); - ep.dissolve(&component); - return; - } - - ep.dissolve(&component); -} - -void test_revoke(Genode::Env &env) -{ - enum { STACK_SIZE = 4096 }; - static Rpc_entrypoint ep(&env.pd(), STACK_SIZE, "rpc_ep_revoke", - Affinity::Location()); - - Test::Component component; - Test::Capability session_cap = ep.manage(&component); - Test::Client client(session_cap); - - Genode::addr_t local_name = Native_thread::INVALID_INDEX; - - long rpc = Test::cap_void_manual(session_cap, session_cap, local_name); - if (rpc != Genode::Rpc_exception_code::SUCCESS || - local_name == (addr_t)session_cap.local_name() || - local_name == (addr_t)Native_thread::INVALID_INDEX) - { - failed ++; - error("test_revoke ipc call failed ", Hex(rpc)); - ep.dissolve(&component); - return; - } - - Genode::Native_capability copy_session_cap = Capability_space::import(local_name); - - local_name = Native_thread::INVALID_INDEX; - rpc = Test::cap_void_manual(copy_session_cap, copy_session_cap, local_name); - if (rpc != Genode::Rpc_exception_code::SUCCESS || - local_name == (addr_t)copy_session_cap.local_name() || - local_name == (addr_t)Native_thread::INVALID_INDEX || - local_name == (addr_t)session_cap.local_name()) - { - failed ++; - error("test_revoke ipc call failed ", Hex(rpc)); - ep.dissolve(&component); - return; - } - - Nova::Obj_crd crd_dst(local_name, 0); - Genode::uint8_t res = Nova::lookup(crd_dst); - if (res != Nova::NOVA_OK || crd_dst.base() != local_name || crd_dst.type() != 3 || - crd_dst.order() != 0) { - failed ++; - error(__LINE__, " - lookup call failed ", Hex(res)); - ep.dissolve(&component); - return; - } - - Nova::Obj_crd crd_ses(copy_session_cap.local_name(), 0); - res = Nova::lookup(crd_ses); - if (res != Nova::NOVA_OK || crd_ses.base() != (addr_t)copy_session_cap.local_name() - || crd_ses.type() != 3 || crd_ses.order() != 0) { - failed ++; - error(__LINE__, " - lookup call failed err=", Hex(res), " is_null=", crd_ses.is_null()); - ep.dissolve(&component); - return; - } - - res = Nova::lookup(crd_dst); - if (res != Nova::NOVA_OK || crd_dst.base() != local_name || crd_dst.type() != 3 || - crd_dst.order() != 0) { - failed ++; - error(__LINE__, " - lookup call failed err=", Hex(res), " is_null=", crd_dst.is_null()); - ep.dissolve(&component); - return; - } - - crd_ses = Nova::Obj_crd(copy_session_cap.local_name(), 0); - enum { SELF = true, LOCAL_REVOKE = false, LOCAL_PD = 0, NO_BLOCKING = 0, KEEP_IN_MDB = true }; - Nova::revoke(crd_ses, SELF, LOCAL_REVOKE, LOCAL_PD, NO_BLOCKING, KEEP_IN_MDB); - - crd_ses = Nova::Obj_crd(copy_session_cap.local_name(), 0); - res = Nova::lookup(crd_ses); - if (res != Nova::NOVA_OK || !crd_ses.is_null()) { - failed ++; - error(__LINE__, " - lookup call failed err=", Hex(res)); - ep.dissolve(&component); - return; - } - - res = Nova::lookup(crd_dst); - if (res != Nova::NOVA_OK || crd_dst.base() != local_name || crd_dst.type() != 3 || - crd_dst.order() != 0) { - failed ++; - error(__LINE__, " - lookup call failed err=", Hex(res), " is_null=", crd_dst.is_null()); - ep.dissolve(&component); - return; - } - - /* - * Request some other capability and place it on very same selector - * as used before by copy_session_cap - */ - Genode::Thread * myself = Genode::Thread::myself(); - request_native_ec_cap(myself->native_thread().exc_pt_sel + Nova::PT_SEL_PAGE_FAULT, - copy_session_cap.local_name()); - - /* check whether the requested cap before is valid and placed well */ - crd_ses = Nova::Obj_crd(copy_session_cap.local_name(), 0); - res = Nova::lookup(crd_ses); - if (res != Nova::NOVA_OK || crd_ses.base() != (addr_t)copy_session_cap.local_name() || - crd_ses.type() != 3 || crd_ses.order() != 0) { - failed ++; - error(__LINE__, " - lookup call failed err=", Hex(res), " is_null=", crd_ses.is_null()); - ep.dissolve(&component); - return; - } - - /* revoke it */ - Nova::revoke(crd_ses, SELF, LOCAL_REVOKE, LOCAL_PD, NO_BLOCKING); - - /* the delegated cap to the client should still be there */ - res = Nova::lookup(crd_dst); - if (res != Nova::NOVA_OK || crd_dst.base() != local_name || crd_dst.type() != 3 || - crd_dst.order() != 0) { - failed ++; - error(__LINE__, " - lookup call failed err=", Hex(res), " is_null=", crd_dst.is_null()); - ep.dissolve(&component); - return; - } - - /* kill the original session capability */ - ep.dissolve(&component); - /* manually: cap.free_rpc_cap(session_cap); */ - - /* the delegated cap to the client should be now invalid */ - res = Nova::lookup(crd_dst); - if (res != Nova::NOVA_OK || !crd_dst.is_null()) { - failed ++; - error(__LINE__, " - lookup call failed err=", Hex(res), " is_null=", crd_dst.is_null()); - return; - } -} - -static void portal_entry() -{ - Genode::Thread &myself = *Genode::Thread::myself(); - Nova::Utcb &utcb = *reinterpret_cast(myself.utcb()); - - Nova::Crd const snd_crd(utcb.msg()[0]); - - enum { - HOTSPOT = 0, USER_PD = false, HOST_PGT = false, SOLELY_MAP = false, - NO_DMA = false, EVILLY_DONT_WRITE_COMBINE = false - }; - - utcb.set_msg_word(0); - bool ok = utcb.append_item(snd_crd, HOTSPOT, USER_PD, HOST_PGT, - SOLELY_MAP, NO_DMA, EVILLY_DONT_WRITE_COMBINE); - (void)ok; - - Nova::reply(myself.stack_top()); -} - -void test_pat(Genode::Env &env) -{ - Genode::Thread &myself = *Genode::Thread::myself(); - Nova::Utcb &utcb = *reinterpret_cast(myself.utcb()); - - /* read out the tsc frequenzy once */ - Attached_rom_dataspace const platform_info (env, "platform_info"); - Xml_node const hardware = platform_info.xml().sub_node("hardware"); - uint64_t const tsc_freq = hardware.sub_node("tsc").attribute_value("freq_khz", 1ULL); - - enum { DS_ORDER = 12, PAGE_4K = 12 }; - - Ram_dataspace_capability ds = env.ram().alloc (1 << (DS_ORDER + PAGE_4K), - WRITE_COMBINED); - addr_t map_addr = env.rm().attach(ds); - - enum { STACK_SIZE = 4096 }; - - static Rpc_entrypoint ep(&env.pd(), STACK_SIZE, "rpc_ep_pat", - Affinity::Location()); - - Genode::Rm_connection rm(env); - Genode::Region_map_client rm_free_area(rm.create(1 << (DS_ORDER + PAGE_4K))); - addr_t remap_addr = env.rm().attach(rm_free_area.dataspace()); - - /* trigger mapping of whole area */ - for (addr_t i = map_addr; i < map_addr + (1 << (DS_ORDER + PAGE_4K)); i += (1 << PAGE_4K)) - touch_read(reinterpret_cast(map_addr)); - - /* - * Establish memory mapping with evilly wrong mapping attributes - */ - Nova_native_pd_client native_pd { env.pd().native_pd() }; - Thread * thread = reinterpret_cast(&ep); - Native_capability const thread_cap - = Capability_space::import(thread->native_thread().ec_sel); - - Untyped_capability const pt = - native_pd.alloc_rpc_cap(thread_cap, (addr_t)portal_entry, 0 /* MTD */); - - Nova::Rights const all(true, true, true); - Nova::Mem_crd const rcv_crd(remap_addr >> PAGE_4K, DS_ORDER, all); - Nova::Mem_crd const snd_crd(map_addr >> PAGE_4K, DS_ORDER, all); - Nova::Crd const old_crd = utcb.crd_rcv; - - utcb.crd_rcv = rcv_crd; - utcb.set_msg_word(1); - utcb.msg()[0] = snd_crd.value(); - - uint8_t const res = Nova::call(pt.local_name()); - utcb.crd_rcv = old_crd; - - if (res != Nova::NOVA_OK) { - Genode::error("establishing memory failed ", res); - failed++; - } - - /* sanity check - touch re-mapped area */ - for (addr_t i = remap_addr; i < remap_addr + (1 << (DS_ORDER + PAGE_4K)); i += (1 << PAGE_4K)) - touch_read(reinterpret_cast(remap_addr)); - - /* - * measure time to write to the memory - */ - memset(reinterpret_cast(map_addr), 0, 1 << (DS_ORDER + PAGE_4K)); - Trace::Timestamp map_start = Trace::timestamp(); - memset(reinterpret_cast(map_addr), 0, 1 << (DS_ORDER + PAGE_4K)); - Trace::Timestamp map_end = Trace::timestamp(); - - memset(reinterpret_cast(remap_addr), 0, 1 << (DS_ORDER + PAGE_4K)); - Trace::Timestamp remap_start = Trace::timestamp(); - memset(reinterpret_cast(remap_addr), 0, 1 << (DS_ORDER + PAGE_4K)); - Trace::Timestamp remap_end = Trace::timestamp(); - - Trace::Timestamp map_run = map_end - map_start; - Trace::Timestamp remap_run = remap_end - remap_start; - - Trace::Timestamp diff_run = map_run > remap_run ? map_run - remap_run : remap_run - map_run; - - if (check_pat && diff_run * 100 / tsc_freq) { - failed ++; - - error("map=", Hex(map_run), " remap=", Hex(remap_run), " --> " - "diff=", Hex(diff_run), " freq_tsc=", tsc_freq, " ", - diff_run * 1000 / tsc_freq, " us"); - } - - Nova::revoke(Nova::Mem_crd(remap_addr >> PAGE_4K, DS_ORDER, all)); -} - -void test_server_oom(Genode::Env &env) -{ - using namespace Genode; - - enum { STACK_SIZE = 4096 }; - - static Rpc_entrypoint ep(&env.pd(), STACK_SIZE, "rpc_ep_oom", - Affinity::Location()); - - Test::Component component; - Test::Capability session_cap = ep.manage(&component); - Test::Client client(session_cap); - - /* case that during reply we get oom */ - for (unsigned i = 0; i < 20000; i++) { - Genode::Native_capability got_cap = client.void_cap(); - - if (!got_cap.valid()) { - error(i, " cap id ", Hex(got_cap.local_name()), " invalid"); - failed ++; - break; - } - - /* be evil and keep this cap by manually incrementing the ref count */ - Cap_index idx(cap_map().find(got_cap.local_name())); - idx.inc(); - - if (i % 5000 == 4999) - log("received ", i, ". cap"); - } - - /* XXX this code does does no longer work since the removal of 'solely_map' */ -#if 0 - - /* case that during send we get oom */ - for (unsigned i = 0; i < 20000; i++) { - /* be evil and switch translation off - server ever uses a new selector */ - Genode::Native_capability send_cap = session_cap; - send_cap.solely_map(); - - if (!client.cap_void(send_cap)) { - error("sending ", i, ". cap failed"); - failed ++; - break; - } - - if (i % 5000 == 4999) - log("sent ", i, ". cap"); - } -#endif - - ep.dissolve(&component); -} - -class Pager : private Genode::Thread { - - private: - - Native_capability _call_to_map { }; - Ram_dataspace_capability _ds; - static addr_t _ds_mem; - - void entry() override { } - - static void page_fault() - { - Thread * myself = Thread::myself(); - Nova::Utcb * utcb = reinterpret_cast(myself->utcb()); - - if (utcb->msg_words() != 1) { - Genode::error("unexpected"); - while (1) { } - } - - Genode::addr_t map_from = utcb->msg()[0]; -// Genode::error("pager: got map request ", Genode::Hex(map_from)); - - utcb->set_msg_word(0); - utcb->mtd = 0; - - Nova::Mem_crd crd_map(map_from >> 12, 0, Nova::Rights(true, true, true)); - bool res = utcb->append_item(crd_map, 0); - (void)res; - - Nova::reply(myself->stack_top()); - } - - public: - - Pager(Genode::Env &env, Location location) - : - Thread(env, "pager", 0x1000, location, Weight(), env.cpu()), - _ds(env.ram().alloc (4096)) - { - _ds_mem = env.rm().attach(_ds); - touch_read(reinterpret_cast(_ds_mem)); - - /* request creation of a 'local' EC */ - Thread::native_thread().ec_sel = Native_thread::INVALID_INDEX - 1; - Thread::start(); - - Genode::warning("pager: created"); - - Native_capability thread_cap = - Capability_space::import(Thread::native_thread().ec_sel); - - Genode::Nova_native_pd_client native_pd(env.pd().native_pd()); - Nova::Mtd mtd (Nova::Mtd::QUAL | Nova::Mtd::EIP | Nova::Mtd::ESP); - Genode::addr_t entry = reinterpret_cast(page_fault); - - _call_to_map = native_pd.alloc_rpc_cap(thread_cap, entry, - mtd.value()); - } - - Native_capability call_to_map() { return _call_to_map; } - addr_t mem_st() { return _ds_mem; } -}; - -addr_t Pager::_ds_mem; - -class Cause_mapping : public Genode::Thread { - - private: - - Native_capability _call_to_map { }; - Rm_connection _rm; - Region_map_client _sub_rm; - addr_t _mem_nd; - addr_t _mem_st; - Nova::Rights const _mapping_rwx = {true, true, true}; - - public: - - unsigned volatile called = 0; - - Cause_mapping(Genode::Env &env, Native_capability call_to_map, - Genode::addr_t mem_st, Location location) - : - Thread(env, "mapper", 0x1000, location, Weight(), env.cpu()), - _call_to_map(call_to_map), - _rm(env), - _sub_rm(_rm.create(0x2000)), - _mem_nd(env.rm().attach(_sub_rm.dataspace())), - _mem_st(mem_st) - { } - - void entry() override - { - log("mapper: hello"); - - Nova::Utcb * nova_utcb = reinterpret_cast(utcb()); - - while (true) { - called ++; -// log("mapper: request mapping ", Hex(_mem_nd), " ", called); - - Nova::Crd old = nova_utcb->crd_rcv; - -// touch_read((unsigned char *)_mem_st); - - nova_utcb->msg()[0] = _mem_st; - nova_utcb->set_msg_word(1); - nova_utcb->crd_rcv = Nova::Mem_crd(_mem_nd >> 12, 0, - _mapping_rwx); - Nova::call(_call_to_map.local_name()); - //touch_read((unsigned char *)_mem_nd); - - nova_utcb->msg()[0] = _mem_nd; - nova_utcb->set_msg_word(1); - nova_utcb->crd_rcv = Nova::Mem_crd((_mem_nd + 0x1000) >> 12, 0, - _mapping_rwx); - Nova::call(_call_to_map.local_name()); -// touch_read((unsigned char *)_mem_nd + 0x1000); - - nova_utcb->crd_rcv = old; - } - } - - void revoke_remote() - { - Nova::revoke(Nova::Mem_crd(_mem_nd >> 12, 0, _mapping_rwx), true); - } -}; - -void test_delegate_revoke_smp(Genode::Env &env) -{ - Affinity::Space cpus = env.cpu().affinity_space(); - Genode::log("detected ", cpus.width(), "x", cpus.height(), " " - "CPU", cpus.total() > 1 ? "s." : "."); - - Pager pager(env, cpus.location_of_index(1)); - Cause_mapping mapper(env, pager.call_to_map(), pager.mem_st(), - cpus.location_of_index(1)); - mapper.start(); - - for (unsigned i = 0; i < 2000; i++) { - mapper.revoke_remote(); - if (i % 1000 == 0) - Genode::log("main ", i, " ", mapper.called); - } -} - -class Greedy : public Genode::Thread { - - private: - - Genode::Env &_env; - - public: - - Greedy(Genode::Env &env) - : - Thread(env, "greedy", 0x1000), - _env(env) - { } - - void entry() override - { - log("starting"); - - enum { SUB_RM_SIZE = 1280 * 1024 * 1024 }; - - Genode::Ram_dataspace_capability ds = _env.ram().alloc(4096); - - Nova::Rights const mapping_rwx(true, true, true); - - log("cause mappings"); - - for (unsigned i = 0; i < SUB_RM_SIZE / 4096; i++) { - - addr_t map_to = _env.rm().attach(ds); - - /* check that we really got the mapping */ - touch_read(reinterpret_cast(map_to)); - - /* print status information in interval of 32M */ - if (i % 8192 == 0) { - log(Hex(i * 4096)); - /* trigger some work to see quota in kernel decreasing */ -// Nova::Rights rwx(true, true, true); -// Nova::revoke(Nova::Mem_crd((map_to - 32 * 1024 * 1024) >> 12, 12, rwx)); - } - } - log("still alive - done"); - } -}; - -void check(uint8_t res, const char *format, ...) -{ - static char buf[128]; - - va_list list; - va_start(list, format); - - String_console sc(buf, sizeof(buf)); - sc.vprintf(format, list); - - va_end(list); - - if (res == Nova::NOVA_OK) { - error("res=", res, " ", Cstring(buf), " - TEST FAILED"); - failed++; - } - else - log("res=", res, " ", Cstring(buf)); -} - -struct Main -{ - Genode::Env &env; - Genode::Heap heap { env.ram(), env.rm() }; - - Main(Env &env); -}; - -Main::Main(Env &env) : env(env) -{ - log("testing base-nova platform"); - - try { - Attached_rom_dataspace config(env, "config"); - config.xml().attribute("check_pat").value(check_pat); - } catch (...) { - Genode::error("no check_pat attribute found"); - env.parent().exit(-__LINE__); - return; - } - - Thread * myself = Thread::myself(); - if (!myself) { - env.parent().exit(-__LINE__); - return; - } - - /* upgrade available capability indices for this process */ - addr_t index = 512 * 1024; - static char local[128][sizeof(Cap_range)]; - - for (addr_t i = 0; i < sizeof(local) / sizeof (local[0]); i++) { - Cap_range &range = *construct_at(local[i], index); - - cap_map().insert(range); - - index = range.base() + range.elements(); - }; - - addr_t sel_pd = cap_map().insert(); - addr_t sel_ec = myself->native_thread().ec_sel; - addr_t sel_cap = cap_map().insert(); - addr_t handler = 0UL; - uint8_t res = 0; - - Nova::Mtd mtd(Nova::Mtd::ALL); - - if (sel_cap == ~0UL || sel_ec == ~0UL || sel_cap == ~0UL) { - env.parent().exit(-__LINE__); - return; - } - - /* negative syscall tests - they should not succeed */ - res = Nova::create_pt(sel_cap, sel_pd, sel_ec, mtd, handler); - check(res, "create_pt"); - - res = Nova::create_sm(sel_cap, sel_pd, 0); - check(res, "create_sm"); - - /* changing the badge of one of the portal must fail */ - for (unsigned i = 0; i < (1U << Nova::NUM_INITIAL_PT_LOG2); i++) { - addr_t sel_exc = myself->native_thread().exc_pt_sel + i; - res = Nova::pt_ctrl(sel_exc, 0xbadbad); - check(res, "pt_ctrl %2u", i); - } - - /* test PAT kernel feature */ - test_pat(env); - - /* test special revoke */ - test_revoke(env); - - /* test translate together with special revoke */ - test_translate(env); - - /* test SMP delegate/revoke - skip it on Qemu which takes too long */ - if (check_pat) - test_delegate_revoke_smp(env); - - /** - * Test to provoke out of memory during capability transfer of - * server/client. - * - * Set in hypervisor.ld the memory to a low value of about 1M to let - * trigger the test. - */ - test_server_oom(env); - - /* Test to provoke out of memory in kernel during interaction with core */ - static Greedy core_pagefault_oom(env); - core_pagefault_oom.start(); - core_pagefault_oom.join(); - - if (!failed) - log("Test finished"); - - env.parent().exit(-__LINE__); -} - - -void Component::construct(Genode::Env &env) { static Main main(env); } diff --git a/repos/base-nova/src/test/platform/target.mk b/repos/base-nova/src/test/platform/target.mk deleted file mode 100644 index 15c3c49bbf..0000000000 --- a/repos/base-nova/src/test/platform/target.mk +++ /dev/null @@ -1,3 +0,0 @@ -TARGET = test-platform -SRC_CC = main.cc ipc.cc -LIBS = base-nova diff --git a/repos/base-nova/src/timer/nova/main.cc b/repos/base-nova/src/timer/nova/main.cc new file mode 100644 index 0000000000..dea30c022a --- /dev/null +++ b/repos/base-nova/src/timer/nova/main.cc @@ -0,0 +1,415 @@ +/* + * \brief Timer driver for NOVA + * \author Norman Feske + * \date 2024-03-07 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* Genode includes */ +#include +#include +#include +#include +#include +#include + +/* base-internal includes */ +#include + +/* NOVA includes */ +#include + +namespace Timer { + + using namespace Genode; + + struct Tsc { uint64_t tsc; }; + struct Tsc_rate; + struct Clock; + struct Device; + struct Alarm; + struct Root; + struct Session_component; + struct Main; + + using Alarms = Alarm_registry; +} + + +struct Timer::Clock +{ + uint64_t us; + + static constexpr uint64_t MASK = uint64_t(-1); + + uint64_t value() const { return us; } + + void print(Output &out) const { Genode::print(out, us); } +}; + + +struct Timer::Tsc_rate +{ + unsigned long khz; + + static Tsc_rate from_xml(Xml_node const &node) + { + unsigned long khz = 0; + node.with_optional_sub_node("hardware", [&] (Xml_node const &hardware) { + hardware.with_optional_sub_node("tsc", [&] (Xml_node const &tsc) { + khz = tsc.attribute_value("freq_khz", 0UL); }); }); + return { khz }; + } + + Tsc tsc_from_clock(Clock clock) const + { + return { .tsc = (clock.us*khz)/1000 }; + } + + Clock clock_from_tsc(Tsc tsc) const + { + return { .us = (khz > 0) ? (tsc.tsc*1000)/khz : 0 }; + } +}; + + +class Timer::Device +{ + public: + + struct Wakeup_dispatcher : Interface + { + virtual void dispatch_device_wakeup() = 0; + }; + + struct Deadline : Clock { }; + + static constexpr Deadline infinite_deadline { uint64_t(-1) }; + + private: + + Tsc_rate const _tsc_rate; + + struct Waiter : Thread + { + struct Sel /* NOVA kernel-capability selector */ + { + addr_t value; + + static Sel init_signal_sem(Thread &thread) + { + auto const exc_base = thread.native_thread().exc_pt_sel; + + request_signal_sm_cap(exc_base + Nova::PT_SEL_PAGE_FAULT, + exc_base + Nova::SM_SEL_SIGNAL); + + return { exc_base + Nova::SM_SEL_SIGNAL }; + } + + auto down(Tsc deadline) + { + return Nova::sm_ctrl(value, Nova::SEMAPHORE_DOWN, deadline.tsc); + } + + auto up() + { + return Nova::sm_ctrl(value, Nova::SEMAPHORE_UP); + } + }; + + Wakeup_dispatcher &_dispatcher; + + Sel _wakeup_sem { }; /* must be initialize by waiter thread */ + + Mutex _mutex { }; /* protect '_deadline' */ + Tsc _deadline { uint64_t(-1) }; + + Waiter(Env &env, Wakeup_dispatcher &dispatcher) + : + Thread(env, "waiter", 8*1024*sizeof(addr_t)), _dispatcher(dispatcher) + { + start(); + } + + void entry() override + { + _wakeup_sem = Sel::init_signal_sem(*this); + + for (;;) { + + auto deadline_tsc = [&] + { + Mutex::Guard guard(_mutex); + return _deadline; + }; + + /* + * Block until timeout fires or it gets canceled. + * When triggered (not canceled by 'update_deadline'), + * call 'dispatch_device_wakeup'. + */ + if (_wakeup_sem.down(deadline_tsc()) == Nova::NOVA_TIMEOUT) + _dispatcher.dispatch_device_wakeup(); + } + } + + void update_deadline(Tsc const deadline) + { + Mutex::Guard guard(_mutex); + + bool const sooner_than_scheduled = (deadline.tsc < _deadline.tsc); + + _deadline = deadline; + + if (sooner_than_scheduled) + if (_wakeup_sem.up() != Nova::NOVA_OK) + error("unable to cancel already scheduled timeout"); + } + } _waiter; + + public: + + Device(Env &env, Tsc_rate tsc_rate, Wakeup_dispatcher &dispatcher) + : _tsc_rate(tsc_rate), _waiter(env, dispatcher) { } + + Clock now() const + { + return _tsc_rate.clock_from_tsc( Tsc { Trace::timestamp() }); + } + + void update_deadline(Deadline deadline) + { + _waiter.update_deadline(_tsc_rate.tsc_from_clock(deadline)); + } +}; + + +struct Timer::Alarm : Alarms::Element +{ + Session_component &session; + + Alarm(Alarms &alarms, Session_component &session, Clock time) + : + Alarms::Element(alarms, *this, time), session(session) + { } + + void print(Output &out) const; +}; + + +static Timer::Device::Deadline next_deadline(Timer::Alarms &alarms) +{ + using namespace Timer; + + return alarms.soonest(Clock { 0 }).convert( + [&] (Clock soonest) -> Device::Deadline { + + /* scan alarms for a cluster nearby the soonest */ + uint64_t const MAX_DELAY_US = 250; + Device::Deadline result { soonest.us }; + alarms.for_each_in_range(soonest, Clock { soonest.us + MAX_DELAY_US }, + [&] (Alarm const &alarm) { + result.us = max(result.us, alarm.time.us); }); + + return result; + }, + [&] (Alarms::None) { return Device::infinite_deadline; }); +} + + +struct Timer::Session_component : Session_object +{ + Alarms &_alarms; + Mutex &_alarms_mutex; + Device &_device; + + Signal_context_capability _sigh { }; + + Clock const _creation_time = _device.now(); + + uint64_t _local_now_us() const { return _device.now().us - _creation_time.us; } + + struct Period { uint64_t us; }; + + Constructible _period { }; + Constructible _alarm { }; + + Session_component(Env &env, + Resources const &resources, + Label const &label, + Diag const &diag, + Alarms &alarms, + Mutex &alarms_mutex, + Device &device) + : + Session_object(env.ep(), resources, label, diag), + _alarms(alarms), _alarms_mutex(alarms_mutex), _device(device) + { } + + ~Session_component() + { + Mutex::Guard guard(_alarms_mutex); + + _alarm.destruct(); + } + + /** + * Called by Device::Wakeup_dispatcher with '_alarms_mutex' taken + */ + void handle_wakeup() + { + if (_sigh.valid()) + Signal_transmitter(_sigh).submit(); + + if (_period.constructed()) { + Clock const next = _alarm.constructed() + ? Clock { _alarm->time.us + _period->us } + : Clock { _device.now().us + _period->us }; + + _alarm.construct(_alarms, *this, next); + + } else /* response of 'trigger_once' */ { + _alarm.destruct(); + } + } + + /****************************** + ** Timer::Session interface ** + ******************************/ + + void trigger_once(uint64_t rel_us) override + { + Mutex::Guard guard(_alarms_mutex); + + _period.destruct(); + _alarm.destruct(); + + Clock const now = _device.now(); + + rel_us = max(rel_us, 250u); + _alarm.construct(_alarms, *this, Clock { now.us + rel_us }); + + _device.update_deadline(next_deadline(_alarms)); + } + + void trigger_periodic(uint64_t period_us) override + { + Mutex::Guard guard(_alarms_mutex); + + _period.destruct(); + _alarm.destruct(); + + if (period_us) { + period_us = max(period_us, 1000u); + _period.construct(period_us); + handle_wakeup(); + } + + _device.update_deadline(next_deadline(_alarms)); + } + + void sigh(Signal_context_capability sigh) override { _sigh = sigh; } + + uint64_t elapsed_ms() const override { return _local_now_us()/1000; } + uint64_t elapsed_us() const override { return _local_now_us(); } + + void msleep(uint64_t) override { } + void usleep(uint64_t) override { } +}; + + +struct Timer::Root : public Root_component +{ + private: + + Env &_env; + Alarms &_alarms; + Mutex &_alarms_mutex; + Device &_device; + + protected: + + Session_component *_create_session(const char *args) override + { + return new (md_alloc()) + Session_component(_env, + session_resources_from_args(args), + session_label_from_args(args), + session_diag_from_args(args), + _alarms, _alarms_mutex, _device); + } + + void _upgrade_session(Session_component *s, const char *args) override + { + s->upgrade(ram_quota_from_args(args)); + s->upgrade(cap_quota_from_args(args)); + } + + void _destroy_session(Session_component *session) override + { + Genode::destroy(md_alloc(), session); + } + + public: + + Root(Env &env, Allocator &md_alloc, + Alarms &alarms, Mutex &alarms_mutex, Device &device) + : + Root_component(&env.ep().rpc_ep(), &md_alloc), + _env(env), _alarms(alarms), _alarms_mutex(alarms_mutex), _device(device) + { } +}; + + +void Timer::Alarm::print(Output &out) const { Genode::print(out, session.label()); } + + +struct Timer::Main : Device::Wakeup_dispatcher +{ + Env &_env; + + Attached_rom_dataspace _platform_info { _env, "platform_info" }; + + Tsc_rate const _tsc_rate = Tsc_rate::from_xml(_platform_info.xml()); + + Device _device { _env, _tsc_rate, *this }; + + Mutex _alarms_mutex { }; + Alarms _alarms { }; + + Sliced_heap _sliced_heap { _env.ram(), _env.rm() }; + + Root _root { _env, _sliced_heap, _alarms, _alarms_mutex, _device }; + + /** + * Device::Wakeup_dispatcher + */ + void dispatch_device_wakeup() override + { + Mutex::Guard guard(_alarms_mutex); + + /* handle and remove pending alarms */ + while (_alarms.with_any_in_range({ 0 }, _device.now(), [&] (Alarm &alarm) { + alarm.session.handle_wakeup(); })); + + /* schedule next wakeup */ + _device.update_deadline(next_deadline(_alarms)); + } + + Main(Genode::Env &env) : _env(env) + { + if (_tsc_rate.khz == 0) + warning("could not obtain TSC calibration from platform_info ROM"); + + _env.parent().announce(_env.ep().manage(_root)); + } +}; + + +void Component::construct(Genode::Env &env) { static Timer::Main inst(env); } diff --git a/repos/base-nova/src/timer/nova/target.mk b/repos/base-nova/src/timer/nova/target.mk index 7380b2ad97..dd51a9e787 100644 --- a/repos/base-nova/src/timer/nova/target.mk +++ b/repos/base-nova/src/timer/nova/target.mk @@ -1,5 +1,6 @@ -TARGET = nova_timer_drv +TARGET = nova_timer INC_DIR += $(PRG_DIR) -SRC_CC += time_source.cc +SRC_CC += main.cc +LIBS += base -include $(call select_from_repositories,src/timer/target.inc) +REP_INC_DIR += src/include diff --git a/repos/base-nova/src/timer/nova/time_source.cc b/repos/base-nova/src/timer/nova/time_source.cc deleted file mode 100644 index 726526d81b..0000000000 --- a/repos/base-nova/src/timer/nova/time_source.cc +++ /dev/null @@ -1,68 +0,0 @@ -/* - * \brief Time source using Nova timed semaphore down - * \author Alexander Boettcher - * \author Martin Stein - * \date 2014-06-24 - */ - -/* - * Copyright (C) 2014-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -/* NOVA includes */ -#include - -/* local includes */ -#include - -using namespace Genode; -using namespace Nova; - - -void Timer::Time_source::set_timeout(Microseconds duration, - Timeout_handler &handler) -{ - /* set new timeout parameters and wake up the blocking thread */ - Threaded_time_source::handler(handler); - _timeout_us = duration.value; - if (_sem) { - if (Nova::sm_ctrl(_sem, Nova::SEMAPHORE_UP) != Nova::NOVA_OK) { - nova_die(); - } - } -} - - -Timer::Time_source::Result_of_wait_for_irq -Timer::Time_source::_wait_for_irq() -{ - /* initialize semaphore if not done yet */ - if (!_sem) { - auto const &exc_base = Thread::native_thread().exc_pt_sel; - request_signal_sm_cap(exc_base + Nova::PT_SEL_PAGE_FAULT, - exc_base + Nova::SM_SEL_SIGNAL); - - _sem = Thread::native_thread().exc_pt_sel + SM_SEL_SIGNAL; - } - /* calculate absolute timeout */ - unsigned long long const deadline_timestamp { - _timeout_us <= max_timeout().value ? - Trace::timestamp() + _timeout_us * (_tsc_khz / TSC_FACTOR) : 0 }; - - /* block until timeout fires or it gets canceled */ - switch (sm_ctrl(_sem, SEMAPHORE_DOWN, deadline_timestamp)) { - - case Nova::NOVA_TIMEOUT: - return IRQ_TRIGGERED; - - case Nova::NOVA_OK: - return CANCELLED; - - default: - nova_die(); - return CANCELLED; - } -} diff --git a/repos/base-nova/src/timer/nova/time_source.h b/repos/base-nova/src/timer/nova/time_source.h deleted file mode 100644 index c3b4c5128f..0000000000 --- a/repos/base-nova/src/timer/nova/time_source.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * \brief Time source using Nova timed semaphore down - * \author Alexander Boettcher - * \author Martin Stein - * \date 2014-06-24 - */ - -/* - * Copyright (C) 2014-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _TIME_SOURCE_H_ -#define _TIME_SOURCE_H_ - -/* Genode includes */ -#include -#include -#include - -/* local includes */ -#include - -namespace Timer { - - using Genode::uint64_t; - class Time_source; -} - - -class Timer::Time_source : public Threaded_time_source -{ - private: - - /* read the tsc frequency from platform info */ - static unsigned long _obtain_tsc_khz(Genode::Env &env) - { - unsigned long result = 0; - try { - Genode::Attached_rom_dataspace info { env, "platform_info"}; - - result = info.xml().sub_node("hardware") - .sub_node("tsc") - .attribute_value("freq_khz", 0UL); - } catch (...) { } - - if (result) - return result; - - /* - * The returned value must never be zero because it is used as - * divisor by '_tsc_to_us'. - */ - Genode::warning("unable to obtain tsc frequency, assuming 1 GHz"); - return 1000*1000; - } - - Genode::addr_t _sem { 0 }; - uint64_t _timeout_us { 0 }; - unsigned long const _tsc_khz; - Duration _curr_time { Microseconds(0) }; - Genode::Trace::Timestamp _tsc_start { Genode::Trace::timestamp() }; - Genode::Trace::Timestamp _tsc_last { _tsc_start }; - - /* 1 / ((us / (1000 * 1000)) * (tsc_khz * 1000)) */ - enum { TSC_FACTOR = 1000ULL }; - - inline uint64_t _tsc_to_us(uint64_t tsc) const - { - return (tsc) / (_tsc_khz / TSC_FACTOR); - } - - - /************************** - ** Threaded_time_source ** - **************************/ - - Result_of_wait_for_irq _wait_for_irq() override; - - public: - - Time_source(Genode::Env &env) - : - Threaded_time_source(env), _tsc_khz(_obtain_tsc_khz(env)) - { - start(); - } - - /************************* - ** Genode::Time_source ** - *************************/ - - void set_timeout(Microseconds duration, - Timeout_handler &handler) override; - - Microseconds max_timeout() const override - { - return Microseconds(_tsc_to_us(~(uint64_t)0)); - } - - Duration curr_time() override - { - using namespace Genode::Trace; - - Timestamp const curr_tsc = timestamp(); - Microseconds const diff(_tsc_to_us(curr_tsc - _tsc_last)); - - /* update in irq context or if update rate is below 4000 irq/s */ - if (_irq || diff.value > 250) { - _curr_time.add(diff); - _tsc_last = curr_tsc; - } - - return _curr_time; - } -}; - -#endif /* _TIME_SOURCE_H_ */ diff --git a/repos/base-okl4/README b/repos/base-okl4/README index e3da3ffa9a..8105383eae 100644 --- a/repos/base-okl4/README +++ b/repos/base-okl4/README @@ -1,6 +1 @@ -This repository contains the implementation of Genode for the OKL4 -kernel version 2.1. For further information, please refer to the -following website: - -:[http://genode.org/documentation/articles/genode-on-okl4 - Bringing Genode to OKL4]: - This article explains the OKL4-specific porting work. +This repository contains the support of Genode for the OKL4 kernel version 2.1. diff --git a/repos/base-okl4/contrib/generated/README b/repos/base-okl4/contrib/generated/README index 9094cae310..f307febbf1 100644 --- a/repos/base-okl4/contrib/generated/README +++ b/repos/base-okl4/contrib/generated/README @@ -1,8 +1,4 @@ This directory and its subdirectories contain machine-generated code, produced when building the OKL4 kernel with its native Scons build environment. - -It is not part of the Genode project and remains under the licence of the OKL4 kernel. - -You can obtain the OKL4 kernel version 2.1.1. here: - -[http://www.ok-labs.com - Open Kernel Labs] +It is not part of the Genode project and remains under the licence of the OKL4 +kernel. diff --git a/repos/base-okl4/lib/import/import-syscall-okl4.mk b/repos/base-okl4/lib/import/import-syscall-okl4.mk index 030693d8b7..5eaa7633f0 100644 --- a/repos/base-okl4/lib/import/import-syscall-okl4.mk +++ b/repos/base-okl4/lib/import/import-syscall-okl4.mk @@ -1,4 +1,4 @@ -OKL4_DIR = $(call select_from_ports,okl4)/src/kernel/okl4 +OKL4_DIR := $(call select_from_ports,okl4)/src/kernel/okl4 # # Make sure that symlink modification times are handled correctly. diff --git a/repos/base-okl4/lib/mk/base-okl4.mk b/repos/base-okl4/lib/mk/base-okl4.mk index 0fa9cbb360..95ac1ce36f 100644 --- a/repos/base-okl4/lib/mk/base-okl4.mk +++ b/repos/base-okl4/lib/mk/base-okl4.mk @@ -3,7 +3,7 @@ include $(BASE_DIR)/lib/mk/base.inc LIBS += base-okl4-common syscall-okl4 cxx timeout SRC_CC += thread_start.cc SRC_CC += cache.cc +SRC_CC += capability_slab.cc SRC_CC += capability_space.cc SRC_CC += signal_transmitter.cc SRC_CC += signal.cc -SRC_CC += platform.cc diff --git a/repos/base-okl4/lib/mk/kernel-okl4.inc b/repos/base-okl4/lib/mk/kernel-okl4.inc index d1c3bf7429..f0ddf221b4 100644 --- a/repos/base-okl4/lib/mk/kernel-okl4.inc +++ b/repos/base-okl4/lib/mk/kernel-okl4.inc @@ -38,6 +38,7 @@ CC_OPT += -Wno-write-strings -Wredundant-decls -Wundef \ -fno-builtin -fomit-frame-pointer \ -fno-exceptions -fno-unwind-tables \ -fno-asynchronous-unwind-tables \ + -fno-tree-dse \ -finline-limit=99999999 $(addprefix -D,$(CONFIG)) \ "-D__USER__=\"Genode Labs\"" CC_OPT += -DCONFIG_MAX_THREAD_BITS=10 diff --git a/repos/base-okl4/lib/mk/okl4_boot_info.mk b/repos/base-okl4/lib/mk/okl4_boot_info.mk index 74d9a4b07f..63e1bb0757 100644 --- a/repos/base-okl4/lib/mk/okl4_boot_info.mk +++ b/repos/base-okl4/lib/mk/okl4_boot_info.mk @@ -1,7 +1,7 @@ -SRC_C = bootinfo.c -LIBS += syscall-okl4 -INC_DIR += $(REP_DIR)/src/include/bootinfo/internal -CC_WARN = -Wall -Wno-attributes -OKL4_DIR = $(call select_from_ports,okl4)/src/kernel/okl4 +SRC_C = bootinfo.c +LIBS += syscall-okl4 +INC_DIR += $(REP_DIR)/src/include/bootinfo/internal +CC_WARN = -Wall -Wno-attributes +OKL4_DIR := $(call select_from_ports,okl4)/src/kernel/okl4 vpath bootinfo.c $(OKL4_DIR)/libs/bootinfo/src diff --git a/repos/base-okl4/lib/mk/spec/x86/kernel-okl4-include.mk b/repos/base-okl4/lib/mk/spec/x86/kernel-okl4-include.mk index 23796b206c..c5ee413151 100644 --- a/repos/base-okl4/lib/mk/spec/x86/kernel-okl4-include.mk +++ b/repos/base-okl4/lib/mk/spec/x86/kernel-okl4-include.mk @@ -1,4 +1,4 @@ -OKL4_SRC_DIR = $(call select_from_ports,okl4)/src/kernel/okl4 +OKL4_SRC_DIR := $(call select_from_ports,okl4)/src/kernel/okl4 ARCH_DIR = $(OKL4_SRC_DIR)/arch/ia32 PLAT_DIR = $(OKL4_SRC_DIR)/platform/pc99 INC_SYMLINKS = arch/apic.h \ diff --git a/repos/base-okl4/lib/mk/spec/x86/kernel-okl4.mk b/repos/base-okl4/lib/mk/spec/x86/kernel-okl4.mk index bafba103ca..dafeb8e11b 100644 --- a/repos/base-okl4/lib/mk/spec/x86/kernel-okl4.mk +++ b/repos/base-okl4/lib/mk/spec/x86/kernel-okl4.mk @@ -1,4 +1,4 @@ -OKL4_SRC_DIR = $(call select_from_ports,okl4)/src/kernel/okl4 +OKL4_SRC_DIR := $(call select_from_ports,okl4)/src/kernel/okl4 CONFIG = ARCH_IA32 \ CONFIG_ARCH_IA32=1 \ diff --git a/repos/base-okl4/lib/mk/tools.mk b/repos/base-okl4/lib/mk/tools.mk index 40d07e581c..399039581d 100644 --- a/repos/base-okl4/lib/mk/tools.mk +++ b/repos/base-okl4/lib/mk/tools.mk @@ -2,7 +2,7 @@ # Create symlink to elfweaver so that the run tool can use it from within the # build directory. # -OKL4_DIR = $(call select_from_ports,okl4)/src/kernel/okl4 +OKL4_DIR := $(call select_from_ports,okl4)/src/kernel/okl4 HOST_TOOLS += $(BUILD_BASE_DIR)/tool/okl4/elfweaver $(BUILD_BASE_DIR)/tool/okl4/elfweaver: diff --git a/repos/base-okl4/recipes/src/base-okl4/content.mk b/repos/base-okl4/recipes/src/base-okl4/content.mk index 4caca8c8cd..69174fb5c7 100644 --- a/repos/base-okl4/recipes/src/base-okl4/content.mk +++ b/repos/base-okl4/recipes/src/base-okl4/content.mk @@ -21,5 +21,5 @@ content: for spec in x86_32; do \ mv lib/mk/spec/$$spec/ld-okl4.mk lib/mk/spec/$$spec/ld.mk; \ done; - sed -i "s/pit_timer_drv/timer/" src/timer/pit/target.inc + sed -i "s/pit_timer/timer/" src/timer/pit/target.inc diff --git a/repos/base-okl4/recipes/src/base-okl4/hash b/repos/base-okl4/recipes/src/base-okl4/hash index acee3cdeb5..30faaab6bc 100644 --- a/repos/base-okl4/recipes/src/base-okl4/hash +++ b/repos/base-okl4/recipes/src/base-okl4/hash @@ -1 +1 @@ -2022-10-11 b81b8b94731cda35017a740b0110ff4e8e233e07 +2024-08-28 4b22e47966d13c2de61a2d7349bd8fa83520fd1c diff --git a/repos/base-okl4/run/priority.run b/repos/base-okl4/run/priority.run index 7728bcee62..308c62829f 100644 --- a/repos/base-okl4/run/priority.run +++ b/repos/base-okl4/run/priority.run @@ -1,12 +1,12 @@ assert_spec okl4 -build "core init" +build { core init lib/ld } create_boot_directory install_config "[exec cat [genode_dir]/repos/os/src/init/config.priority]" -build_boot_image "core ld.lib.so init" +build_boot_image [build_artifacts] append qemu_args "-nographic " diff --git a/repos/base-okl4/src/core/core_log_out.cc b/repos/base-okl4/src/core/core_log_out.cc index f601a07bc3..fcf503bbaa 100644 --- a/repos/base-okl4/src/core/core_log_out.cc +++ b/repos/base-okl4/src/core/core_log_out.cc @@ -17,7 +17,7 @@ /* base-internal includes */ #include -using namespace Genode; +using namespace Core; void Core_log::out(char const c) { Okl4::L4_KDB_PrintChar(c); } diff --git a/repos/base-okl4/src/core/core_region_map.cc b/repos/base-okl4/src/core/core_region_map.cc index 8540867422..81b17c2f20 100644 --- a/repos/base-okl4/src/core/core_region_map.cc +++ b/repos/base-okl4/src/core/core_region_map.cc @@ -16,56 +16,45 @@ #include #include -using namespace Genode; +using namespace Core; -Region_map::Local_addr -Core_region_map::attach(Dataspace_capability ds_cap, size_t size, - off_t offset, bool use_local_addr, - Region_map::Local_addr, bool, bool) +Region_map::Attach_result +Core_region_map::attach(Dataspace_capability ds_cap, Attr const &attr) { - return _ep.apply(ds_cap, [&] (Dataspace_component *ds) -> void * { - + return _ep.apply(ds_cap, [&] (Dataspace_component *ds) -> Attach_result { if (!ds) - throw Invalid_dataspace(); - - if (size == 0) - size = ds->size(); + return Attach_error::INVALID_DATASPACE; + size_t const size = (attr.size == 0) ? ds->size() : attr.size; size_t const page_rounded_size = (size + get_page_size() - 1) & get_page_mask(); - if (use_local_addr) { - error("parameter 'use_local_addr' not supported within core"); - return nullptr; - } - - if (offset) { - error("parameter 'offset' not supported within core"); - return nullptr; - } + /* attach attributes 'use_at' and 'offset' not supported within core */ + if (attr.use_at || attr.offset) + return Attach_error::REGION_CONFLICT; /* allocate range in core's virtual address space */ Range_allocator &virt_alloc = platform().region_alloc(); - return virt_alloc.try_alloc(page_rounded_size).convert( + return virt_alloc.try_alloc(page_rounded_size).convert( - [&] (void *virt_addr) -> void * { + [&] (void *virt_addr) -> Attach_result { /* map the dataspace's physical pages to virtual memory */ unsigned num_pages = page_rounded_size >> get_page_size_log2(); if (!map_local(ds->phys_addr(), (addr_t)virt_addr, num_pages)) - return nullptr; + return Attach_error::INVALID_DATASPACE; - return virt_addr; + return Range { .start = addr_t(virt_addr), .num_bytes = page_rounded_size }; }, - [&] (Range_allocator::Alloc_error) -> void * { + [&] (Range_allocator::Alloc_error) { error("could not allocate virtual address range in core of size ", page_rounded_size); - return nullptr; + return Attach_error::REGION_CONFLICT; }); }); } -void Core_region_map::detach(Local_addr) { } +void Core_region_map::detach(addr_t) { } diff --git a/repos/base-okl4/src/core/include/ipc_pager.h b/repos/base-okl4/src/core/include/ipc_pager.h index 608522be02..7cd7f42849 100644 --- a/repos/base-okl4/src/core/include/ipc_pager.h +++ b/repos/base-okl4/src/core/include/ipc_pager.h @@ -20,13 +20,13 @@ /* base-internal includes */ #include -/* core-local includes */ +/* core includes */ #include -namespace Genode { class Ipc_pager; } +namespace Core { class Ipc_pager; } -class Genode::Ipc_pager +class Core::Ipc_pager { private: diff --git a/repos/base-okl4/src/core/include/map_local.h b/repos/base-okl4/src/core/include/map_local.h index 66fc2d48cd..794a1efaff 100644 --- a/repos/base-okl4/src/core/include/map_local.h +++ b/repos/base-okl4/src/core/include/map_local.h @@ -14,16 +14,13 @@ #ifndef _CORE__INCLUDE__MAP_LOCAL_H_ #define _CORE__INCLUDE__MAP_LOCAL_H_ -/* Genode includes */ -#include - /* core includes */ #include /* base-internal includes */ #include -namespace Genode { +namespace Core { inline void unmap_local_log2_range(Okl4::L4_Word_t base, Okl4::L4_Word_t size_log2) { diff --git a/repos/base-okl4/src/core/include/platform.h b/repos/base-okl4/src/core/include/platform.h index b096b3d698..4fc2479bfe 100644 --- a/repos/base-okl4/src/core/include/platform.h +++ b/repos/base-okl4/src/core/include/platform.h @@ -32,10 +32,10 @@ namespace Okl4 { extern "C" { #include } } -namespace Genode { class Platform; } +namespace Core { class Platform; } -class Genode::Platform : public Platform_generic +class Core::Platform : public Platform_generic { private: diff --git a/repos/base-okl4/src/core/include/platform_pd.h b/repos/base-okl4/src/core/include/platform_pd.h index 4152629695..a9100cd59c 100644 --- a/repos/base-okl4/src/core/include/platform_pd.h +++ b/repos/base-okl4/src/core/include/platform_pd.h @@ -23,7 +23,7 @@ /* base-internal includes */ #include -namespace Genode { +namespace Core { namespace Thread_id_bits { @@ -39,7 +39,7 @@ namespace Genode { } -class Genode::Platform_pd : public Address_space +class Core::Platform_pd : public Address_space { private: diff --git a/repos/base-okl4/src/core/include/platform_thread.h b/repos/base-okl4/src/core/include/platform_thread.h index bf6c33b0ea..b0a47f8982 100644 --- a/repos/base-okl4/src/core/include/platform_thread.h +++ b/repos/base-okl4/src/core/include/platform_thread.h @@ -23,14 +23,14 @@ #include #include -namespace Genode { +namespace Core { class Platform_pd; class Platform_thread; } -class Genode::Platform_thread +class Core::Platform_thread { private: @@ -47,11 +47,12 @@ class Genode::Platform_thread char _name[32]; /* thread name that will be registered at the kernel debugger */ - Platform_pd *_platform_pd; /* protection domain thread - is bound to */ + Platform_pd &_pd; unsigned _priority; /* thread priority */ Pager_object *_pager; + bool _bound_to_pd = false; + public: enum { THREAD_INVALID = -1 }; /* invalid thread number */ @@ -60,7 +61,7 @@ class Genode::Platform_thread /** * Constructor */ - Platform_thread(size_t, const char *name, + Platform_thread(Platform_pd &pd, size_t, const char *name, unsigned priority, Affinity::Location, addr_t utcb); @@ -68,25 +69,26 @@ class Genode::Platform_thread /** * Constructor used for core-internal threads */ - Platform_thread(char const *name) - : Platform_thread(0, name, 0, Affinity::Location(), 0) { } + Platform_thread(Platform_pd &pd, char const *name) + : Platform_thread(pd, 0, name, 0, Affinity::Location(), 0) { } /** * Destructor */ ~Platform_thread(); + /** + * Return true if thread creation succeeded + */ + bool valid() const { return _bound_to_pd; } + /** * Start thread * - * \param ip instruction pointer to start at - * \param sp stack pointer to use - * \param cpu_no target cpu - * - * \retval 0 successful - * \retval -1 thread could not be started + * \param ip instruction pointer to start at + * \param sp stack pointer to use */ - int start(void *ip, void *sp, unsigned int cpu_no = 0); + void start(void *ip, void *sp); /** * Pause this thread @@ -108,10 +110,8 @@ class Genode::Platform_thread * * \param thread_id local thread ID * \param l4_thread_id final L4 thread ID - * \param pd platform pd, thread is bound to */ - void bind(int thread_id, Okl4::L4_ThreadId_t l4_thread_id, - Platform_pd &pd); + void bind(int thread_id, Okl4::L4_ThreadId_t l4_thread_id); /** * Unbind this thread @@ -120,8 +120,6 @@ class Genode::Platform_thread /** * Override thread state with 's' - * - * \throw Cpu_session::State_access_failed */ void state(Thread_state s); @@ -150,7 +148,7 @@ class Genode::Platform_thread /** * Get the 'Platform_pd' object this thread belongs to */ - Platform_pd* pd() { return _platform_pd; } + Platform_pd &pd() { return _pd; } /** * Return identification of thread when faulting diff --git a/repos/base-okl4/src/core/include/rpc_cap_factory.h b/repos/base-okl4/src/core/include/rpc_cap_factory.h index 8514599aaf..d42c364a6d 100644 --- a/repos/base-okl4/src/core/include/rpc_cap_factory.h +++ b/repos/base-okl4/src/core/include/rpc_cap_factory.h @@ -14,13 +14,17 @@ #ifndef _CORE__INCLUDE__RPC_CAP_FACTORY_H_ #define _CORE__INCLUDE__RPC_CAP_FACTORY_H_ +/* Genode includes */ #include #include -namespace Genode { class Rpc_cap_factory; } +/* core includes */ +#include + +namespace Core { class Rpc_cap_factory; } -class Genode::Rpc_cap_factory +class Core::Rpc_cap_factory { private: diff --git a/repos/base-okl4/src/core/include/util.h b/repos/base-okl4/src/core/include/util.h index cde9413910..7c2ffe940a 100644 --- a/repos/base-okl4/src/core/include/util.h +++ b/repos/base-okl4/src/core/include/util.h @@ -16,14 +16,15 @@ /* Genode includes */ #include -#include -#include #include /* base-internal includes */ #include #include +/* core includes */ +#include + /* * The binding for 'L4_KDB_Enter' on ARM takes a 'char *' as argument, which * prevents us from passing a plain const "string". However, on x86, the @@ -37,7 +38,7 @@ #endif -namespace Genode { +namespace Core { inline void log_event(const char *) { } inline void log_event(const char *, unsigned, unsigned, unsigned) { } @@ -110,7 +111,7 @@ namespace Genode { inline addr_t map_src_addr(addr_t, addr_t phys) { return phys; } - inline size_t constrain_map_size_log2(size_t size_log2) { return size_log2; } + inline Log2 kernel_constrained_map_size(Log2 size) { return size; } } #endif /* _CORE__INCLUDE__UTIL_H_ */ diff --git a/repos/base-okl4/src/core/io_mem_session_support.cc b/repos/base-okl4/src/core/io_mem_session_support.cc index 4b9c8c49ff..6b0422ea42 100644 --- a/repos/base-okl4/src/core/io_mem_session_support.cc +++ b/repos/base-okl4/src/core/io_mem_session_support.cc @@ -16,10 +16,10 @@ #include -using namespace Genode; +using namespace Core; -void Io_mem_session_component::_unmap_local(addr_t, size_t) { } +void Io_mem_session_component::_unmap_local(addr_t, size_t, addr_t) { } addr_t Io_mem_session_component::_map_local(addr_t, size_t) { return 0; } diff --git a/repos/base-okl4/src/core/irq_session_component.cc b/repos/base-okl4/src/core/irq_session_component.cc index c2d838c46e..e8e2bce9e8 100644 --- a/repos/base-okl4/src/core/irq_session_component.cc +++ b/repos/base-okl4/src/core/irq_session_component.cc @@ -13,11 +13,11 @@ */ /* Genode includes */ -#include #include /* core includes */ #include +#include #include /* base-internal includes */ @@ -25,7 +25,7 @@ #include using namespace Okl4; -using namespace Genode; +using namespace Core; /* bit to use for IRQ notifications */ @@ -80,10 +80,11 @@ void Irq_object::_wait_for_irq() } -void Irq_object::start() +Thread::Start_result Irq_object::start() { - ::Thread::start(); + Start_result const result = ::Thread::start(); _sync_bootup.block(); + return result; } @@ -108,7 +109,7 @@ void Irq_object::entry() if (!_sig_cap.valid()) continue; - Genode::Signal_transmitter(_sig_cap).submit(1); + Signal_transmitter(_sig_cap).submit(1); _sync_ack.block(); } @@ -134,7 +135,8 @@ Irq_session_component::Irq_session_component(Range_allocator &irq_alloc, _irq_alloc(irq_alloc), _irq_object(_irq_number) { - long msi = Arg_string::find_arg(args, "device_config_phys").long_value(0); + Irq_args irq_args(args); + bool msi { irq_args.type() != Irq_session::TYPE_LEGACY }; if (msi) throw Service_denied(); @@ -159,7 +161,7 @@ void Irq_session_component::ack_irq() } -void Irq_session_component::sigh(Genode::Signal_context_capability cap) +void Irq_session_component::sigh(Signal_context_capability cap) { _irq_object.sigh(cap); } diff --git a/repos/base-okl4/src/core/pager.cc b/repos/base-okl4/src/core/pager.cc index 17abffe3dd..f2549d8b68 100644 --- a/repos/base-okl4/src/core/pager.cc +++ b/repos/base-okl4/src/core/pager.cc @@ -11,9 +11,6 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* Genode includes */ -#include - /* core includes */ #include #include @@ -29,7 +26,7 @@ static const bool verbose_page_fault = false; static const bool verbose_exception = false; -using namespace Genode; +using namespace Core; using namespace Okl4; /** diff --git a/repos/base-okl4/src/core/pager_object.cc b/repos/base-okl4/src/core/pager_object.cc index 661c052e9d..9d7a15c503 100644 --- a/repos/base-okl4/src/core/pager_object.cc +++ b/repos/base-okl4/src/core/pager_object.cc @@ -18,7 +18,7 @@ #include #include -using namespace Genode; +using namespace Core; void Pager_object::wake_up() @@ -44,5 +44,5 @@ void Pager_object::wake_up() void Pager_object::unresolved_page_fault_occurred() { - state.unresolved_page_fault = true; + state.state = Thread_state::State::PAGE_FAULT; } diff --git a/repos/base-okl4/src/core/platform.cc b/repos/base-okl4/src/core/platform.cc index 170737f499..9f9dca1e91 100644 --- a/repos/base-okl4/src/core/platform.cc +++ b/repos/base-okl4/src/core/platform.cc @@ -12,7 +12,6 @@ */ /* Genode includes */ -#include #include #include #include @@ -33,7 +32,7 @@ #include #include -using namespace Genode; +using namespace Core; /**************************************** @@ -52,9 +51,9 @@ bool Mapped_mem_allocator::_unmap_local(addr_t virt_addr, addr_t, size_t size) { ** Boot-info parser ** **********************/ -int Platform::bi_init_mem(Okl4::uintptr_t virt_base, Okl4::uintptr_t virt_end, - Okl4::uintptr_t phys_base, Okl4::uintptr_t phys_end, - const Okl4::bi_user_data_t *data) +int Core::Platform::bi_init_mem(Okl4::uintptr_t virt_base, Okl4::uintptr_t virt_end, + Okl4::uintptr_t phys_base, Okl4::uintptr_t phys_end, + const Okl4::bi_user_data_t *data) { Platform &p = *(Platform *)data->user_data; p._core_mem_alloc.phys_alloc().add_range(phys_base, phys_end - phys_base + 1); @@ -63,8 +62,8 @@ int Platform::bi_init_mem(Okl4::uintptr_t virt_base, Okl4::uintptr_t virt_end, } -int Platform::bi_add_virt_mem(Okl4::bi_name_t, Okl4::uintptr_t base, - Okl4::uintptr_t end, const Okl4::bi_user_data_t *data) +int Core::Platform::bi_add_virt_mem(Okl4::bi_name_t, Okl4::uintptr_t base, + Okl4::uintptr_t end, const Okl4::bi_user_data_t *data) { /* prevent first page from being added to core memory */ if (base < get_page_size() || end < get_page_size()) @@ -76,8 +75,8 @@ int Platform::bi_add_virt_mem(Okl4::bi_name_t, Okl4::uintptr_t base, } -int Platform::bi_add_phys_mem(Okl4::bi_name_t pool, Okl4::uintptr_t base, - Okl4::uintptr_t end, const Okl4::bi_user_data_t *data) +int Core::Platform::bi_add_phys_mem(Okl4::bi_name_t pool, Okl4::uintptr_t base, + Okl4::uintptr_t end, const Okl4::bi_user_data_t *data) { if (pool == 2) { Platform &p = *(Platform *)data->user_data; @@ -91,7 +90,7 @@ static char init_slab_block_rom[get_page_size()]; static char init_slab_block_thread[get_page_size()]; -Platform::Platform() +Core::Platform::Platform() : _io_mem_alloc(&core_mem_alloc()), _io_port_alloc(&core_mem_alloc()), _irq_alloc(&core_mem_alloc()), @@ -143,9 +142,9 @@ Platform::Platform() * type. */ static Okl4::bi_callbacks_t callbacks; - callbacks.init_mem = Platform::bi_init_mem; - callbacks.add_virt_mem = Platform::bi_add_virt_mem; - callbacks.add_phys_mem = Platform::bi_add_phys_mem; + callbacks.init_mem = bi_init_mem; + callbacks.add_virt_mem = bi_add_virt_mem; + callbacks.add_phys_mem = bi_add_phys_mem; Okl4::bootinfo_parse((void *)boot_info_addr, &callbacks, this); @@ -179,12 +178,10 @@ Platform::Platform() * not destroy this task, it should be no problem. */ Platform_thread &core_thread = - *new (&_thread_slab) Platform_thread("core.main"); + *new (&_thread_slab) Platform_thread(*_core_pd, "core.main"); core_thread.set_l4_thread_id(Okl4::L4_rootserver); - _core_pd->bind_thread(core_thread); - /* core log as ROM module */ { unsigned const pages = 1; @@ -203,8 +200,8 @@ Platform::Platform() map_local(phys_addr, (addr_t)ptr, pages); memset(ptr, 0, log_size); - _rom_fs.insert(new (core_mem_alloc()) - Rom_module(phys_addr, log_size, "core_log")); + new (core_mem_alloc()) + Rom_module(_rom_fs, "core_log", phys_addr, log_size); init_core_log(Core_log_range { (addr_t)ptr, log_size } ); }, @@ -215,7 +212,7 @@ Platform::Platform() ); } - /* export platform specific infos */ + /* export platform-specific infos */ { unsigned const pages = 1; size_t const size = pages << get_page_size_log2(); @@ -234,12 +231,12 @@ Platform::Platform() if (map_local(phys_addr, core_local_addr, pages)) { Xml_generator xml(reinterpret_cast(core_local_addr), - size, "platform_info", [&] () { - xml.node("kernel", [&] () { xml.attribute("name", "okl4"); }); + size, "platform_info", [&] { + xml.node("kernel", [&] { xml.attribute("name", "okl4"); }); }); - _rom_fs.insert(new (core_mem_alloc()) Rom_module(phys_addr, size, - "platform_info")); + new (core_mem_alloc()) + Rom_module(_rom_fs, "platform_info", phys_addr, size); } }, [&] (Range_allocator::Alloc_error) { } @@ -255,7 +252,7 @@ Platform::Platform() ** Generic platform interface ** ********************************/ -void Platform::wait_for_exit() +void Core::Platform::wait_for_exit() { /* * On OKL4, core never exits. So let us sleep forever. diff --git a/repos/base-okl4/src/core/platform_pd.cc b/repos/base-okl4/src/core/platform_pd.cc index e7b6af7260..97072de94f 100644 --- a/repos/base-okl4/src/core/platform_pd.cc +++ b/repos/base-okl4/src/core/platform_pd.cc @@ -11,9 +11,6 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* Genode includes */ -#include - /* core includes */ #include #include @@ -23,13 +20,9 @@ /* base-internal includes */ #include -using namespace Genode; +using namespace Core; -/**************************** - ** Private object members ** - ****************************/ - void Platform_pd::_create_pd(bool syscall) { using namespace Okl4; @@ -186,7 +179,7 @@ bool Platform_pd::bind_thread(Platform_thread &thread) l4_thread_id = make_l4_id(_pd_id, thread_id); /* finally inform thread about binding */ - thread.bind(thread_id, l4_thread_id, *this); + thread.bind(thread_id, l4_thread_id); return true; } @@ -207,7 +200,7 @@ void Platform_pd::space_pager(Platform_thread &thread) using namespace Okl4; L4_Word_t control = L4_SpaceCtrl_space_pager; - L4_SpaceId_t pager_space = L4_SpaceId(thread.pd()->pd_id()); + L4_SpaceId_t pager_space = L4_SpaceId(thread.pd().pd_id()); L4_ClistId_t cap_list = L4_rootclist; L4_Word_t utcb_area_size = L4_GetUtcbSize()*(1 << Thread_id_bits::THREAD); L4_Word_t utcb_location = platform_specific().utcb_base() diff --git a/repos/base-okl4/src/core/platform_thread.cc b/repos/base-okl4/src/core/platform_thread.cc index 90e69e0aff..c95ac8b6df 100644 --- a/repos/base-okl4/src/core/platform_thread.cc +++ b/repos/base-okl4/src/core/platform_thread.cc @@ -14,8 +14,6 @@ */ /* Genode includes */ -#include -#include #include /* core includes */ @@ -27,21 +25,20 @@ #include #include -using namespace Genode; +using namespace Core; using namespace Okl4; -int Platform_thread::start(void *ip, void *sp, unsigned) +void Platform_thread::start(void *ip, void *sp) { - if (!_platform_pd) { + if (!_bound_to_pd) { warning("thread ", _thread_id, " is not bound to a PD"); - return -1; + return; } /* activate local thread by assigning a UTCB address and thread ID */ - int space_no = _platform_pd->pd_id(); - L4_ThreadId_t new_thread_id = _platform_pd->make_l4_id(space_no, - _thread_id); + int space_no = _pd.pd_id(); + L4_ThreadId_t new_thread_id = _pd.make_l4_id(space_no, _thread_id); L4_SpaceId_t space_id = L4_SpaceId(space_no); L4_ThreadId_t scheduler = L4_rootserver; @@ -53,7 +50,7 @@ int Platform_thread::start(void *ip, void *sp, unsigned) L4_Word_t resources = 0; L4_Word_t utcb_size_per_task = L4_GetUtcbSize()*(1 << Thread_id_bits::THREAD); L4_Word_t utcb_location = platform_specific().utcb_base() - + _platform_pd->pd_id()*utcb_size_per_task + + _pd.pd_id()*utcb_size_per_task + _thread_id*L4_GetUtcbSize(); /* * On some ARM architectures, UTCBs are allocated by the kernel. @@ -70,8 +67,8 @@ int Platform_thread::start(void *ip, void *sp, unsigned) * * Note: This is used by OKLinux only */ - if(_platform_pd && _platform_pd->space_pager()) { - pager = _platform_pd->space_pager()->_l4_thread_id; + if(_pd.space_pager()) { + pager = _pd.space_pager()->_l4_thread_id; exception_handler = pager; } @@ -81,7 +78,7 @@ int Platform_thread::start(void *ip, void *sp, unsigned) resources, (void *)utcb_location); if (ret != 1) { error("L4_ThreadControl returned ", ret, ", error=", ret, L4_ErrorCode()); - return -1; + return; } /* make the symbolic thread name known to the kernel debugger */ @@ -104,7 +101,6 @@ int Platform_thread::start(void *ip, void *sp, unsigned) warning("could not set thread prioritry to default"); set_l4_thread_id(new_thread_id); - return 0; } @@ -120,12 +116,10 @@ void Platform_thread::resume() } -void Platform_thread::bind(int thread_id, L4_ThreadId_t l4_thread_id, - Platform_pd &pd) +void Platform_thread::bind(int thread_id, L4_ThreadId_t l4_thread_id) { _thread_id = thread_id; _l4_thread_id = l4_thread_id; - _platform_pd = &pd; } @@ -136,10 +130,6 @@ void Platform_thread::unbind() if (res != 1) error("deleting thread ", Hex(_l4_thread_id.raw), " failed"); - - _thread_id = THREAD_INVALID; - _l4_thread_id = L4_nilthread; - _platform_pd = nullptr; } @@ -149,13 +139,14 @@ unsigned long Platform_thread::pager_object_badge() const } -Platform_thread::Platform_thread(size_t, const char *name, unsigned prio, - Affinity::Location, addr_t) +Platform_thread::Platform_thread(Platform_pd &pd, size_t, const char *name, + unsigned prio, Affinity::Location, addr_t) : - _l4_thread_id(L4_nilthread), _platform_pd(0), - _priority(prio), _pager(0) + _l4_thread_id(L4_nilthread), _pd(pd), _priority(prio), _pager(0) { copy_cstring(_name, name, sizeof(_name)); + + _bound_to_pd = pd.bind_thread(*this); } @@ -165,6 +156,6 @@ Platform_thread::~Platform_thread() * We inform our protection domain about thread destruction, which will end up in * Thread::unbind() */ - if (_platform_pd) - _platform_pd->unbind_thread(*this); + if (_bound_to_pd) + _pd.unbind_thread(*this); } diff --git a/repos/base-okl4/src/core/ram_dataspace_support.cc b/repos/base-okl4/src/core/ram_dataspace_support.cc index afb346b0c7..37d8df0675 100644 --- a/repos/base-okl4/src/core/ram_dataspace_support.cc +++ b/repos/base-okl4/src/core/ram_dataspace_support.cc @@ -25,7 +25,7 @@ /* base-internal includes */ #include -using namespace Genode; +using namespace Core; void Ram_dataspace_factory::_export_ram_ds(Dataspace_component &) { } diff --git a/repos/base-okl4/src/core/spec/x86/platform_thread_x86.cc b/repos/base-okl4/src/core/spec/x86/platform_thread_x86.cc index 5ab3ffb730..6621cd4dd6 100644 --- a/repos/base-okl4/src/core/spec/x86/platform_thread_x86.cc +++ b/repos/base-okl4/src/core/spec/x86/platform_thread_x86.cc @@ -17,13 +17,13 @@ /* base-internal includes */ #include -using namespace Genode; +using namespace Core; using namespace Okl4; Thread_state Platform_thread::state() { - Thread_state s; + Thread_state s { }; L4_Copy_regs_to_mrs(_l4_thread_id); @@ -40,23 +40,19 @@ Thread_state Platform_thread::state() MR_EAX = 9, }; - L4_StoreMR(MR_EIP, &s.ip); - L4_StoreMR(MR_EFLAGS, &s.eflags); - L4_StoreMR(MR_EDI, &s.edi); - L4_StoreMR(MR_ESI, &s.esi); - L4_StoreMR(MR_EBP, &s.ebp); - L4_StoreMR(MR_ESP, &s.sp); - L4_StoreMR(MR_EBX, &s.ebx); - L4_StoreMR(MR_EDX, &s.edx); - L4_StoreMR(MR_ECX, &s.ecx); - L4_StoreMR(MR_EAX, &s.eax); + L4_StoreMR(MR_EIP, &s.cpu.ip); + L4_StoreMR(MR_EFLAGS, &s.cpu.eflags); + L4_StoreMR(MR_EDI, &s.cpu.edi); + L4_StoreMR(MR_ESI, &s.cpu.esi); + L4_StoreMR(MR_EBP, &s.cpu.ebp); + L4_StoreMR(MR_ESP, &s.cpu.sp); + L4_StoreMR(MR_EBX, &s.cpu.ebx); + L4_StoreMR(MR_EDX, &s.cpu.edx); + L4_StoreMR(MR_ECX, &s.cpu.ecx); + L4_StoreMR(MR_EAX, &s.cpu.eax); return s; } -void Platform_thread::state(Thread_state) -{ - warning("Platform_thread::state not implemented"); - throw Cpu_thread::State_access_failed(); -} +void Platform_thread::state(Thread_state) { } diff --git a/repos/base-okl4/src/core/thread_start.cc b/repos/base-okl4/src/core/thread_start.cc index f3e03d1e5f..c37fc08f3b 100644 --- a/repos/base-okl4/src/core/thread_start.cc +++ b/repos/base-okl4/src/core/thread_start.cc @@ -34,20 +34,20 @@ void Thread::_thread_start() } -void Thread::start() +Thread::Start_result Thread::start() { /* create and start platform thread */ - native_thread().pt = new (platform_specific().thread_slab()) - Platform_thread(_stack->name().string()); - - platform_specific().core_pd().bind_thread(*native_thread().pt); + native_thread().pt = new (Core::platform_specific().thread_slab()) + Core::Platform_thread(Core::platform_specific().core_pd(), _stack->name().string()); native_thread().pt->start((void *)_thread_start, stack_top()); + + return Start_result::OK; } void Thread::_deinit_platform_thread() { /* destruct platform thread */ - destroy(platform_specific().thread_slab(), native_thread().pt); + destroy(Core::platform_specific().thread_slab(), native_thread().pt); } diff --git a/repos/base-okl4/src/include/base/internal/native_thread.h b/repos/base-okl4/src/include/base/internal/native_thread.h index d05a9c421c..bd9c0668f0 100644 --- a/repos/base-okl4/src/include/base/internal/native_thread.h +++ b/repos/base-okl4/src/include/base/internal/native_thread.h @@ -20,11 +20,10 @@ /* base-internal includes */ #include -namespace Genode { +namespace Core { class Platform_thread; } - struct Native_thread; - class Platform_thread; -} + +namespace Genode { struct Native_thread; } struct Genode::Native_thread @@ -38,7 +37,7 @@ struct Genode::Native_thread * the physical thread object, which is going to be destroyed * on destruction of the 'Thread'. */ - Platform_thread *pt; + Core::Platform_thread *pt; }; #endif /* _INCLUDE__BASE__INTERNAL__NATIVE_THREAD_H_ */ diff --git a/repos/base-okl4/src/include/base/internal/rpc_destination.h b/repos/base-okl4/src/include/base/internal/rpc_destination.h index 0aeb69e125..69947de0fe 100644 --- a/repos/base-okl4/src/include/base/internal/rpc_destination.h +++ b/repos/base-okl4/src/include/base/internal/rpc_destination.h @@ -19,7 +19,7 @@ namespace Genode { - typedef Okl4::L4_ThreadId_t Rpc_destination; + using Rpc_destination = Okl4::L4_ThreadId_t; static inline Rpc_destination invalid_rpc_destination() { diff --git a/repos/base-okl4/src/lib/base/ipc.cc b/repos/base-okl4/src/lib/base/ipc.cc index f2f6b0ef08..7402df1e6d 100644 --- a/repos/base-okl4/src/lib/base/ipc.cc +++ b/repos/base-okl4/src/lib/base/ipc.cc @@ -14,7 +14,7 @@ /* Genode includes */ #include #include -#include +#include /* base-internal includes */ #include @@ -162,15 +162,9 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst, L4_MsgTag_t rcv_tag = L4_Call(dst_data.dst); - enum { ERROR_MASK = 0xe, ERROR_CANCELED = 3 << 1 }; - if (L4_IpcFailed(rcv_tag) && - ((L4_ErrorCode() & ERROR_MASK) == ERROR_CANCELED)) - throw Genode::Blocking_canceled(); - if (L4_IpcFailed(rcv_tag)) { raw("Ipc failed"); - - return Rpc_exception_code(Rpc_exception_code::INVALID_OBJECT); + sleep_forever(); } return Rpc_exception_code(extract_msg_from_utcb(rcv_tag, rcv_msg)); diff --git a/repos/base-okl4/src/lib/base/thread_bootstrap.cc b/repos/base-okl4/src/lib/base/thread_bootstrap.cc index 7ecbc7f57d..aa01bd65b1 100644 --- a/repos/base-okl4/src/lib/base/thread_bootstrap.cc +++ b/repos/base-okl4/src/lib/base/thread_bootstrap.cc @@ -22,9 +22,19 @@ #include #include +using namespace Genode; + + Okl4::L4_ThreadId_t main_thread_tid; +static Thread_capability main_thread_cap(Thread_capability main_cap = { }) +{ + static Thread_capability cap = main_cap; + return cap; +} + + /******************* ** local helpers ** *******************/ @@ -53,7 +63,7 @@ using namespace Genode; ** Startup library support ** *****************************/ -void prepare_init_main_thread() +void Genode::prepare_init_main_thread() { /* copy thread ID to utcb */ main_thread_tid.raw = Okl4::copy_uregister_to_utcb(); @@ -83,3 +93,9 @@ void Thread::_init_platform_thread(size_t, Type type) native_thread().l4id.raw = main_thread_tid.raw; _thread_cap = main_thread_cap(); } + + +void Genode::init_thread_bootstrap(Cpu_session &, Thread_capability main_cap) +{ + main_thread_cap(main_cap); +} diff --git a/repos/base-okl4/tool/README b/repos/base-okl4/tool/README deleted file mode 100644 index 2287bccb39..0000000000 --- a/repos/base-okl4/tool/README +++ /dev/null @@ -1,3 +0,0 @@ -This directory contains the following utilities for working with Genode -on OKL4. - diff --git a/repos/base-okl4/tool/weaver_x86.xml b/repos/base-okl4/tool/weaver_x86.xml index 6d848b4926..79a36aa0a4 100644 --- a/repos/base-okl4/tool/weaver_x86.xml +++ b/repos/base-okl4/tool/weaver_x86.xml @@ -66,11 +66,11 @@ - - + + - + diff --git a/repos/base-pistachio/README b/repos/base-pistachio/README index 8d8d81f71a..92ca674872 100644 --- a/repos/base-pistachio/README +++ b/repos/base-pistachio/README @@ -1,3 +1 @@ -This repository contains the L4ka::Pistachio-specific implementation of Genode. -Please see the documentation at 'base-pistachio/doc/pistachio.txt' for further -instructions on building and using Genode on the L4ka::Pistachio kernel. +This repository contains the L4ka::Pistachio-specific parts of Genode. diff --git a/repos/base-pistachio/lib/mk/base-pistachio.mk b/repos/base-pistachio/lib/mk/base-pistachio.mk index d77f60bb26..a4a558c3dd 100644 --- a/repos/base-pistachio/lib/mk/base-pistachio.mk +++ b/repos/base-pistachio/lib/mk/base-pistachio.mk @@ -4,7 +4,7 @@ LIBS += base-pistachio-common syscall-pistachio cxx timeout SRC_CC += thread_start.cc SRC_CC += cache.cc +SRC_CC += capability_slab.cc SRC_CC += capability_space.cc SRC_CC += signal_transmitter.cc SRC_CC += signal.cc -SRC_CC += platform.cc diff --git a/repos/base-pistachio/lib/mk/syscall-pistachio.mk b/repos/base-pistachio/lib/mk/syscall-pistachio.mk index 044e47807d..a9b8b08edf 100644 --- a/repos/base-pistachio/lib/mk/syscall-pistachio.mk +++ b/repos/base-pistachio/lib/mk/syscall-pistachio.mk @@ -15,7 +15,7 @@ unexport .SHELLFLAGS user_build.tag: LIBGCCFLAGS="$(CC_MARCH)" \ LDFLAGS="$(addprefix $(LD_PREFIX),$(LD_MARCH)) -nostdlib" \ - CFLAGS="$(CC_MARCH) $(CC_WARN)" \ + CFLAGS="$(CC_MARCH) $(CC_WARN) -fno-tree-loop-distribute-patterns" \ $(PISTACHIO_CONTRIB_DIR)/user/configure --build=ia32 --host i686 \ CC=$(CROSS_DEV_PREFIX)gcc $(VERBOSE_MK) MAKEFLAGS= $(MAKE) -s $(VERBOSE_DIR) diff --git a/repos/base-pistachio/patches/gcc12.patch b/repos/base-pistachio/patches/gcc12.patch new file mode 100644 index 0000000000..60a081b2ab --- /dev/null +++ b/repos/base-pistachio/patches/gcc12.patch @@ -0,0 +1,22 @@ +gcc12.patch + +diff --git a/kernel/src/api/v4/tcb.h b/kernel/src/api/v4/tcb.h +index 21b10df..779aad5 100644 +--- a/kernel/src/api/v4/tcb.h ++++ b/kernel/src/api/v4/tcb.h +@@ -763,13 +763,13 @@ INLINE arch_ktcb_t *tcb_t::get_arch() + + INLINE tcb_t * get_idle_tcb() + { +- extern tcb_t *__idle_tcb; ++ extern const tcb_t *__idle_tcb; + return (tcb_t*)__idle_tcb; + } + + INLINE tcb_t * get_dummy_tcb() + { +- extern tcb_t *__dummy_tcb; ++ extern const tcb_t *__dummy_tcb; + return (tcb_t*)__dummy_tcb; + } + diff --git a/repos/base-pistachio/ports/pistachio.hash b/repos/base-pistachio/ports/pistachio.hash index f883156156..2e07c71e7e 100644 --- a/repos/base-pistachio/ports/pistachio.hash +++ b/repos/base-pistachio/ports/pistachio.hash @@ -1 +1 @@ -2961c41705536e84699829f8c1d3825c24c063d3 +10ce61c40c6a740070eee64320bce5df390180fa diff --git a/repos/base-pistachio/recipes/src/base-pistachio/content.mk b/repos/base-pistachio/recipes/src/base-pistachio/content.mk index c33056fc45..e666d4b917 100644 --- a/repos/base-pistachio/recipes/src/base-pistachio/content.mk +++ b/repos/base-pistachio/recipes/src/base-pistachio/content.mk @@ -21,5 +21,5 @@ content: for spec in x86_32; do \ mv lib/mk/spec/$$spec/ld-pistachio.mk lib/mk/spec/$$spec/ld.mk; \ done; - sed -i "s/pit_timer_drv/timer/" src/timer/pit/target.inc + sed -i "s/pit_timer/timer/" src/timer/pit/target.inc diff --git a/repos/base-pistachio/recipes/src/base-pistachio/hash b/repos/base-pistachio/recipes/src/base-pistachio/hash index 6177cd0ad9..993b9b9441 100644 --- a/repos/base-pistachio/recipes/src/base-pistachio/hash +++ b/repos/base-pistachio/recipes/src/base-pistachio/hash @@ -1 +1 @@ -2022-10-11 b522663f9c8c779f255e2a5eb37f98b4301c5446 +2024-08-28 ef60eabef7b6a62cb0ca9844e76dcaa0d5fd9032 diff --git a/repos/base-pistachio/src/core/core_log_out.cc b/repos/base-pistachio/src/core/core_log_out.cc index 80a66f810f..9971c13594 100644 --- a/repos/base-pistachio/src/core/core_log_out.cc +++ b/repos/base-pistachio/src/core/core_log_out.cc @@ -18,7 +18,7 @@ #include -void Genode::Core_log::out(char const c) +void Core::Core_log::out(char const c) { Pistachio::L4_KDB_PrintChar(c); } diff --git a/repos/base-pistachio/src/core/include/ipc_pager.h b/repos/base-pistachio/src/core/include/ipc_pager.h index 9d3589ffd8..5c46ba5f43 100644 --- a/repos/base-pistachio/src/core/include/ipc_pager.h +++ b/repos/base-pistachio/src/core/include/ipc_pager.h @@ -17,20 +17,20 @@ /* Genode includes */ #include #include -#include #include -/* core-local includes */ +/* core includes */ +#include #include #include /* base-internal includes */ #include -namespace Genode { class Ipc_pager; } +namespace Core { class Ipc_pager; } -class Genode::Ipc_pager +class Core::Ipc_pager { private: diff --git a/repos/base-pistachio/src/core/include/map_local.h b/repos/base-pistachio/src/core/include/map_local.h index 96a6114385..dd642677cb 100644 --- a/repos/base-pistachio/src/core/include/map_local.h +++ b/repos/base-pistachio/src/core/include/map_local.h @@ -21,7 +21,7 @@ /* base-internal includes */ #include -namespace Genode { +namespace Core { /** * Map page locally within core diff --git a/repos/base-pistachio/src/core/include/platform.h b/repos/base-pistachio/src/core/include/platform.h index 240038fb2c..8febf8ccee 100644 --- a/repos/base-pistachio/src/core/include/platform.h +++ b/repos/base-pistachio/src/core/include/platform.h @@ -27,17 +27,17 @@ #include #include -namespace Genode { class Platform; } +namespace Core { class Platform; } -class Genode::Platform : public Platform_generic +class Core::Platform : public Platform_generic { private: /* * Shortcut for the type of allocator instances for physical resources */ - typedef Synced_range_allocator Phys_allocator; + using Phys_allocator = Synced_range_allocator; Phys_allocator _ram_alloc; /* RAM allocator */ Phys_allocator _io_mem_alloc; /* MMIO allocator */ @@ -101,7 +101,8 @@ class Genode::Platform : public Platform_generic */ Sigma0(); - int pager(Ipc_pager &) override { /* never called */ return -1; } + /* never called */ + Pager_result pager(Ipc_pager &) override { return Pager_result::STOP; } }; /** @@ -119,7 +120,8 @@ class Genode::Platform : public Platform_generic */ Core_pager(Platform_pd &core_pd); - int pager(Ipc_pager &) override { /* never called */ return -1; } + /* never called */ + Pager_result pager(Ipc_pager &) override { return Pager_result::STOP; } }; /** diff --git a/repos/base-pistachio/src/core/include/platform_pd.h b/repos/base-pistachio/src/core/include/platform_pd.h index 631cea8d79..2f71087418 100644 --- a/repos/base-pistachio/src/core/include/platform_pd.h +++ b/repos/base-pistachio/src/core/include/platform_pd.h @@ -21,18 +21,24 @@ #include /* core includes */ -#include #include -namespace Genode { +namespace Core { class Platform_thread; class Platform_pd; } -class Genode::Platform_pd : public Address_space +class Core::Platform_pd : public Address_space { + public: + + struct Thread_id { unsigned value; }; + + enum class Alloc_thread_id_error { EXHAUSTED }; + using Alloc_thread_id_result = Attempt; + private: /* @@ -67,9 +73,9 @@ class Genode::Platform_pd : public Address_space /** * Manually construct L4 thread ID from its components */ - Pistachio::L4_ThreadId_t make_l4_id(unsigned pd_no, - unsigned thread_no, - unsigned version) + static Pistachio::L4_ThreadId_t make_l4_id(unsigned pd_no, + unsigned thread_no, + unsigned version) { /* * We have to make sure that the 6 lower version bits are @@ -87,31 +93,7 @@ class Genode::Platform_pd : public Address_space ** Threads of this protection domain object ** **********************************************/ - Platform_thread *_threads[THREAD_MAX]; - - /** - * Initialize thread allocator - */ - void _init_threads(); - - /** - * Thread iteration for one PD - */ - Platform_thread *_next_thread(); - - /** - * Thread allocation - * - * Again a special case for Core thread0. - */ - int _alloc_thread(int thread_id, Platform_thread &thread); - - /** - * Thread deallocation - * - * No special case for Core thread0 here - we just never call it. - */ - void _free_thread(int thread_id); + Platform_thread *_threads[THREAD_MAX] { }; /****************** @@ -210,25 +192,29 @@ class Genode::Platform_pd : public Address_space */ void upgrade_ram_quota(size_t) { } + /** + * Allocate PD-local ID for a new 'Platform_thread' + */ + Alloc_thread_id_result alloc_thread_id(Platform_thread &); + + /** + * Release PD-local thread ID at destruction of 'Platform_thread' + */ + void free_thread_id(Thread_id); + + /** + * Return L4 thread ID from the PD's task ID and the PD-local thread ID + */ + Pistachio::L4_ThreadId_t l4_thread_id(Thread_id const id) const + { + return make_l4_id(_pd_id, id.value, _version); + } + static Pistachio::L4_Word_t _core_utcb_ptr; static void touch_utcb_space(); - /** - * Bind thread to protection domain - * - * This function allocates the physical L4 thread ID. - */ - bool bind_thread(Platform_thread &thread); - int bind_initial_thread(Platform_thread &thread); - /** - * Unbind thread from protection domain - * - * Free the thread's slot and update thread object. - */ - void unbind_thread(Platform_thread &thread); - /** * Assign parent interface to protection domain */ diff --git a/repos/base-pistachio/src/core/include/platform_thread.h b/repos/base-pistachio/src/core/include/platform_thread.h index e201b8d941..98f241d177 100644 --- a/repos/base-pistachio/src/core/include/platform_thread.h +++ b/repos/base-pistachio/src/core/include/platform_thread.h @@ -27,7 +27,7 @@ /* base-internal includes */ #include -namespace Genode { +namespace Core { class Platform_pd; class Platform_thread; @@ -44,11 +44,11 @@ inline unsigned long convert_native_thread_id_to_badge(Pistachio::L4_ThreadId_t } -class Genode::Platform_thread : Interface +class Core::Platform_thread : Interface { private: - typedef Pistachio::L4_ThreadId_t L4_ThreadId_t; + using L4_ThreadId_t = Pistachio::L4_ThreadId_t; /* * Noncopyable @@ -56,88 +56,92 @@ class Genode::Platform_thread : Interface Platform_thread(Platform_thread const &); Platform_thread &operator = (Platform_thread const &); - typedef String<32> Name; + using Name = String<32>; - int _thread_id = THREAD_INVALID; - L4_ThreadId_t _l4_thread_id = L4_nilthread; Name const _name; /* thread name at kernel debugger */ - Platform_pd *_platform_pd = nullptr; - unsigned _priority = 0; + Platform_pd &_pd; + unsigned const _priority = 0; Pager_object *_pager = nullptr; - Affinity::Location _location; + Affinity::Location _location { }; + + using Id = Platform_pd::Alloc_thread_id_result; + + Id const _id { _pd.alloc_thread_id(*this) }; + + Pistachio::L4_ThreadId_t _l4_id_from_pd_thread_id() const + { + using namespace Pistachio; + return _id.convert( + [&] (Platform_pd::Thread_id id) { return _pd.l4_thread_id(id); }, + [&] (Platform_pd::Alloc_thread_id_error) { return L4_nilthread; } + ); + } + + Pistachio::L4_ThreadId_t const _l4_id = _l4_id_from_pd_thread_id(); public: - enum { THREAD_INVALID = -1 }; enum { DEFAULT_PRIORITY = 128 }; /** * Constructor */ - Platform_thread(size_t, char const *name, unsigned priority, + Platform_thread(Platform_pd &pd, size_t, char const *name, unsigned priority, Affinity::Location location, addr_t) : - _name(name), _priority(priority), _location(location) + _name(name), _pd(pd), _priority(priority), _location(location) + { } + + /** + * Constructor used for initial roottask thread "core.main" + */ + Platform_thread(Platform_pd &pd, Pistachio::L4_ThreadId_t l4_id) + : + _name("core.main"), _pd(pd), _l4_id(l4_id) { } /** * Constructor used for core-internal threads */ - Platform_thread(char const *name) - : _name(name), _location(Affinity::Location()) { } + Platform_thread(Platform_pd &pd, char const *name) : _name(name), _pd(pd) { } /** * Destructor */ ~Platform_thread(); + /** + * Return true if thread creation suceeded + */ + bool valid() const { return _id.ok(); } + /** * Start thread * * \param ip instruction pointer to start at * \param sp stack pointer to use - * - * \retval 0 successful - * \retval -1 thread could not be started */ - int start(void *ip, void *sp); + void start(void *ip, void *sp); /** * Pause this thread */ - void pause(); + void pause() { /* not implemented */ } /** * Enable/disable single stepping */ - void single_step(bool) { } + void single_step(bool) { /* not implemented */ } /** * Resume this thread */ - void resume(); - - /** - * This thread is about to be bound - * - * \param thread_id local thread ID - * \param l4_thread_id final L4 thread ID - * \param pd platform pd, thread is bound to - */ - void bind(int thread_id, Pistachio::L4_ThreadId_t l4_thread_id, - Platform_pd &pd); - - /** - * Unbind this thread - */ - void unbind(); + void resume() { /* not implemented */ } /** * Override thread state with 's' - * - * \throw Cpu_session::State_access_failed */ - void state(Thread_state s); + void state(Thread_state) { /* not implemented */ } /** * Read thread state @@ -167,7 +171,7 @@ class Genode::Platform_thread : Interface */ unsigned long pager_object_badge() const { - return convert_native_thread_id_to_badge(_l4_thread_id); + return convert_native_thread_id_to_badge(native_thread_id()); } /** @@ -195,12 +199,9 @@ class Genode::Platform_thread : Interface ** Pistachio-specific Accessors ** **********************************/ - int thread_id() const { return _thread_id; } - Pistachio::L4_ThreadId_t native_thread_id() const { return _l4_thread_id; } - Name name() const { return _name; } + Pistachio::L4_ThreadId_t native_thread_id() const { return _l4_id; } - /* use only for core... */ - void set_l4_thread_id(Pistachio::L4_ThreadId_t id) { _l4_thread_id = id; } + Name name() const { return _name; } }; #endif /* _CORE__INCLUDE__PLATFORM_THREAD_H_ */ diff --git a/repos/base-pistachio/src/core/include/print_l4_thread_id.h b/repos/base-pistachio/src/core/include/print_l4_thread_id.h index eafd22b6aa..76a58de439 100644 --- a/repos/base-pistachio/src/core/include/print_l4_thread_id.h +++ b/repos/base-pistachio/src/core/include/print_l4_thread_id.h @@ -14,15 +14,16 @@ #ifndef _CORE__INCLUDE__PRINT_L4_THREAD_ID_H_ #define _CORE__INCLUDE__PRINT_L4_THREAD_ID_H_ -#include +/* core includes */ +#include /* base-internal includes */ #include -namespace Genode { struct Formatted_tid; } +namespace Core { struct Formatted_tid; } -struct Genode::Formatted_tid +struct Core::Formatted_tid { Pistachio::L4_ThreadId_t tid; diff --git a/repos/base-pistachio/src/core/include/rpc_cap_factory.h b/repos/base-pistachio/src/core/include/rpc_cap_factory.h index 8514599aaf..d42c364a6d 100644 --- a/repos/base-pistachio/src/core/include/rpc_cap_factory.h +++ b/repos/base-pistachio/src/core/include/rpc_cap_factory.h @@ -14,13 +14,17 @@ #ifndef _CORE__INCLUDE__RPC_CAP_FACTORY_H_ #define _CORE__INCLUDE__RPC_CAP_FACTORY_H_ +/* Genode includes */ #include #include -namespace Genode { class Rpc_cap_factory; } +/* core includes */ +#include + +namespace Core { class Rpc_cap_factory; } -class Genode::Rpc_cap_factory +class Core::Rpc_cap_factory { private: diff --git a/repos/base-pistachio/src/core/include/util.h b/repos/base-pistachio/src/core/include/util.h index 7add6722a9..36ba5fe68d 100644 --- a/repos/base-pistachio/src/core/include/util.h +++ b/repos/base-pistachio/src/core/include/util.h @@ -15,8 +15,6 @@ #define _CORE__INCLUDE__UTIL_H_ /* Genode includes */ -#include -#include #include #include @@ -24,11 +22,14 @@ #include #include -/* core-local includes */ +/* core includes */ +#include #include #include -namespace Genode { +namespace Core { + + using Genode::get_page_size; inline void log_event(const char *) { } inline void log_event(const char *, unsigned, unsigned, unsigned) { } @@ -104,8 +105,7 @@ namespace Genode { inline addr_t map_src_addr(addr_t core_local_addr, addr_t) { return core_local_addr; } - inline size_t constrain_map_size_log2(size_t size_log2) { - return size_log2; } + inline Log2 kernel_constrained_map_size(Log2 size) { return size; } } #endif /* _CORE__INCLUDE__UTIL_H_ */ diff --git a/repos/base-pistachio/src/core/io_mem_session_support.cc b/repos/base-pistachio/src/core/io_mem_session_support.cc index b1365d467e..f0763ab1e7 100644 --- a/repos/base-pistachio/src/core/io_mem_session_support.cc +++ b/repos/base-pistachio/src/core/io_mem_session_support.cc @@ -21,7 +21,7 @@ /* base-internal includes */ #include -using namespace Genode; +using namespace Core; /* @@ -46,7 +46,7 @@ static bool is_conventional_memory(addr_t base) } -void Io_mem_session_component::_unmap_local(addr_t, size_t) { } +void Io_mem_session_component::_unmap_local(addr_t, size_t, addr_t) { } static inline bool can_use_super_page(addr_t base, size_t size) @@ -60,16 +60,16 @@ addr_t Io_mem_session_component::_map_local(addr_t base, size_t size) { using namespace Pistachio; - auto alloc_virt_range = [&] () + auto alloc_virt_range = [&] { /* special case for the null page */ if (is_conventional_memory(base)) return base; - /* align large I/O dataspaces on a super-page boundary within core */ + /* align large I/O dataspaces to super page size, otherwise to size */ size_t const align = (size >= get_super_page_size()) - ? get_super_page_size_log2() - : get_page_size_log2(); + ? get_super_page_size_log2() + : log2(size); return platform().region_alloc().alloc_aligned(size, align).convert( [&] (void *ptr) { return (addr_t)ptr; }, diff --git a/repos/base-pistachio/src/core/irq_session_component.cc b/repos/base-pistachio/src/core/irq_session_component.cc index 90292a0d6c..35bd3be1ae 100644 --- a/repos/base-pistachio/src/core/irq_session_component.cc +++ b/repos/base-pistachio/src/core/irq_session_component.cc @@ -12,16 +12,14 @@ */ /* Genode includes */ -#include #include /* core includes */ #include +#include #include -/* base-internal includes */ - -using namespace Genode; +using namespace Core; using namespace Pistachio; @@ -55,10 +53,11 @@ void Irq_object::_wait_for_irq() } -void Irq_object::start() +Thread::Start_result Irq_object::start() { - ::Thread::start(); + Start_result const result = ::Thread::start(); _sync_bootup.block(); + return result; } @@ -129,7 +128,8 @@ Irq_session_component::Irq_session_component(Range_allocator &irq_alloc, _irq_alloc(irq_alloc), _irq_object(_irq_number) { - long msi = Arg_string::find_arg(args, "device_config_phys").long_value(0); + Irq_args irq_args(args); + bool msi { irq_args.type() != Irq_session::TYPE_LEGACY }; if (msi) throw Service_denied(); diff --git a/repos/base-pistachio/src/core/kip.cc b/repos/base-pistachio/src/core/kip.cc index 20712295f9..0d6882be7a 100644 --- a/repos/base-pistachio/src/core/kip.cc +++ b/repos/base-pistachio/src/core/kip.cc @@ -11,7 +11,7 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* core-local includes */ +/* core includes */ #include using namespace Pistachio; diff --git a/repos/base-pistachio/src/core/pager.cc b/repos/base-pistachio/src/core/pager.cc index 7942fbd0f9..636417bd1b 100644 --- a/repos/base-pistachio/src/core/pager.cc +++ b/repos/base-pistachio/src/core/pager.cc @@ -11,10 +11,6 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* Genode includes */ -#include -#include - /* base-internal includes */ #include #include @@ -24,7 +20,7 @@ #include #include -using namespace Genode; +using namespace Core; using namespace Pistachio; diff --git a/repos/base-pistachio/src/core/pager_object.cc b/repos/base-pistachio/src/core/pager_object.cc index 37b4ff1d16..857aea4004 100644 --- a/repos/base-pistachio/src/core/pager_object.cc +++ b/repos/base-pistachio/src/core/pager_object.cc @@ -18,7 +18,7 @@ #include #include -using namespace Genode; +using namespace Core; void Pager_object::wake_up() @@ -44,5 +44,5 @@ void Pager_object::wake_up() void Pager_object::unresolved_page_fault_occurred() { - state.unresolved_page_fault = true; + state.state = Thread_state::State::PAGE_FAULT; } diff --git a/repos/base-pistachio/src/core/platform.cc b/repos/base-pistachio/src/core/platform.cc index 8399f96510..7c7e0c142a 100644 --- a/repos/base-pistachio/src/core/platform.cc +++ b/repos/base-pistachio/src/core/platform.cc @@ -12,7 +12,6 @@ */ /* Genode includes */ -#include #include #include #include @@ -37,7 +36,7 @@ #include #include -using namespace Genode; +using namespace Core; static const bool verbose = true; @@ -196,7 +195,7 @@ static void _core_pager_loop() } -Platform::Sigma0::Sigma0() +Core::Platform::Sigma0::Sigma0() : Pager_object(Cpu_session_capability(), Thread_capability(), 0, Affinity::Location(), @@ -206,23 +205,22 @@ Platform::Sigma0::Sigma0() } -Platform::Sigma0 &Platform::sigma0() +Core::Platform::Sigma0 &Core::Platform::sigma0() { static Sigma0 _sigma0; return _sigma0; } -Platform::Core_pager::Core_pager(Platform_pd &core_pd) +Core::Platform::Core_pager::Core_pager(Platform_pd &core_pd) : - Platform_thread("core.pager"), + Platform_thread(core_pd, "core.pager"), Pager_object(Cpu_session_capability(), Thread_capability(), 0, Affinity::Location(), Session_label(), Cpu_session::Name(name())) { Platform_thread::pager(sigma0()); - core_pd.bind_thread(*this); cap(Capability_space::import(native_thread_id(), Rpc_obj_key())); /* stack begins at the top end of the '_core_pager_stack' array */ @@ -234,7 +232,7 @@ Platform::Core_pager::Core_pager(Platform_pd &core_pd) } -Platform::Core_pager &Platform::core_pager() +Core::Platform::Core_pager &Core::Platform::core_pager() { static Core_pager _core_pager(core_pd()); return _core_pager; @@ -261,7 +259,7 @@ struct Region return (((base + size) > start) && (base < end)); } - void print(Genode::Output &out) const + void print(Output &out) const { size_t const size = end - start; Genode::print(out, Hex_range(start, size), " ", @@ -371,7 +369,7 @@ bool sigma0_req_region(addr_t *addr, unsigned log2size) } -void Platform::_setup_mem_alloc() +void Core::Platform::_setup_mem_alloc() { Pistachio::L4_KernelInterfacePage_t *kip = Pistachio::get_kip(); @@ -453,10 +451,10 @@ void Platform::_setup_mem_alloc() } -void Platform::_setup_irq_alloc() { _irq_alloc.add_range(0, 0x10); } +void Core::Platform::_setup_irq_alloc() { _irq_alloc.add_range(0, 0x10); } -void Platform::_setup_preemption() +void Core::Platform::_setup_preemption() { /* * The roottask has the maximum priority @@ -466,7 +464,7 @@ void Platform::_setup_preemption() } -void Platform::_setup_basics() +void Core::Platform::_setup_basics() { using namespace Pistachio; @@ -486,9 +484,6 @@ void Platform::_setup_basics() dump_kip_memdesc(kip); - /* add KIP as ROM module */ - _rom_fs.insert(&_kip_rom); - L4_Fpage_t bipage = L4_Sigma0_GetPage(get_sigma0(), L4_Fpage(kip->BootInfo, get_page_size())); @@ -559,7 +554,7 @@ void Platform::_setup_basics() } -Platform_pd &Platform::core_pd() +Platform_pd &Core::Platform::core_pd() { /* on first call, setup task object for core task */ static Platform_pd _core_pd(true); @@ -567,13 +562,13 @@ Platform_pd &Platform::core_pd() } -Platform::Platform() +Core::Platform::Platform() : _ram_alloc(nullptr), _io_mem_alloc(&core_mem_alloc()), _io_port_alloc(&core_mem_alloc()), _irq_alloc(&core_mem_alloc()), _region_alloc(&core_mem_alloc()), - _kip_rom((addr_t)Pistachio::get_kip(), - sizeof(Pistachio::L4_KernelInterfacePage_t), "pistachio_kip") + _kip_rom(_rom_fs, "pistachio_kip", (addr_t)Pistachio::get_kip(), + sizeof(Pistachio::L4_KernelInterfacePage_t)) { /* * We must be single-threaded at this stage and so this is safe. @@ -598,13 +593,10 @@ Platform::Platform() * thread_id of first task. But since we do not destroy this * task, it should be no problem. */ - static Platform_thread core_thread("core.main"); + static Platform_thread core_thread(core_pd(), Pistachio::L4_MyGlobalId()); - core_thread.set_l4_thread_id(Pistachio::L4_MyGlobalId()); core_thread.pager(sigma0()); - core_pd().bind_thread(core_thread); - auto export_page_as_rom_module = [&] (auto rom_name, auto content_fn) { size_t const size = 1 << get_page_size_log2(); @@ -620,8 +612,8 @@ Platform::Platform() memset(core_local_ptr, 0, size); content_fn(core_local_ptr, size); - _rom_fs.insert(new (core_mem_alloc()) - Rom_module(phys_addr, size, rom_name)); + new (core_mem_alloc()) + Rom_module(_rom_fs, rom_name, phys_addr, size); }, [&] (Range_allocator::Alloc_error) { warning("failed to export ", rom_name, " as ROM module"); } @@ -638,8 +630,8 @@ Platform::Platform() [&] (void *core_local_ptr, size_t size) { Xml_generator xml(reinterpret_cast(core_local_ptr), size, "platform_info", - [&] () { - xml.node("kernel", [&] () { + [&] { + xml.node("kernel", [&] { xml.attribute("name", "pistachio"); }); }); }); } @@ -648,7 +640,7 @@ Platform::Platform() ** Generic platform interface ** ********************************/ -void Platform::wait_for_exit() +void Core::Platform::wait_for_exit() { /* * On Pistachio, core never exits. So let us sleep forever. diff --git a/repos/base-pistachio/src/core/platform_pd.cc b/repos/base-pistachio/src/core/platform_pd.cc index 21e91ea481..31d8105df5 100644 --- a/repos/base-pistachio/src/core/platform_pd.cc +++ b/repos/base-pistachio/src/core/platform_pd.cc @@ -13,15 +13,14 @@ */ /* Genode includes */ -#include #include -#include +#include /* base-internal includes */ #include using namespace Pistachio; -using namespace Genode; +using namespace Core; /************************** @@ -117,97 +116,27 @@ void Platform_pd::_free_pd() } -void Platform_pd::_init_threads() +Platform_pd::Alloc_thread_id_result Platform_pd::alloc_thread_id(Platform_thread &thread) { - unsigned i; - - for (i = 0; i < THREAD_MAX; ++i) - _threads[i] = 0; -} - - -Platform_thread* Platform_pd::_next_thread() -{ - unsigned i; - - /* look for bound thread */ - for (i = 0; i < THREAD_MAX; ++i) - if (_threads[i]) break; - - /* no bound threads */ - if (i == THREAD_MAX) return 0; - - return _threads[i]; -} - - -int Platform_pd::_alloc_thread(int thread_id, Platform_thread &thread) -{ - int i = thread_id; - - /* look for free thread */ - if (thread_id == Platform_thread::THREAD_INVALID) { - - /* start from 1 here, because thread 0 is our placeholder thread */ - for (i = 1; i < THREAD_MAX; ++i) - if (!_threads[i]) break; - - /* no free threads available */ - if (i == THREAD_MAX) return -1; - } else { - if (_threads[i]) return -2; + for (unsigned i = 0; i < THREAD_MAX; i++) { + if (_threads[i] == nullptr) { + _threads[i] = &thread; + return Thread_id { i }; + } } - - _threads[i] = &thread; - - return i; + return Alloc_thread_id_error::EXHAUSTED; } -void Platform_pd::_free_thread(int thread_id) +void Platform_pd::free_thread_id(Thread_id const id) { - if (!_threads[thread_id]) - warning("double-free of thread ", Hex(_pd_id), ".", Hex(thread_id), " detected"); + if (id.value >= THREAD_MAX) + return; - _threads[thread_id] = 0; -} + if (!_threads[id.value]) + warning("double-free of thread ", Hex(_pd_id), ".", Hex(id.value), " detected"); - -/*************************** - ** Public object members ** - ***************************/ - -bool Platform_pd::bind_thread(Platform_thread &thread) -{ - using namespace Pistachio; - - /* thread_id is THREAD_INVALID by default - only core is the special case */ - int thread_id = thread.thread_id(); - L4_ThreadId_t l4_thread_id; - - int t = _alloc_thread(thread_id, thread); - if (t < 0) { - error("thread alloc failed"); - return false; - } - thread_id = t; - l4_thread_id = make_l4_id(_pd_id, thread_id, _version); - - /* finally inform thread about binding */ - thread.bind(thread_id, l4_thread_id, *this); - - return true; -} - - -void Platform_pd::unbind_thread(Platform_thread &thread) -{ - int thread_id = thread.thread_id(); - - /* unbind thread before proceeding */ - thread.unbind(); - - _free_thread(thread_id); + _threads[id.value] = nullptr; } @@ -304,8 +233,6 @@ Platform_pd::Platform_pd(bool) : _l4_task_id(L4_MyGlobalId()) */ Pd_alloc free(false, true, 2); - _init_threads(); - /* init remainder */ for (unsigned i = 0 ; i < PD_MAX; ++i) _pds()[i] = free; @@ -324,8 +251,6 @@ Platform_pd::Platform_pd(Allocator &, char const *, signed pd_id, bool create) if (!create) panic("create must be true."); - _init_threads(); - int const id = _alloc_pd(pd_id); if (id < 0) { error("pd alloc failed"); @@ -340,10 +265,6 @@ Platform_pd::Platform_pd(Allocator &, char const *, signed pd_id, bool create) Platform_pd::~Platform_pd() { - /* unbind all threads */ - while (Platform_thread *t = _next_thread()) - unbind_thread(*t); - _destroy_pd(); _free_pd(); } diff --git a/repos/base-pistachio/src/core/platform_thread.cc b/repos/base-pistachio/src/core/platform_thread.cc index 722d0c0001..e006b80345 100644 --- a/repos/base-pistachio/src/core/platform_thread.cc +++ b/repos/base-pistachio/src/core/platform_thread.cc @@ -11,10 +11,6 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* Genode includes */ -#include -#include - /* base-internal includes */ #include #include @@ -25,7 +21,7 @@ #include #include -using namespace Genode; +using namespace Core; using namespace Pistachio; @@ -38,8 +34,8 @@ void Platform_thread::affinity(Affinity::Location location) return; } - if (_l4_thread_id != L4_nilthread) { - if (L4_Set_ProcessorNo(_l4_thread_id, cpu_no) == 0) + if (native_thread_id() != L4_nilthread) { + if (L4_Set_ProcessorNo(native_thread_id(), cpu_no) == 0) error("could not set processor number"); else _location = location; @@ -53,9 +49,12 @@ Affinity::Location Platform_thread::affinity() const } -int Platform_thread::start(void *ip, void *sp) +void Platform_thread::start(void *ip, void *sp) { - L4_ThreadId_t thread = _l4_thread_id; + if (_id.failed()) + return; + + L4_ThreadId_t thread = native_thread_id(); L4_ThreadId_t pager = _pager ? Capability_space::ipc_cap_data(_pager->cap()).dst : L4_nilthread; @@ -63,29 +62,26 @@ int Platform_thread::start(void *ip, void *sp) /* XXX should always be the root task */ L4_ThreadId_t preempter = L4_Myself(); - if (_thread_id == THREAD_INVALID) { - error("attempt to start a thread with invalid ID"); - return -1; - } + L4_Word_t const utcb_location = _id.convert( + [&] (Platform_pd::Thread_id id) { return _pd._utcb_location(id.value); }, + [&] (Platform_pd::Alloc_thread_id_error) { return 0UL; }); - L4_Word_t utcb_location = _platform_pd->_utcb_location(_thread_id); - - int ret = L4_ThreadControl(thread, _platform_pd->_l4_task_id, + int ret = L4_ThreadControl(thread, _pd._l4_task_id, preempter, L4_Myself(), (void *)utcb_location); if (ret != 1) { error(__func__, ": L4_ThreadControl returned ", Hex(L4_ErrorCode())); - return -2; + return; } /* set real pager */ - ret = L4_ThreadControl(thread, _platform_pd->_l4_task_id, + ret = L4_ThreadControl(thread, _pd._l4_task_id, L4_nilthread, pager, (void *)-1); if (ret != 1) { error(__func__, ": L4_ThreadControl returned ", Hex(L4_ErrorCode())); error("setting pager failed"); - return -3; + return; } /* get the thread running on the right cpu */ @@ -107,58 +103,14 @@ int Platform_thread::start(void *ip, void *sp) if (L4_IpcFailed(tag)) { error("starting thread failed. (IPC error)"); - return -4; + return; } - - return 0; -} - - -void Platform_thread::pause() -{ - warning(__func__, " not implemented"); -} - - -void Platform_thread::resume() -{ - warning(__func__, " not implemented"); -} - - -void Platform_thread::bind(int thread_id, L4_ThreadId_t l4_thread_id, - Platform_pd &pd) -{ - _thread_id = thread_id; - _l4_thread_id = l4_thread_id; - _platform_pd = &pd; -} - - -void Platform_thread::unbind() -{ - L4_Word_t res = L4_ThreadControl(_l4_thread_id, L4_nilthread, - L4_nilthread, L4_nilthread, (void *)-1); - - if (res != 1) - error("deleting thread ", Formatted_tid(_l4_thread_id), " failed"); - - _thread_id = THREAD_INVALID; - _l4_thread_id = L4_nilthread; - _platform_pd = 0; -} - - -void Platform_thread::state(Thread_state) -{ - warning(__func__, " not implemented"); - throw Cpu_thread::State_access_failed(); } Thread_state Platform_thread::state() { - Thread_state s; + Thread_state s { }; L4_Word_t dummy; L4_ThreadId_t dummy_tid; @@ -168,23 +120,30 @@ Thread_state Platform_thread::state() DELIVER = 1 << 9, }; - L4_ExchangeRegisters(_l4_thread_id, + L4_ExchangeRegisters(native_thread_id(), DELIVER, 0, 0, 0, 0, L4_nilthread, &dummy, &sp, &ip, &dummy, &dummy, &dummy_tid); - s.ip = ip; - s.sp = sp; + s.cpu.ip = ip; + s.cpu.sp = sp; + s.state = Thread_state::State::VALID; return s; } Platform_thread::~Platform_thread() { - /* - * We inform our protection domain about thread destruction, which will end up in - * Thread::unbind() - */ - if (_platform_pd) - _platform_pd->unbind_thread(*this); + _id.with_result( + [&] (Platform_pd::Thread_id id) { + + L4_Word_t res = L4_ThreadControl(native_thread_id(), L4_nilthread, + L4_nilthread, L4_nilthread, (void *)-1); + if (res != 1) + error("deleting thread ", Formatted_tid(native_thread_id()), " failed"); + + _pd.free_thread_id(id); + }, + [&] (Platform_pd::Alloc_thread_id_error) { } + ); } diff --git a/repos/base-pistachio/src/core/ram_dataspace_support.cc b/repos/base-pistachio/src/core/ram_dataspace_support.cc index 843f3e6ec0..b6f6fae203 100644 --- a/repos/base-pistachio/src/core/ram_dataspace_support.cc +++ b/repos/base-pistachio/src/core/ram_dataspace_support.cc @@ -16,7 +16,7 @@ #include -using namespace Genode; +using namespace Core; void Ram_dataspace_factory::_export_ram_ds(Dataspace_component &) { } diff --git a/repos/base-pistachio/src/core/spec/x86/platform_x86.cc b/repos/base-pistachio/src/core/spec/x86/platform_x86.cc index c7ec258f9d..d6ff5ef11d 100644 --- a/repos/base-pistachio/src/core/spec/x86/platform_x86.cc +++ b/repos/base-pistachio/src/core/spec/x86/platform_x86.cc @@ -14,12 +14,12 @@ /* base-internal includes */ #include -/* core-local includes */ +/* core includes */ #include #include #include -using namespace Genode; +using namespace Core; void Platform::_setup_io_port_alloc() diff --git a/repos/base-pistachio/src/core/thread_start.cc b/repos/base-pistachio/src/core/thread_start.cc index 29ccc8d1f9..d31662b446 100644 --- a/repos/base-pistachio/src/core/thread_start.cc +++ b/repos/base-pistachio/src/core/thread_start.cc @@ -15,14 +15,15 @@ #include #include +/* core includes */ +#include +#include +#include + /* base-internal includes */ #include -/* core includes */ -#include -#include - -using namespace Genode; +using namespace Core; void Thread::_thread_start() @@ -34,18 +35,18 @@ void Thread::_thread_start() } -void Thread::start() +Thread::Start_result Thread::start() { /* create and start platform thread */ native_thread().pt = new (platform().core_mem_alloc()) - Platform_thread(_stack->name().string()); - - platform_specific().core_pd().bind_thread(*native_thread().pt); + Platform_thread(platform_specific().core_pd(), _stack->name().string()); native_thread().pt->pager(platform_specific().core_pager()); native_thread().l4id = native_thread().pt->native_thread_id(); native_thread().pt->start((void *)_thread_start, stack_top()); + + return Start_result::OK; } diff --git a/repos/base-pistachio/src/include/base/internal/native_thread.h b/repos/base-pistachio/src/include/base/internal/native_thread.h index 7ad8f52aa5..d867c9ede5 100644 --- a/repos/base-pistachio/src/include/base/internal/native_thread.h +++ b/repos/base-pistachio/src/include/base/internal/native_thread.h @@ -20,11 +20,9 @@ /* base-internal includes */ #include -namespace Genode { - - class Platform_thread; - struct Native_thread; -} +namespace Genode { struct Native_thread; } + +namespace Core { class Platform_thread; } struct Genode::Native_thread @@ -38,7 +36,7 @@ struct Genode::Native_thread * the physical thread object, which is going to be destroyed * on destruction of the 'Thread'. */ - Platform_thread *pt; + Core::Platform_thread *pt; }; #endif /* _INCLUDE__BASE__INTERNAL__NATIVE_THREAD_H_ */ diff --git a/repos/base-pistachio/src/include/base/internal/rpc_destination.h b/repos/base-pistachio/src/include/base/internal/rpc_destination.h index 2e0f643bc0..684f05ac51 100644 --- a/repos/base-pistachio/src/include/base/internal/rpc_destination.h +++ b/repos/base-pistachio/src/include/base/internal/rpc_destination.h @@ -18,7 +18,7 @@ namespace Genode { - typedef Pistachio::L4_ThreadId_t Rpc_destination; + using Rpc_destination = Pistachio::L4_ThreadId_t; static inline Rpc_destination invalid_rpc_destination() { diff --git a/repos/base-pistachio/src/lib/base/ipc.cc b/repos/base-pistachio/src/lib/base/ipc.cc index ac04cbea76..66d14d9fa0 100644 --- a/repos/base-pistachio/src/lib/base/ipc.cc +++ b/repos/base-pistachio/src/lib/base/ipc.cc @@ -15,7 +15,6 @@ /* Genode includes */ #include #include -#include #include /* base-internal includes */ @@ -32,26 +31,18 @@ using namespace Pistachio; */ static inline void check_ipc_result(L4_MsgTag_t result, L4_Word_t error_code) { - /* - * Test for IPC cancellation via Core's cancel-blocking mechanism - */ - enum { ERROR_MASK = 0xe, ERROR_CANCELED = 3 << 1 }; - if (L4_IpcFailed(result) && - ((L4_ErrorCode() & ERROR_MASK) == ERROR_CANCELED)) - throw Genode::Blocking_canceled(); - /* * Provide diagnostic information on unexpected conditions */ if (L4_IpcFailed(result)) { raw("Error in thread ", Hex(L4_Myself().raw), ". IPC failed."); - throw Genode::Ipc_error(); + throw Ipc_error(); } if (L4_UntypedWords(result) < 2) { raw("Error in thread ", Hex(L4_Myself().raw), ". " "Expected at leat two untyped words, but got ", L4_UntypedWords(result), ".\n"); - throw Genode::Ipc_error(); + throw Ipc_error(); } } diff --git a/repos/base-pistachio/src/lib/base/thread_bootstrap.cc b/repos/base-pistachio/src/lib/base/thread_bootstrap.cc index de515d4b37..36d74dcec8 100644 --- a/repos/base-pistachio/src/lib/base/thread_bootstrap.cc +++ b/repos/base-pistachio/src/lib/base/thread_bootstrap.cc @@ -20,14 +20,24 @@ #include #include +using namespace Genode; + + Pistachio::L4_ThreadId_t main_thread_tid; +static Thread_capability main_thread_cap(Thread_capability main_cap = { }) +{ + static Thread_capability cap = main_cap; + return cap; +} + + /***************************** ** Startup library support ** *****************************/ -void prepare_init_main_thread() +void Genode::prepare_init_main_thread() { main_thread_tid = Pistachio::L4_Myself(); } @@ -52,3 +62,9 @@ void Genode::Thread::_init_platform_thread(size_t, Type type) _thread_cap = main_thread_cap(); } + + +void Genode::init_thread_bootstrap(Cpu_session &, Thread_capability main_cap) +{ + main_thread_cap(main_cap); +} diff --git a/repos/base-sel4/include/sel4/functions_aarch32.h b/repos/base-sel4/include/sel4/functions_aarch32.h new file mode 100644 index 0000000000..3c171b8842 --- /dev/null +++ b/repos/base-sel4/include/sel4/functions_aarch32.h @@ -0,0 +1,24 @@ +/* + * \brief Implementation for seL4_GetIPCBuffer on aarch32 + * \author Alexander Boettcher + * \date 2023-05-23 + */ + +/* + * Copyright (C) 2023 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _INCLUDE__SEL4__FUNCTIONS_AARCH32_H_ +#define _INCLUDE__SEL4__FUNCTIONS_AARCH32_H_ + +LIBSEL4_INLINE_FUNC seL4_IPCBuffer *seL4_GetIPCBuffer(void) +{ + seL4_IPCBuffer ** ptr = nullptr; + asm volatile ("mrc p15, 0, %0, c13, c0, 2" : "=r"(ptr)); + return *ptr; +} + +#endif /* _INCLUDE__SEL4__FUNCTIONS_AARCH32_H_ */ diff --git a/repos/base-sel4/include/sel4/functions_x86_64.h b/repos/base-sel4/include/sel4/functions_x86_64.h new file mode 100644 index 0000000000..3ef3cc29e8 --- /dev/null +++ b/repos/base-sel4/include/sel4/functions_x86_64.h @@ -0,0 +1,24 @@ +/* + * \brief Implementation for seL4_GetIPCBuffer on x86_64 + * \author Alexander Boettcher + * \date 2023-05-23 + */ + +/* + * Copyright (C) 2023 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _INCLUDE__SEL4__FUNCTIONS_X86_64_H_ +#define _INCLUDE__SEL4__FUNCTIONS_X86_64_H_ + +LIBSEL4_INLINE_FUNC seL4_IPCBuffer *seL4_GetIPCBuffer(void) +{ + seL4_IPCBuffer * ptr = nullptr; + asm volatile ("movq %%fs:0, %0" : "=r" (ptr) : :); + return ptr; +} + +#endif /* _INCLUDE__SEL4__FUNCTIONS_X86_64_H_ */ diff --git a/repos/base-sel4/lib/mk/base-sel4-common.inc b/repos/base-sel4/lib/mk/base-sel4-common.inc index 70171a9b49..a6606a746f 100644 --- a/repos/base-sel4/lib/mk/base-sel4-common.inc +++ b/repos/base-sel4/lib/mk/base-sel4-common.inc @@ -12,4 +12,3 @@ SRC_CC += rpc_dispatch_loop.cc SRC_CC += thread.cc thread_myself.cc thread_bootstrap.cc SRC_CC += capability.cc capability_raw.cc SRC_CC += stack_area_addr.cc -SRC_CC += platform.cc diff --git a/repos/base-sel4/lib/mk/base-sel4.inc b/repos/base-sel4/lib/mk/base-sel4.inc index b59644222b..5d7dff8b13 100644 --- a/repos/base-sel4/lib/mk/base-sel4.inc +++ b/repos/base-sel4/lib/mk/base-sel4.inc @@ -1,6 +1,6 @@ include $(BASE_DIR)/lib/mk/base.inc -SRC_CC += capability_space.cc +SRC_CC += capability_space.cc capability_slab.cc SRC_CC += thread_start.cc thread_init.cc SRC_CC += cache.cc SRC_CC += signal_transmitter.cc signal.cc diff --git a/repos/base-sel4/lib/mk/spec/arm/kernel-sel4-imx7d_sabre.mk b/repos/base-sel4/lib/mk/spec/arm/kernel-sel4-imx7d_sabre.mk deleted file mode 100644 index e708620e4f..0000000000 --- a/repos/base-sel4/lib/mk/spec/arm/kernel-sel4-imx7d_sabre.mk +++ /dev/null @@ -1,5 +0,0 @@ -PLAT := imx7 -CPU := cortex-a7 -override BOARD := imx7d_sabre - --include $(REP_DIR)/lib/mk/spec/arm/kernel-sel4.inc diff --git a/repos/base-sel4/lib/mk/spec/arm/kernel-sel4.inc b/repos/base-sel4/lib/mk/spec/arm/kernel-sel4.inc index dc9cfee611..954e2cac08 100644 --- a/repos/base-sel4/lib/mk/spec/arm/kernel-sel4.inc +++ b/repos/base-sel4/lib/mk/spec/arm/kernel-sel4.inc @@ -18,14 +18,36 @@ else SEL4_CCACHE= endif -elfloader/elfloader.o: +configured_kernel: + $(VERBOSE) cmake -DCROSS_COMPILER_PREFIX=$(CROSS_DEV_PREFIX) \ + -DCMAKE_TOOLCHAIN_FILE=$(SEL4_DIR)/gcc.cmake \ + -DKernelARMPlatform=sabre \ + -G Ninja \ + -C $(SEL4_DIR)/configs/ARM_verified.cmake \ + $(SEL4_DIR) \ + && echo -e "\n#define CONFIG_PRINTING 1" >>gen_config/kernel/gen_config.h \ + && echo -e "#define CONFIG_DEBUG_BUILD 1" >>gen_config/kernel/gen_config.h \ + && echo -e "#define CONFIG_ENABLE_BENCHMARKS 1" >>gen_config/kernel/gen_config.h \ + && echo -e "#define CONFIG_BENCHMARK_TRACK_UTILISATION 1" >>gen_config/kernel/gen_config.h \ + && echo -e "#define CONFIG_SET_TLS_BASE_SELF 1" >>gen_config/kernel/gen_config.h \ + && echo -e "#define CONFIG_HAVE_FPU 1" >>gen_config/kernel/gen_config.h \ + && echo -e "#define CONFIG_AARCH32_FPU_ENABLE_CONTEXT_SWITCH 1" >>gen_config/kernel/gen_config.h \ + && echo -e "#define CONFIG_FPU_MAX_RESTORES_SINCE_SWITCH 64" >>gen_config/kernel/gen_config.h \ + \ + && sed -e "s/CONFIG_NUM_DOMAINS 16/CONFIG_NUM_DOMAINS 1/" \ + -e "s/CONFIG_ROOT_CNODE_SIZE_BITS 12/CONFIG_ROOT_CNODE_SIZE_BITS 15/" \ + gen_config/kernel/gen_config.h >gen_config/kernel/gen_config.tmp \ + && mv gen_config/kernel/gen_config.tmp gen_config/kernel/gen_config.h \ + && touch configured_kernel + +elfloader/elfloader.o: configured_kernel $(VERBOSE)cp -r $(TOOLS_DIR)/elfloader-tool $(LIB_CACHE_DIR)/$(LIB)/elfloader $(VERBOSE)mkdir -p $(LIB_CACHE_DIR)/$(LIB)/elfloader/tools/kbuild $(VERBOSE)mkdir -p $(LIB_CACHE_DIR)/$(LIB)/elfloader/include/generated $(VERBOSE)ln -s $(TOOLS_DIR)/common-tool/common.mk $(LIB_CACHE_DIR)/$(LIB)/elfloader/ $(VERBOSE)ln -s $(TOOLS_DIR)/common-tool/files_to_obj.sh $(LIB_CACHE_DIR)/$(LIB)/elfloader/ $(VERBOSE)ln -s $(TOOLS_DIR)/kbuild-tool/Kbuild.include $(LIB_CACHE_DIR)/$(LIB)/elfloader/tools/kbuild/ - $(VERBOSE)ln -s $(SEL4_DIR)/configs/$(PLAT)/$(BOARD)/autoconf.h $(LIB_CACHE_DIR)/$(LIB)/elfloader/include/generated/ + $(VERBOSE)ln -s $(LIB_CACHE_DIR)/$(LIB)/gen_config/kernel/gen_config.h $(LIB_CACHE_DIR)/$(LIB)/elfloader/include/generated/autoconf.h $(VERBOSE)$(MAKE) -C $(LIB_CACHE_DIR)/$(LIB)/elfloader \ TOOLPREFIX=$(CROSS_DEV_PREFIX) \ ARCH=arm PLAT=$(PLAT) ARMV=armv7-a __ARM_32__="y" \ @@ -35,7 +57,5 @@ elfloader/elfloader.o: srctree=. build_kernel: elfloader/elfloader.o - $(VERBOSE)$(MAKE) \ - TOOLPREFIX=$(CROSS_DEV_PREFIX) \ - BOARD=$(BOARD) ARCH=arm PLAT=$(PLAT) CPU=$(CPU) ARMV=armv7-a DEBUG=1 \ - SOURCE_ROOT=$(SEL4_DIR) -f$(SEL4_DIR)/Makefile + $(VERBOSE) ninja kernel.elf && \ + $(CUSTOM_STRIP) -o kernel.elf.strip kernel.elf diff --git a/repos/base-sel4/lib/mk/spec/arm/syscall-sel4-imx6q_sabrelite.mk b/repos/base-sel4/lib/mk/spec/arm/syscall-sel4-imx6q_sabrelite.mk index 16d149b926..449c39b762 100644 --- a/repos/base-sel4/lib/mk/spec/arm/syscall-sel4-imx6q_sabrelite.mk +++ b/repos/base-sel4/lib/mk/spec/arm/syscall-sel4-imx6q_sabrelite.mk @@ -1,8 +1,10 @@ PLAT := imx6 ARCH := arm +BOARD := imx6q_sabrelite SEL4_ARCH := aarch32 -PLAT_BOARD := /imx6q_sabrelite SEL4_WORDBITS := 32 +LIBS += kernel-sel4-imx6q_sabrelite + include $(REP_DIR)/lib/mk/syscall-sel4.inc diff --git a/repos/base-sel4/lib/mk/spec/arm/syscall-sel4-imx7d_sabre.mk b/repos/base-sel4/lib/mk/spec/arm/syscall-sel4-imx7d_sabre.mk deleted file mode 100644 index 675bd0d742..0000000000 --- a/repos/base-sel4/lib/mk/spec/arm/syscall-sel4-imx7d_sabre.mk +++ /dev/null @@ -1,8 +0,0 @@ -PLAT := imx7 -ARCH := arm - -SEL4_ARCH := aarch32 -PLAT_BOARD := /imx7d_sabre -SEL4_WORDBITS := 32 - -include $(REP_DIR)/lib/mk/syscall-sel4.inc diff --git a/repos/base-sel4/lib/mk/spec/x86_32/core-sel4.mk b/repos/base-sel4/lib/mk/spec/x86_32/core-sel4.mk deleted file mode 100644 index 732de2cbdf..0000000000 --- a/repos/base-sel4/lib/mk/spec/x86_32/core-sel4.mk +++ /dev/null @@ -1,21 +0,0 @@ -GEN_SRC_CC = \ - spec/x86/io_port_session_component.cc \ - vm_session_common.cc - -REP_SRC_CC = \ - spec/x86/io_port_session_support.cc \ - spec/x86/irq.cc \ - spec/x86/platform_services.cc \ - spec/x86/platform_thread.cc \ - spec/x86/vm_space.cc \ - spec/x86/vm_session_component.cc \ - spec/x86_32/boot_info.cc \ - spec/x86_32/platform.cc \ - spec/x86_32/platform_pd.cc \ - spec/x86_32/thread.cc \ - spec/x86_32/vm_space.cc - -INC_DIR += $(REP_DIR)/src/core/spec/x86_32 -INC_DIR += $(REP_DIR)/src/core/spec/x86 - -include $(REP_DIR)/lib/mk/core-sel4.inc diff --git a/repos/base-sel4/lib/mk/spec/x86_32/kernel-sel4-pc.mk b/repos/base-sel4/lib/mk/spec/x86_32/kernel-sel4-pc.mk deleted file mode 100644 index 5ecbe6aecd..0000000000 --- a/repos/base-sel4/lib/mk/spec/x86_32/kernel-sel4-pc.mk +++ /dev/null @@ -1,19 +0,0 @@ -SEL4_DIR := $(call select_from_ports,sel4)/src/kernel/sel4 - -# -# Execute the kernel build only at the second build stage when we know -# about the complete build settings (e.g., the 'CROSS_DEV_PREFIX') and the -# current working directory is the library location. -# -ifeq ($(called_from_lib_mk),yes) -all: build_kernel -else -all: -endif - -build_kernel: - $(VERBOSE)$(MAKE) \ - TOOLPREFIX=$(CROSS_DEV_PREFIX) \ - BOARD=ia32 ARCH=x86 SEL4_ARCH=ia32 PLAT=pc99 DEBUG=1 \ - SOURCE_ROOT=$(SEL4_DIR) -f$(SEL4_DIR)/Makefile - diff --git a/repos/base-sel4/lib/mk/spec/x86_32/ld-sel4.mk b/repos/base-sel4/lib/mk/spec/x86_32/ld-sel4.mk deleted file mode 100644 index 090b9884dc..0000000000 --- a/repos/base-sel4/lib/mk/spec/x86_32/ld-sel4.mk +++ /dev/null @@ -1,3 +0,0 @@ -BASE_LIBS += base-sel4-common base-sel4 - -include $(BASE_DIR)/lib/mk/spec/x86_32/ld-platform.inc diff --git a/repos/base-sel4/lib/mk/spec/x86_32/startup-sel4.mk b/repos/base-sel4/lib/mk/spec/x86_32/startup-sel4.mk deleted file mode 100644 index 7042fbc7a1..0000000000 --- a/repos/base-sel4/lib/mk/spec/x86_32/startup-sel4.mk +++ /dev/null @@ -1,10 +0,0 @@ -# -# Make the includes of src/base/include/ available to the startup lib. This is -# needed because the seL4-specific src/platform/_main_parent_cap.h as included -# by the startup lib depends on base/internal/capability_space_sel4.h. -# -INC_DIR += $(REP_DIR)/src/include $(BASE_DIR)/src/include - -LIBS += syscall-sel4 - -include $(BASE_DIR)/lib/mk/spec/x86_32/startup.inc diff --git a/repos/base-sel4/lib/mk/spec/x86_32/syscall-sel4-pc.mk b/repos/base-sel4/lib/mk/spec/x86_32/syscall-sel4-pc.mk deleted file mode 100644 index 9f49056d07..0000000000 --- a/repos/base-sel4/lib/mk/spec/x86_32/syscall-sel4-pc.mk +++ /dev/null @@ -1,10 +0,0 @@ -PLAT := pc99 -ARCH := x86 - -SEL4_ARCH := ia32 -PLAT_BOARD := /$(SEL4_ARCH) -SEL4_WORDBITS := 32 - -ARCH_INCLUDES := exIPC.h vmenter.h - -include $(REP_DIR)/lib/mk/syscall-sel4.inc diff --git a/repos/base-sel4/lib/mk/spec/x86_64/kernel-sel4-pc.mk b/repos/base-sel4/lib/mk/spec/x86_64/kernel-sel4-pc.mk index 0ad8b149e0..bb38b30de4 100644 --- a/repos/base-sel4/lib/mk/spec/x86_64/kernel-sel4-pc.mk +++ b/repos/base-sel4/lib/mk/spec/x86_64/kernel-sel4-pc.mk @@ -11,9 +11,36 @@ else all: endif -build_kernel: - $(VERBOSE)$(MAKE) \ - TOOLPREFIX=$(CROSS_DEV_PREFIX) \ - BOARD=x86_64 ARCH=x86 SEL4_ARCH=x86_64 PLAT=pc99 DEBUG=1 \ - SOURCE_ROOT=$(SEL4_DIR) -f$(SEL4_DIR)/Makefile +configured_kernel: + $(VERBOSE) cmake -DCROSS_COMPILER_PREFIX=$(CROSS_DEV_PREFIX) \ + -DCMAKE_TOOLCHAIN_FILE=$(SEL4_DIR)/gcc.cmake \ + -G Ninja \ + -C $(SEL4_DIR)/configs/X64_verified.cmake \ + $(SEL4_DIR) \ + \ + && echo -e "\n#define CONFIG_PRINTING 1" >>gen_config/kernel/gen_config.h \ + && echo -e "#define CONFIG_DEBUG_BUILD 1" >>gen_config/kernel/gen_config.h \ + && echo -e "#define CONFIG_VTX 1" >>gen_config/kernel/gen_config.h \ + && echo -e "#define CONFIG_ENABLE_BENCHMARKS 1" >>gen_config/kernel/gen_config.h \ + && echo -e "#define CONFIG_BENCHMARK_TRACK_UTILISATION 1" >>gen_config/kernel/gen_config.h \ + && echo -e "#define CONFIG_ARCH_X86_GENERIC 1" >>gen_config/kernel/gen_config.h \ + && echo -e "#define CONFIG_FXSAVE 1" >>gen_config/kernel/gen_config.h \ + && echo -e "#define CONFIG_SET_TLS_BASE_SELF 1" >>gen_config/kernel/gen_config.h \ + \ + && sed -e "s/CONFIG_MAX_NUM_NODES 1/CONFIG_MAX_NUM_NODES 16/" \ + -e "s/CONFIG_MAX_VPIDS 0/CONFIG_MAX_VPIDS 64/" \ + -e "s/CONFIG_NUM_DOMAINS 16/CONFIG_NUM_DOMAINS 1/" \ + -e "s/CONFIG_MAX_NUM_BOOTINFO_UNTYPED_CAPS 50/CONFIG_MAX_NUM_BOOTINFO_UNTYPED_CAPS 160/" \ + -e "s/CONFIG_FSGSBASE_INST 1/CONFIG_FSGSBASE_MSR 1/" \ + -e "s/CONFIG_KERNEL_FSGS_BASE inst/CONFIG_KERNEL_FSGS_BASE msr/" \ + -e "/CONFIG_HUGE_PAGE/d" \ + -e "/CONFIG_SUPPORT_PCID/d" \ + -e "/CONFIG_XSAVE 1/d" \ + -e "/CONFIG_XSAVE_XSAVEOPT 1/d" \ + gen_config/kernel/gen_config.h >gen_config/kernel/gen_config.tmp \ + && mv gen_config/kernel/gen_config.tmp gen_config/kernel/gen_config.h \ + && touch configured_kernel +build_kernel: configured_kernel + $(VERBOSE) ninja kernel.elf && \ + $(CUSTOM_STRIP) -o kernel.elf.strip kernel.elf diff --git a/repos/base-sel4/lib/mk/spec/x86_64/syscall-sel4-pc.mk b/repos/base-sel4/lib/mk/spec/x86_64/syscall-sel4-pc.mk index a7fec89056..73ced6e6e1 100644 --- a/repos/base-sel4/lib/mk/spec/x86_64/syscall-sel4-pc.mk +++ b/repos/base-sel4/lib/mk/spec/x86_64/syscall-sel4-pc.mk @@ -1,11 +1,13 @@ PLAT := pc99 ARCH := x86 +BOARD := pc SEL4_ARCH := x86_64 -PLAT_BOARD := /$(SEL4_ARCH) SEL4_WORDBITS := 64 ARCH_INCLUDES := exIPC.h vmenter.h SEL4_ARCH_INCLUDES := syscalls_syscall.h +LIBS += kernel-sel4-pc + include $(REP_DIR)/lib/mk/syscall-sel4.inc diff --git a/repos/base-sel4/lib/mk/syscall-sel4.inc b/repos/base-sel4/lib/mk/syscall-sel4.inc index af9b286d46..5382835188 100644 --- a/repos/base-sel4/lib/mk/syscall-sel4.inc +++ b/repos/base-sel4/lib/mk/syscall-sel4.inc @@ -10,7 +10,6 @@ # port, if missing, is added to the missing-ports list of this stage. # LIBSEL4_DIR := $(call select_from_ports,sel4)/src/kernel/sel4/libsel4 -LIBSEL4_AUTO:= $(call select_from_ports,sel4)/src/kernel/sel4/configs/$(PLAT)$(PLAT_BOARD) # # Execute the rules in this file only at the second build stage when we know @@ -29,14 +28,15 @@ SEL4_ARCH_INCLUDES += simple_types.h types.h constants.h objecttype.h \ functions.h syscalls.h invocation.h deprecated.h \ types_gen.h faults.h -ARCH_INCLUDES += objecttype.h types.h constants.h functions.h deprecated.h \ +ARCH_INCLUDES += objecttype.h types.h constants.h deprecated.h \ syscalls.h invocation.h simple_types.h INCLUDES := objecttype.h types.h bootinfo.h bootinfo_types.h errors.h \ - constants.h messages.h sel4.h macros.h simple_types.h \ + constants.h sel4.h macros.h simple_types.h \ syscall.h invocation.h shared_types_gen.h debug_assert.h \ - shared_types.h sel4.h deprecated.h autoconf.h syscalls.h faults.h \ - benchmark_utilisation_types.h + shared_types.h deprecated.h autoconf.h syscalls.h faults.h \ + benchmark_utilisation_types.h \ + syscalls_master.h virtual_client.h PLAT_API_INCLUDES := constants.h @@ -49,6 +49,29 @@ INCLUDE_SYMLINKS += include/interfaces/sel4_client.h all: $(INCLUDE_SYMLINKS) +# +# IPCBuffer pointer are not set up by kernel anymore, instead user land has +# to care about tracking the IPCBuffer, details are in the RFC +# +# https://sel4.atlassian.net/browse/RFC-3 +# +# The usage of the __thread variable in the original include/sel4/functions.h +# would require our emutls emulation to work in core/roottask at an very +# early stage, which we don't support currently. +# +# As workaround, we setup the tls pointer per architecture such, that it +# points to the IPCBuffer pointer per thread, which is implemented in +# repos/base-sel4/include/sel4/functions_$(SEL4_ARCH).h +# +include/sel4/sel4_arch/functions.h: $(LIBSEL4_DIR)/include/sel4/functions.h + $(VERBOSE)mkdir -p $(dir $@) && \ + sed -e "s|extern __thread seL4_IPCBuffer|//extern __thread seL4_IPCBuffer|" \ + -e "s|#include |#include \n#include \n|" \ + -e "/LIBSEL4_INLINE_FUNC void seL4_SetIPCBuffer(seL4_IPCBuffer \*ipc_buffer)/,+4d" \ + -e "/LIBSEL4_INLINE_FUNC seL4_IPCBuffer \*seL4_GetIPCBuffer/,+3d" \ + $< >include/sel4/functions.h && \ + touch $@ + # # Plain symlinks to existing headers # @@ -60,9 +83,11 @@ include/sel4/arch/%.h: $(LIBSEL4_DIR)/arch_include/$(ARCH)/sel4/arch/%.h $(VERBOSE)mkdir -p $(dir $@) $(VERBOSE)ln -sf $< $@ -include/sel4/autoconf.h: $(LIBSEL4_AUTO)/autoconf.h +include/sel4/autoconf.h: $(LIB_CACHE_DIR)/kernel-sel4-$(BOARD)/autoconf/autoconf.h $(VERBOSE)mkdir -p $(dir $@) $(VERBOSE)ln -sf $< $@ + $(VERBOSE)mkdir include/sel4/kernel -p + $(VERBOSE)ln -sf $(LIB_CACHE_DIR)/kernel-sel4-$(BOARD)/gen_config/kernel/gen_config.h include/sel4/kernel/gen_config.h include/sel4/%.h: $(LIBSEL4_DIR)/include/sel4/%.h $(VERBOSE)mkdir -p $(dir $@) @@ -79,17 +104,17 @@ include/sel4/mode/types.h: $(LIBSEL4_DIR)/mode_include/$(SEL4_WORDBITS)/sel4/mod # # Generated headers # -include/sel4/%.pbf: $(LIBSEL4_DIR)/include/sel4/%.bf include/sel4/autoconf.h +include/sel4/mode_include/$(SEL4_WORDBITS)/sel4/shared_types.pbf: $(LIBSEL4_DIR)/mode_include/$(SEL4_WORDBITS)/sel4/shared_types.bf include/sel4/autoconf.h $(MSG_CONVERT)$(notdir $@) $(VERBOSE)mkdir -p $(dir $@) - $(VERBOSE)$(CPP) -P $< >$@ + $(VERBOSE)$(CPP) -Iinclude/sel4 -P $< >$@ include/sel4/sel4_arch/types.pbf: $(LIBSEL4_DIR)/sel4_arch_include/$(SEL4_ARCH)/sel4/sel4_arch/types.bf include/sel4/autoconf.h $(MSG_CONVERT)$(notdir $@) $(VERBOSE)mkdir -p $(dir $@) $(VERBOSE)$(CPP) -Iinclude/sel4 -I$(LIBSEL4_DIR)/arch_include/$(ARCH) -P $< >$@ -include/sel4/shared_types_gen.h: include/sel4/shared_types_$(SEL4_WORDBITS).pbf +include/sel4/shared_types_gen.h: include/sel4/mode_include/$(SEL4_WORDBITS)/sel4/shared_types.pbf $(MSG_CONVERT)$(notdir $@) $(VERBOSE)mkdir -p $(dir $@) $(VERBOSE)python -B $(LIBSEL4_DIR)/tools/bitfield_gen.py \ diff --git a/repos/base-sel4/mk/spec/sel4_x86_32.mk b/repos/base-sel4/mk/spec/sel4_x86_32.mk deleted file mode 100644 index 17b2b520b5..0000000000 --- a/repos/base-sel4/mk/spec/sel4_x86_32.mk +++ /dev/null @@ -1,4 +0,0 @@ -# \deprecated - -SPECS += x86_32 -include $(call select_from_repositories,mk/spec/x86_32.mk) diff --git a/repos/base-sel4/patches/address_of_packed_member.patch b/repos/base-sel4/patches/address_of_packed_member.patch deleted file mode 100644 index e3113f61c2..0000000000 --- a/repos/base-sel4/patches/address_of_packed_member.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 3e83f89990e356b02b227cd883d32ccafa283127 Mon Sep 17 00:00:00 2001 -From: Simon Shields -Date: Tue, 17 Sep 2019 11:54:22 +1000 -Subject: [PATCH] x86: avoid -Waddress-of-packed-member - -It's safe to take the address of this member, since it's the -first thing in a cacheline-aligned struct. ---- - include/arch/x86/arch/32/mode/stack.h | 7 ++++++- - src/arch/x86/kernel/vspace.c | 9 +++++++-- - 2 files changed, 13 insertions(+), 3 deletions(-) - -diff --git a/include/arch/x86/arch/32/mode/stack.h b/include/arch/x86/arch/32/mode/stack.h -index 93304b96fa..e8e7f1c254 100644 ---- src/kernel/sel4/include/arch/x86/arch/32/mode/stack.h -+++ src/kernel/sel4/include/arch/x86/arch/32/mode/stack.h -@@ -45,7 +45,12 @@ static inline void setKernelEntryStackPointer(tcb_t *target_thread) - /* The first item to be pushed onto the stack should always be SS */ - register_context_top = (word_t)&target_thread->tcbArch.tcbContext.registers[SS + 1]; - -- tss_ptr_set_esp0(&x86KSGlobalState[CURRENT_CPU_INDEX()].x86KStss.tss, register_context_top); -+ /* -+ * Work around -Waddress-of-packed-member. TSS is the first thing -+ * in the struct and so it's safe to take its address. -+ */ -+ void *tss = &x86KSGlobalState[CURRENT_CPU_INDEX()].x86KStss.tss; -+ tss_ptr_set_esp0(tss, register_context_top); - - if (config_set(CONFIG_HARDWARE_DEBUG_API)) { - x86_wrmsr(IA32_SYSENTER_ESP_MSR, register_context_top); -diff --git a/src/arch/x86/kernel/vspace.c b/src/arch/x86/kernel/vspace.c -index 0ff6d30fff..be9d5f6266 100644 ---- src/kernel/sel4/src/arch/x86/kernel/vspace.c -+++ src/kernel/sel4/src/arch/x86/kernel/vspace.c -@@ -493,8 +493,13 @@ BOOT_CODE bool_t init_vm_state(void) - SMP_COND_STATEMENT(return false); - } - -- init_tss(&x86KSGlobalState[CURRENT_CPU_INDEX()].x86KStss.tss); -- init_gdt(x86KSGlobalState[CURRENT_CPU_INDEX()].x86KSgdt, &x86KSGlobalState[CURRENT_CPU_INDEX()].x86KStss.tss); -+ /* -+ * Work around -Waddress-of-packed-member. TSS is the first thing -+ * in the struct and so it's safe to take its address. -+ */ -+ void *tss_ptr = &x86KSGlobalState[CURRENT_CPU_INDEX()].x86KStss.tss; -+ init_tss(tss_ptr); -+ init_gdt(x86KSGlobalState[CURRENT_CPU_INDEX()].x86KSgdt, tss_ptr); - init_idt(x86KSGlobalState[CURRENT_CPU_INDEX()].x86KSidt); - return true; - } diff --git a/repos/base-sel4/patches/arm_no_dtb.patch b/repos/base-sel4/patches/arm_no_dtb.patch new file mode 100644 index 0000000000..aad61c4cb2 --- /dev/null +++ b/repos/base-sel4/patches/arm_no_dtb.patch @@ -0,0 +1,15 @@ +--- src/kernel/sel4/src/arch/arm/kernel/boot.c ++++ src/kernel/sel4/src/arch/arm/kernel/boot.c +@@ -582,6 +582,12 @@ + dtb_end_p = dtb_addr_p + dtb_size; + } + ++ /* ++ * no DTB support on Genode/seL4 - avoids assertion in ++ * src/kernel/boot.c: assert(r->start >= reserved[i - 1].end); ++ */ ++ dtb_addr_p = dtb_end_p = 0; ++ + #ifdef ENABLE_SMP_SUPPORT + /* we assume there exists a cpu with id 0 and will use it for bootstrapping */ + if (getCurrentCPUIndex() == 0) { diff --git a/repos/base-sel4/patches/autoconf_32.patch b/repos/base-sel4/patches/autoconf_32.patch deleted file mode 100644 index fc7daf1cca..0000000000 --- a/repos/base-sel4/patches/autoconf_32.patch +++ /dev/null @@ -1,48 +0,0 @@ ---- src/kernel/sel4/configs/pc99/autoconf.h -+++ src/kernel/sel4/configs/pc99/autoconf.h -@@ -51,13 +51,13 @@ - #define CONFIG_MAX_NUM_BOOTINFO_UNTYPED_CAPS 167 - #define CONFIG_FPU_MAX_RESTORES_SINCE_SWITCH 64 - #define CONFIG_LIB_SEL4_VKA_DEBUG_LIVE_SLOTS_SZ 0 --#define CONFIG_MAX_NUM_NODES 1 -+#define CONFIG_MAX_NUM_NODES 16 - #define CONFIG_CROSS_COMPILER_PREFIX "" - #define CONFIG_LIB_SEL4_INLINE_INVOCATIONS 1 - #define CONFIG_LIB_SEL4_MUSLC_SYS 1 - #define CONFIG_HAVE_LIB_SEL4_TEST 1 - #define CONFIG_LIB_MUSL_C 1 --#define CONFIG_ARCH_X86_NEHALEM 1 -+#define CONFIG_ARCH_X86_GENERIC 1 - #define CONFIG_MAX_NUM_WORK_UNITS_PER_PREEMPTION 100 - #define CONFIG_USER_CFLAGS "" - #define CONFIG_HAVE_LIB_SEL4_DEBUG 1 -@@ -75,13 +75,13 @@ - #define CONFIG_HAVE_LIB_SEL4_SIMPLE 1 - #define CONFIG_HAVE_LIB_ELF 1 - #define CONFIG_HAVE_LIB_PLATSUPPORT 1 --#define CONFIG_NUM_DOMAINS 16 -+#define CONFIG_NUM_DOMAINS 1 - #define CONFIG_ARCH_IA32 1 - #define CONFIG_HAVE_LIB_UTILS 1 - #define CONFIG_USER_OPTIMISATION_O2 1 - #define CONFIG_LIB_CPIO 1 - #define CONFIG_RETYPE_FAN_OUT_LIMIT 256 --#define CONFIG_ROOT_CNODE_SIZE_BITS 16 -+#define CONFIG_ROOT_CNODE_SIZE_BITS 18 - #define CONFIG_NUM_PRIORITIES 256 - #define CONFIG_TESTPRINTER_REGEX ".*" - #define CONFIG_APP_SEL4TEST 1 -@@ -96,6 +96,13 @@ - #define CONFIG_CACHE_LN_SZ 64 - #define CONFIG_LIB_SEL4_MUSLC_SYS_MORECORE_BYTES 1048576 - #define CONFIG_BUILDSYS_USE_CCACHE 1 -+#define CONFIG_MULTIBOOT1_HEADER -+#define CONFIG_MULTIBOOT2_HEADER -+#define CONFIG_PRINTING 1 -+#define CONFIG_ENABLE_BENCHMARKS 1 -+#define CONFIG_BENCHMARK_TRACK_UTILISATION 1 -+#define CONFIG_VTX 1 -+#define CONFIG_MAX_VPIDS 64 - #else - #define AUTOCONF_INCLUDED - #define CONFIG_LIB_SEL4_SIMPLE 1 diff --git a/repos/base-sel4/patches/autoconf_64.patch b/repos/base-sel4/patches/autoconf_64.patch deleted file mode 100644 index de290d4491..0000000000 --- a/repos/base-sel4/patches/autoconf_64.patch +++ /dev/null @@ -1,63 +0,0 @@ ---- src/kernel/sel4/configs/pc99/autoconf.h -+++ src/kernel/sel4/configs/pc99/autoconf.h -@@ -129,7 +129,7 @@ - #define CONFIG_SEL4UTILS_STACK_SIZE 655360 - #define CONFIG_HAVE_LIB_SEL4_ALLOCMAN 1 - #define CONFIG_FASTPATH 1 --#define CONFIG_X2APIC 1 -+#define CONFIG_XAPIC 1 - #define CONFIG_LIB_SEL4_VKA_DEBUG_LIVE_OBJS_SZ 0 - #define CONFIG_HAVE_TIMER 1 - #define CONFIG_SEL4UTILS_CSPACE_SIZE_BITS 18 -@@ -147,7 +147,6 @@ - #define CONFIG_MAX_NUM_BOOTINFO_UNTYPED_CAPS 230 - #define CONFIG_LIB_SEL4_VKA_DEBUG_LIVE_SLOTS_SZ 0 - #define CONFIG_SYSCALL 1 --#define CONFIG_MAX_NUM_NODES 1 - #define CONFIG_CROSS_COMPILER_PREFIX "" - #define CONFIG_MAX_RMRR_ENTRIES 32 - #define CONFIG_LIB_SEL4_INLINE_INVOCATIONS 1 -@@ -162,21 +161,20 @@ - #define CONFIG_OPTIMISATION_O2 1 - #define CONFIG_HAVE_LIB_CPIO 1 - #define CONFIG_HAVE_LIB_SEL4_VKA 1 --#define CONFIG_FSGSBASE_INST 1 -+#define CONFIG_FSGSBASE_MSR 1 - #define CONFIG_HAVE_LIB_SEL4_PLAT_SUPPORT 1 - #define CONFIG_USER_EXTRA_CFLAGS "-D_XOPEN_SOURCE=700" - #define CONFIG_HAVE_FPU 1 - #define CONFIG_FPU_MAX_RESTORES_SINCE_SWITCH 64 - #define CONFIG_HAVE_LIB_SEL4_SIMPLE 1 - #define CONFIG_HAVE_LIB_ELF 1 --#define CONFIG_SUPPORT_PCID 1 - #define CONFIG_HAVE_LIB_PLATSUPPORT 1 --#define CONFIG_NUM_DOMAINS 16 -+#define CONFIG_NUM_DOMAINS 1 - #define CONFIG_HAVE_LIB_UTILS 1 - #define CONFIG_USER_OPTIMISATION_O2 1 - #define CONFIG_LIB_CPIO 1 - #define CONFIG_RETYPE_FAN_OUT_LIMIT 256 --#define CONFIG_ROOT_CNODE_SIZE_BITS 16 -+#define CONFIG_ROOT_CNODE_SIZE_BITS 18 - #define CONFIG_NUM_PRIORITIES 256 - #define CONFIG_TESTPRINTER_REGEX ".*" - #define CONFIG_APP_SEL4TEST 1 -@@ -189,9 +187,16 @@ - #define CONFIG_LIBSEL4DEBUG_ALLOC_BUFFER_ENTRIES 128 - #define CONFIG_CACHE_LN_SZ 64 - #define CONFIG_ARCH_X86_64 1 --#define CONFIG_HUGE_PAGE 1 - #define CONFIG_LIB_SEL4_MUSLC_SYS_MORECORE_BYTES 1048576 - #define CONFIG_BUILDSYS_USE_CCACHE 1 --#define CONFIG_MAX_NUM_NODES 1 -+#define CONFIG_MAX_NUM_NODES 16 - #define CONFIG_KERNEL_STACK_BITS 12 -+#define CONFIG_ARCH_X86_GENERIC 1 -+#define CONFIG_MULTIBOOT1_HEADER -+#define CONFIG_MULTIBOOT2_HEADER -+#define CONFIG_PRINTING 1 -+#define CONFIG_ENABLE_BENCHMARKS 1 -+#define CONFIG_BENCHMARK_TRACK_UTILISATION 1 -+#define CONFIG_VTX 1 -+#define CONFIG_MAX_VPIDS 64 - #endif /* ARCH_IA32 */ diff --git a/repos/base-sel4/patches/cmake.patch b/repos/base-sel4/patches/cmake.patch new file mode 100644 index 0000000000..dc377d9a7e --- /dev/null +++ b/repos/base-sel4/patches/cmake.patch @@ -0,0 +1,14 @@ +Prevent truncation of stdout/stderr on open(O_TRUNC) in cmake. + +--- src/kernel/sel4/config.cmake ++++ src/kernel/sel4/config.cmake +@@ -168,9 +168,6 @@ if(DEFINED KernelDTSList AND (NOT "${KernelDTSList}" STREQUAL "")) + "${device_dest}" --hardware-config "${config_file}" --hardware-schema + "${config_schema}" --yaml --yaml-out "${platform_yaml}" --arch "${KernelArch}" + --addrspace-max "${KernelPaddrUserTop}" +- INPUT_FILE /dev/stdin +- OUTPUT_FILE /dev/stdout +- ERROR_FILE /dev/stderr + RESULT_VARIABLE error + ) + if(error) diff --git a/repos/base-sel4/patches/config.patch b/repos/base-sel4/patches/config.patch index a0dde99cba..5fd7dc7986 100644 --- a/repos/base-sel4/patches/config.patch +++ b/repos/base-sel4/patches/config.patch @@ -1,53 +1,22 @@ ---- src/kernel/sel4/Makefile -+++ src/kernel/sel4/Makefile -@@ -287,8 +287,8 @@ - # Only set CFLAGS if we're building standalone. - # common/Makefile.Flags sets NK_CFLAGS in Kbuild environments. - ifndef NK_CFLAGS --STATICHEADERS += ${SOURCE_ROOT}/configs/$(PLAT)/autoconf.h --INCLUDES += "-I${SOURCE_ROOT}/configs/$(PLAT)" -+STATICHEADERS += ${SOURCE_ROOT}/configs/$(PLAT)/$(BOARD)/autoconf.h -+INCLUDES += "-I${SOURCE_ROOT}/configs/$(PLAT)/$(BOARD)" - DEFINES += -DHAVE_AUTOCONF - ifdef DEBUG - DEFINES += -DCONFIG_DEBUG_BUILD ---- src/kernel/sel4/src/plat/pc99/linker.lds -+++ src/kernel/sel4/src/plat/pc99/linker.lds -@@ -16,13 +16,13 @@ - #if defined(CONFIG_ARCH_IA32) - #undef i386 - PADDR_BASE = 0x00000000; --PADDR_LOAD = 0x00100000; -+PADDR_LOAD = 0x00200000; - KERNEL_BASE = 0xe0000000; - OUTPUT_ARCH(i386) - OUTPUT_FORMAT(elf32-i386) - #elif defined(CONFIG_ARCH_X86_64) - PADDR_BASE = 0x00000000; --PADDR_LOAD = 0x00100000; -+PADDR_LOAD = 0x00200000; - KERNEL_BASE = 0xffffffff80000000; - OUTPUT_FORMAT(elf64-x86-64) - #endif --- src/kernel/sel4/include/plat/pc99/plat/64/plat_mode/machine/hardware.h +++ src/kernel/sel4/include/plat/pc99/plat/64/plat_mode/machine/hardware.h -@@ -19,7 +19,7 @@ - * because they need to defined like this in linker.lds - */ - #define PADDR_BASE UL_CONST(0x00000000) --#define PADDR_LOAD UL_CONST(0x00100000) -+#define PADDR_LOAD UL_CONST(0x00200000) - /* our kernel window is 2^39 bits (2^9 * 1gb) and the virtual address - * range is 48 bits. Therefore our base is 2^48 - 2^39 - */ +@@ -87,7 +87,7 @@ + #define PPTR_TOP UL_CONST(0xffffffff80000000) + + /* The physical memory address to use for mapping the kernel ELF */ +-#define KERNEL_ELF_PADDR_BASE UL_CONST(0x00100000) ++#define KERNEL_ELF_PADDR_BASE UL_CONST(0x00200000) + + /* Kernel mapping starts directly after the physical memory window */ + #define KERNEL_ELF_BASE (PPTR_TOP + KERNEL_ELF_PADDR_BASE) --- src/kernel/sel4/include/plat/pc99/plat/32/plat_mode/machine/hardware.h +++ src/kernel/sel4/include/plat/pc99/plat/32/plat_mode/machine/hardware.h -@@ -15,7 +15,7 @@ +@@ -74,7 +74,7 @@ + #define PPTR_TOP KS_LOG_PPTR - /* WARNING: some of these constants are also defined in linker.lds */ - #define PADDR_BASE 0x00000000 --#define PADDR_LOAD 0x00100000 -+#define PADDR_LOAD 0x00200000 - #define PPTR_BASE 0xe0000000 + /* The physical memory address to use for mapping the kernel ELF */ +-#define KERNEL_ELF_PADDR_BASE UL_CONST(0x00100000) ++#define KERNEL_ELF_PADDR_BASE UL_CONST(0x00200000) - #define PPTR_USER_TOP (PPTR_BASE & (~MASK(seL4_LargePageBits))) + /* The base address in virtual memory to use for the kernel ELF mapping */ + #define KERNEL_ELF_BASE (PPTR_BASE + KERNEL_ELF_PADDR_BASE) diff --git a/repos/base-sel4/patches/gcc12.patch b/repos/base-sel4/patches/gcc12.patch new file mode 100644 index 0000000000..15ab25ddd6 --- /dev/null +++ b/repos/base-sel4/patches/gcc12.patch @@ -0,0 +1,47 @@ +gcc12.patch + +--- src/kernel/sel4/src/arch/x86/kernel/cmdline.c ++++ src/kernel/sel4/src/arch/x86/kernel/cmdline.c +@@ -109,14 +109,20 @@ + /* use BIOS data area to read serial configuration. The BDA is not + * fully standardized and parts are absolete. See http://wiki.osdev.org/Memory_Map_(x86)#BIOS_Data_Area_.28BDA.29 + * for an explanation */ ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Warray-bounds" + const unsigned short *bda_port = (unsigned short *)0x400; + const unsigned short *bda_equi = (unsigned short *)0x410; + int const bda_ports_count = (*bda_equi >> 9) & 0x7; ++#pragma GCC diagnostic pop + #endif + + #ifdef CONFIG_PRINTING + /* initialise to default or use BDA if available */ ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Warray-bounds" + cmdline_opt->console_port = bda_ports_count && *bda_port ? *bda_port : 0x3f8; ++#pragma GCC diagnostic pop + + if (parse_opt(cmdline, "console_port", cmdline_val, MAX_CMDLINE_VAL_LEN) != -1) { + parse_uint16_array(cmdline_val, &cmdline_opt->console_port, 1); +@@ -138,7 +144,10 @@ + + #ifdef CONFIG_DEBUG_BUILD + /* initialise to default or use BDA if available */ ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Warray-bounds" + cmdline_opt->debug_port = bda_ports_count && *bda_port ? *bda_port : 0x3f8; ++#pragma GCC diagnostic pop + if (parse_opt(cmdline, "debug_port", cmdline_val, MAX_CMDLINE_VAL_LEN) != -1) { + parse_uint16_array(cmdline_val, &cmdline_opt->debug_port, 1); + } +--- src/kernel/sel4/tools/circular_includes.py ++++ src/kernel/sel4/tools/circular_includes.py +@@ -28,7 +28,7 @@ + if ignore_args and len(ignore_args): + ignore_args = [re.escape(ignore) for ignore in ignore_args] + ignore_re_string = '(' + '|'.join(ignore_args) + ')' +- ignore_re = re.compile(r'^# 1 ".*' + ignore_re_string + '"') ++ ignore_re = re.compile(r'^# [01] ".*' + ignore_re_string + '"') + + header_re = re.compile(r'^# (\d+) "(.*\..)"') + diff --git a/repos/base-sel4/patches/imx6q_sabrelite.config b/repos/base-sel4/patches/imx6q_sabrelite.config deleted file mode 100644 index 3638b226ec..0000000000 --- a/repos/base-sel4/patches/imx6q_sabrelite.config +++ /dev/null @@ -1,27 +0,0 @@ ---- src/kernel/sel4/configs/imx6/imx6q_sabrelite/autoconf.h -+++ src/kernel/sel4/configs/imx6/imx6q_sabrelite/autoconf.h -@@ -41,6 +41,7 @@ - #define CONFIG_LIBSEL4DEBUG_FUNCTION_INSTRUMENTATION_NONE 1 - #define CONFIG_LIB_SEL4_UTILS 1 - #define CONFIG_LIB_SEL4_VSPACE 1 -+#define CONFIG_PRINTING 1 - #define CONFIG_LIB_PLATSUPPORT 1 - #define CONFIG_LIB_SEL4_ALLOCMAN 1 - #define CONFIG_HAVE_LIB_SEL4_SIMPLE_DEFAULT 1 -@@ -78,7 +78,7 @@ - #define CONFIG_USER_OPTIMISATION_O2 1 - #define CONFIG_LIB_CPIO 1 - #define CONFIG_RETYPE_FAN_OUT_LIMIT 256 --#define CONFIG_ROOT_CNODE_SIZE_BITS 12 -+#define CONFIG_ROOT_CNODE_SIZE_BITS 15 - #define CONFIG_NUM_PRIORITIES 256 - #define CONFIG_TESTPRINTER_REGEX ".*" - #define CONFIG_APP_SEL4TEST 1 -@@ -93,3 +93,7 @@ - #define CONFIG_BUILDSYS_USE_CCACHE 1 - #define CONFIG_MAX_NUM_NODES 1 - #define CONFIG_KERNEL_STACK_BITS 12 -+#define CONFIG_ENABLE_BENCHMARKS 1 -+#define CONFIG_BENCHMARK_TRACK_UTILISATION 1 -+#define CONFIG_HAVE_FPU 1 -+#define CONFIG_FPU_MAX_RESTORES_SINCE_SWITCH 64 diff --git a/repos/base-sel4/patches/imx7d_sabre.config b/repos/base-sel4/patches/imx7d_sabre.config deleted file mode 100644 index 55095bcb6d..0000000000 --- a/repos/base-sel4/patches/imx7d_sabre.config +++ /dev/null @@ -1,29 +0,0 @@ ---- src/kernel/sel4/configs/imx7/imx7d_sabre/autoconf.h -+++ src/kernel/sel4/configs/imx7/imx7d_sabre/autoconf.h -@@ -38,6 +38,7 @@ - #define CONFIG_LIBSEL4DEBUG_FUNCTION_INSTRUMENTATION_NONE 1 - #define CONFIG_LIB_SEL4_UTILS 1 - #define CONFIG_LIB_SEL4_VSPACE 1 -+#define CONFIG_PRINTING 1 - #define CONFIG_LIB_PLATSUPPORT 1 - #define CONFIG_LIB_SEL4_ALLOCMAN 1 - #define CONFIG_HAVE_LIB_SEL4_SIMPLE_DEFAULT 1 -@@ -75,7 +76,7 @@ - #define CONFIG_USER_OPTIMISATION_O2 1 - #define CONFIG_LIB_CPIO 1 - #define CONFIG_RETYPE_FAN_OUT_LIMIT 256 --#define CONFIG_ROOT_CNODE_SIZE_BITS 12 -+#define CONFIG_ROOT_CNODE_SIZE_BITS 15 - #define CONFIG_NUM_PRIORITIES 256 - #define CONFIG_TESTPRINTER_REGEX ".*" - #define CONFIG_APP_SEL4TEST 1 -@@ -89,3 +90,9 @@ - #define CONFIG_BUILDSYS_USE_CCACHE 1 - #define CONFIG_MAX_NUM_NODES 1 - #define CONFIG_KERNEL_STACK_BITS 12 -+#define CONFIG_ARCH_AARCH32 1 -+#define CONFIG_IPC_BUF_TPIDRURW 1 -+#define CONFIG_ENABLE_BENCHMARKS 1 -+#define CONFIG_BENCHMARK_TRACK_UTILISATION 1 -+#define CONFIG_HAVE_FPU 1 -+#define CONFIG_FPU_MAX_RESTORES_SINCE_SWITCH 64 diff --git a/repos/base-sel4/patches/intel_vmcs.patch b/repos/base-sel4/patches/intel_vmcs.patch index f0806b05a1..46250f6de3 100644 --- a/repos/base-sel4/patches/intel_vmcs.patch +++ b/repos/base-sel4/patches/intel_vmcs.patch @@ -1,15 +1,14 @@ --- src/kernel/sel4/src/arch/x86/object/vcpu.c +++ src/kernel/sel4/src/arch/x86/object/vcpu.c -@@ -760,6 +774,8 @@ decodeWriteVMCS(cap_t cap, word_t length, word_t* buffer) - case VMX_GUEST_CR3: +@@ -713,6 +727,7 @@ static exception_t decodeWriteVMCS(cap_t cap, word_t length, word_t *buffer) case VMX_CONTROL_EXCEPTION_BITMAP: case VMX_CONTROL_ENTRY_INTERRUPTION_INFO: -+ case VMX_CONTROL_ENTRY_EXCEPTION_ERROR_CODE: + case VMX_CONTROL_ENTRY_EXCEPTION_ERROR_CODE: + case VMX_CONTROL_ENTRY_INSTRUCTION_LENGTH: break; case VMX_CONTROL_PIN_EXECUTION_CONTROLS: value = applyFixedBits(value, pin_control_high, pin_control_low); -@@ -909,6 +925,7 @@ decodeReadVMCS(cap_t cap, word_t length, word_t* buffer) +@@ -860,6 +875,7 @@ static exception_t decodeReadVMCS(cap_t cap, word_t length, word_t *buffer) case VMX_GUEST_CR0: case VMX_GUEST_CR3: case VMX_GUEST_CR4: diff --git a/repos/base-sel4/patches/intel_vmx_full_state.patch b/repos/base-sel4/patches/intel_vmx_full_state.patch index 1d78c44c99..c212f58d15 100644 --- a/repos/base-sel4/patches/intel_vmx_full_state.patch +++ b/repos/base-sel4/patches/intel_vmx_full_state.patch @@ -1,26 +1,14 @@ --- src/kernel/sel4/src/arch/x86/object/vcpu.c +++ src/kernel/sel4/src/arch/x86/object/vcpu.c -@@ -88,6 +88,9 @@ static bool_t vmx_feature_ack_on_exit; - static vcpu_t *x86KSVPIDTable[VPID_LAST + 1]; - static vpid_t x86KSNextVPID = VPID_FIRST; +@@ -921,6 +921,8 @@ + vmwrite(VMX_CONTROL_ENTRY_INTERRUPTION_INFO, getSyscallArg(2, buffer)); + } -+static void -+setMRs_vmexit(uint32_t reason, word_t qualification, tcb_t *tcb); ++static void setMRs_vmexit(uint32_t reason, word_t qualification, tcb_t *tcb); + - static inline bool_t - vmxon(paddr_t vmxon_region) + void vcpu_sysvmenter_reply_to_user(tcb_t *tcb) { -@@ -967,10 +987,8 @@ vcpu_update_state_sysvmenter(vcpu_t *vcpu) - void - vcpu_sysvmenter_reply_to_user(tcb_t *tcb) - { -- word_t *buffer; vcpu_t *vcpu; - -- buffer = lookupIPCBuffer(true, tcb); - vcpu = tcb->tcbArch.tcbVCPU; - - assert(vcpu); @@ -979,11 +997,9 @@ vcpu_sysvmenter_reply_to_user(tcb_t *tcb) switchVCPU(vcpu); } @@ -35,12 +23,12 @@ } exception_t -@@ -1113,27 +1141,27 @@ vtx_init(void) +@@ -1065,29 +1067,29 @@ + return true; } - static void --setMRs_vmexit(uint32_t reason, word_t qualification) -+setMRs_vmexit(uint32_t reason, word_t qualification, tcb_t *tcb) +-static void setMRs_vmexit(uint32_t reason, word_t qualification) ++static void setMRs_vmexit(uint32_t reason, word_t qualification, tcb_t *tcb) { word_t *buffer; int i; @@ -49,21 +37,23 @@ + buffer = lookupIPCBuffer(true, tcb); - setMR(NODE_STATE(ksCurThread), buffer, SEL4_VMENTER_CALL_EIP_MR, vmread(VMX_GUEST_RIP)); -- setMR(NODE_STATE(ksCurThread), buffer, SEL4_VMENTER_CALL_CONTROL_PPC_MR, vmread(VMX_CONTROL_PRIMARY_PROCESSOR_CONTROLS)); +- setMR(NODE_STATE(ksCurThread), buffer, SEL4_VMENTER_CALL_CONTROL_PPC_MR, ++ setMR(tcb, buffer, SEL4_VMENTER_CALL_EIP_MR, vmread(VMX_GUEST_RIP)); ++ setMR(tcb, buffer, SEL4_VMENTER_CALL_CONTROL_PPC_MR, + vmread(VMX_CONTROL_PRIMARY_PROCESSOR_CONTROLS)); - setMR(NODE_STATE(ksCurThread), buffer, SEL4_VMENTER_CALL_CONTROL_ENTRY_MR, vmread(VMX_CONTROL_ENTRY_INTERRUPTION_INFO)); - setMR(NODE_STATE(ksCurThread), buffer, SEL4_VMENTER_FAULT_REASON_MR, reason); - setMR(NODE_STATE(ksCurThread), buffer, SEL4_VMENTER_FAULT_QUALIFICATION_MR, qualification); -+ setMR(tcb, buffer, SEL4_VMENTER_CALL_EIP_MR, vmread(VMX_GUEST_RIP)); -+ setMR(tcb, buffer, SEL4_VMENTER_CALL_CONTROL_PPC_MR, vmread(VMX_CONTROL_PRIMARY_PROCESSOR_CONTROLS)); -+ setMR(tcb, buffer, SEL4_VMENTER_CALL_CONTROL_ENTRY_MR, vmread(VMX_CONTROL_ENTRY_INTERRUPTION_INFO)); -+ setMR(tcb, buffer, SEL4_VMENTER_FAULT_REASON_MR, reason); -+ setMR(tcb, buffer, SEL4_VMENTER_FAULT_QUALIFICATION_MR, qualification); - +- - setMR(NODE_STATE(ksCurThread), buffer, SEL4_VMENTER_FAULT_INSTRUCTION_LEN_MR, vmread(VMX_DATA_EXIT_INSTRUCTION_LENGTH)); - setMR(NODE_STATE(ksCurThread), buffer, SEL4_VMENTER_FAULT_GUEST_PHYSICAL_MR, vmread(VMX_DATA_GUEST_PHYSICAL)); - setMR(NODE_STATE(ksCurThread), buffer, SEL4_VMENTER_FAULT_RFLAGS_MR, vmread(VMX_GUEST_RFLAGS)); - setMR(NODE_STATE(ksCurThread), buffer, SEL4_VMENTER_FAULT_GUEST_INT_MR, vmread(VMX_GUEST_INTERRUPTABILITY)); - setMR(NODE_STATE(ksCurThread), buffer, SEL4_VMENTER_FAULT_CR3_MR, vmread(VMX_GUEST_CR3)); ++ setMR(tcb, buffer, SEL4_VMENTER_CALL_CONTROL_ENTRY_MR, vmread(VMX_CONTROL_ENTRY_INTERRUPTION_INFO)); ++ setMR(tcb, buffer, SEL4_VMENTER_FAULT_REASON_MR, reason); ++ setMR(tcb, buffer, SEL4_VMENTER_FAULT_QUALIFICATION_MR, qualification); ++ + setMR(tcb, buffer, SEL4_VMENTER_FAULT_INSTRUCTION_LEN_MR, vmread(VMX_DATA_EXIT_INSTRUCTION_LENGTH)); + setMR(tcb, buffer, SEL4_VMENTER_FAULT_GUEST_PHYSICAL_MR, vmread(VMX_DATA_GUEST_PHYSICAL)); + setMR(tcb, buffer, SEL4_VMENTER_FAULT_RFLAGS_MR, vmread(VMX_GUEST_RFLAGS)); @@ -71,8 +61,10 @@ + setMR(tcb, buffer, SEL4_VMENTER_FAULT_CR3_MR, vmread(VMX_GUEST_CR3)); for (i = 0; i < n_vcpu_gp_register; i++) { -- setMR(NODE_STATE(ksCurThread), buffer, SEL4_VMENTER_FAULT_EAX + i, NODE_STATE(ksCurThread)->tcbArch.tcbVCPU->gp_registers[i]); -+ setMR(tcb, buffer, SEL4_VMENTER_FAULT_EAX + i, tcb->tcbArch.tcbVCPU->gp_registers[i]); +- setMR(NODE_STATE(ksCurThread), buffer, SEL4_VMENTER_FAULT_EAX + i, +- NODE_STATE(ksCurThread)->tcbArch.tcbVCPU->gp_registers[i]); ++ setMR(tcb, buffer, SEL4_VMENTER_FAULT_EAX + i, ++ tcb->tcbArch.tcbVCPU->gp_registers[i]); } } diff --git a/repos/base-sel4/patches/intel_vtx_check.patch b/repos/base-sel4/patches/intel_vtx_check.patch index 3ad6455a28..690f953f4e 100644 --- a/repos/base-sel4/patches/intel_vtx_check.patch +++ b/repos/base-sel4/patches/intel_vtx_check.patch @@ -36,15 +36,14 @@ case seL4_X86_EPTPML4Object: --- src/kernel/sel4/src/arch/x86/object/vcpu.c +++ src/kernel/sel4/src/arch/x86/object/vcpu.c -@@ -409,9 +416,14 @@ applyFixedBits(uint32_t original, uint32_t high, uint32_t low) +@@ -401,8 +401,13 @@ return original; } --void +-void vcpu_init(vcpu_t *vcpu) +static bool_t vcpu_support_available = false; + -+bool_t - vcpu_init(vcpu_t *vcpu) ++bool_t vcpu_init(vcpu_t *vcpu) { + if (!vcpu_support_available) + return false; @@ -61,6 +60,14 @@ } static void +@@ -937,6 +937,7 @@ + + buffer = lookupIPCBuffer(true, tcb); + vcpu = tcb->tcbArch.tcbVCPU; ++ (void)buffer; + + assert(vcpu); + @@ -1067,6 +1081,12 @@ vtx_init(void) printf("vt-x: lack of required features\n"); return false; diff --git a/repos/base-sel4/patches/noise.patch b/repos/base-sel4/patches/noise.patch index 6ee65e7b6a..cdbb1f4d6b 100644 --- a/repos/base-sel4/patches/noise.patch +++ b/repos/base-sel4/patches/noise.patch @@ -9,101 +9,3 @@ return; default: ---- src/kernel/sel4/libsel4/include/sel4/shared_types.h -+++ src/kernel/sel4/libsel4/include/sel4/shared_types.h -@@ -33,7 +33,7 @@ - seL4_CapFault_GuardMismatch_GuardFound = seL4_CapFault_DepthMismatch_BitsFound, - seL4_CapFault_GuardMismatch_BitsFound, - SEL4_FORCE_LONG_ENUM(seL4_CapFault_Msg), --} seL4_CapFault_Msg; -+}; // seL4_CapFault_Msg; - - #define seL4_ReadWrite seL4_CapRights_new(0, 1, 1) - #define seL4_AllRights seL4_CapRights_new(1, 1, 1) ---- src/kernel/sel4/libsel4/sel4_arch_include/ia32/sel4/sel4_arch/constants.h -+++ src/kernel/sel4/libsel4/sel4_arch_include/ia32/sel4/sel4_arch/constants.h -@@ -83,7 +83,7 @@ - seL4_VMFault_FSR, - seL4_VMFault_Length, - SEL4_FORCE_LONG_ENUM(seL4_VMFault_Msg), --} seL4_VMFault_Msg; -+}; // seL4_VMFault_Msg; - - enum { - seL4_UnknownSyscall_EAX, -@@ -99,7 +99,7 @@ - seL4_UnknownSyscall_Syscall, - seL4_UnknownSyscall_Length, - SEL4_FORCE_LONG_ENUM(seL4_UnknownSyscall_Msg), --} seL4_UnknownSyscall_Msg; -+}; // seL4_UnknownSyscall_Msg; - - enum { - seL4_UserException_FaultIP, -@@ -109,7 +109,7 @@ - seL4_UserException_Code, - seL4_UserException_Length, - SEL4_FORCE_LONG_ENUM(seL4_UserException_Msg) --} seL4_UserException_Msg; -+}; // seL4_UserException_Msg; - - #endif /* __ASSEMBLER__ */ - #define seL4_FastMessageRegisters 2 ---- src/kernel/sel4/libsel4/sel4_arch_include/x86_64/sel4/sel4_arch/constants.h -+++ src/kernel/sel4/libsel4/sel4_arch_include/x86_64/sel4/sel4_arch/constants.h -@@ -74,7 +74,7 @@ - seL4_VMFault_FSR, - seL4_VMFault_Length, - SEL4_FORCE_LONG_ENUM(seL4_VMFault_Msg), --} seL4_VMFault_Msg; -+}; // seL4_VMFault_Msg; - - enum { - seL4_UnknownSyscall_RAX, -@@ -98,7 +98,7 @@ - seL4_UnknownSyscall_Syscall, - seL4_UnknownSyscall_Length, - SEL4_FORCE_LONG_ENUM(seL4_UnknownSyscall_Msg) --} seL4_UnknownSyscall_Msg; -+}; // seL4_UnknownSyscall_Msg; - - enum { - seL4_UserException_FaultIP, -@@ -108,7 +108,7 @@ - seL4_UserException_Code, - seL4_UserException_Length, - SEL4_FORCE_LONG_ENUM(seL4_UserException_Msg) --} seL4_UserException_Msg; -+}; // seL4_UserException_Msg; - - #endif /* __ASSEMBLER__ */ - #define seL4_FastMessageRegisters 4 ---- src/kernel/sel4/libsel4/sel4_arch_include/aarch32/sel4/sel4_arch/constants.h -+++ src/kernel/sel4/libsel4/sel4_arch_include/aarch32/sel4/sel4_arch/constants.h -@@ -40,7 +40,7 @@ - /* length of an unknown syscall message */ - seL4_UnknownSyscall_Length, - SEL4_FORCE_LONG_ENUM(seL4_UnknownSyscall_Msg), --} seL4_UnknownSyscall_Msg; -+}; // seL4_UnknownSyscall_Msg; - - /* format of a user exception message */ - enum { -@@ -52,7 +52,7 @@ - /* length of a user exception */ - seL4_UserException_Length, - SEL4_FORCE_LONG_ENUM(seL4_UserException_Msg), --} seL4_UserException_Msg; -+}; // seL4_UserException_Msg; - - /* format of a vm fault message */ - enum { -@@ -62,7 +62,7 @@ - seL4_VMFault_FSR, - seL4_VMFault_Length, - SEL4_FORCE_LONG_ENUM(seL4_VMFault_Msg), --} seL4_VMFault_Msg; -+}; // seL4_VMFault_Msg; - - #ifdef CONFIG_ARM_HYPERVISOR_SUPPORT - enum { diff --git a/repos/base-sel4/patches/sched_bug_x86.patch b/repos/base-sel4/patches/sched_bug_x86.patch deleted file mode 100644 index c522888862..0000000000 --- a/repos/base-sel4/patches/sched_bug_x86.patch +++ /dev/null @@ -1,27 +0,0 @@ ---- src/kernel/sel4/src/kernel/thread.c -+++ src/kernel/sel4/src/kernel/thread.c -@@ -437,8 +437,11 @@ scheduleTCB(tcb_t *tptr) - void - timerTick(void) - { -- if (likely(thread_state_get_tsType(NODE_STATE(ksCurThread)->tcbState) == -- ThreadState_Running)) { -+ switch (thread_state_get_tsType(NODE_STATE(ksCurThread)->tcbState)) { -+ case ThreadState_Running: -+#ifdef CONFIG_VTX -+ case ThreadState_RunningVM: -+#endif - if (NODE_STATE(ksCurThread)->tcbTimeSlice > 1) { - NODE_STATE(ksCurThread)->tcbTimeSlice--; - } else { -@@ -446,6 +449,10 @@ timerTick(void) - SCHED_APPEND_CURRENT_TCB; - rescheduleRequired(); - } -+ break; -+ default: -+ /* no tick updates */ -+ break; - } - - if (CONFIG_NUM_DOMAINS > 1) { diff --git a/repos/base-sel4/patches/sel4_tlb_x86_bug.patch b/repos/base-sel4/patches/sel4_tlb_x86_bug.patch deleted file mode 100644 index 8de41bf0e8..0000000000 --- a/repos/base-sel4/patches/sel4_tlb_x86_bug.patch +++ /dev/null @@ -1,25 +0,0 @@ ---- src/kernel/sel4/src/arch/x86/kernel/vspace.c -+++ src/kernel/sel4/src/arch/x86/kernel/vspace.c -@@ -711,7 +711,6 @@ void unmapPage(vm_page_size_t page_size, asid_t asid, vptr_t vptr, void *pptr) - { - findVSpaceForASID_ret_t find_ret; - lookupPTSlot_ret_t lu_ret; -- cap_t threadRoot; - lookupPDSlot_ret_t pd_ret; - pde_t *pde; - -@@ -756,12 +756,8 @@ void unmapPage(vm_page_size_t page_size, asid_t asid, vptr_t vptr, void *pptr) - break; - } - -- /* check if page belongs to current address space */ -- threadRoot = TCB_PTR_CTE_PTR(NODE_STATE(ksCurThread), tcbVTable)->cap; -- if (config_set(CONFIG_SUPPORT_PCID) || (isValidNativeRoot(threadRoot) && (vspace_root_t*)pptr_of_cap(threadRoot) == find_ret.vspace_root)) { -- invalidateTranslationSingleASID(vptr, asid, -- SMP_TERNARY(tlb_bitmap_get(find_ret.vspace_root), 0)); -- } -+ invalidateTranslationSingleASID(vptr, asid, -+ SMP_TERNARY(tlb_bitmap_get(find_ret.vspace_root), 0)); - } - - void unmapPageTable(asid_t asid, vptr_t vaddr, pte_t* pt) diff --git a/repos/base-sel4/patches/vcpu_nullptr_bug.patch b/repos/base-sel4/patches/vcpu_nullptr_bug.patch deleted file mode 100644 index b90f722b48..0000000000 --- a/repos/base-sel4/patches/vcpu_nullptr_bug.patch +++ /dev/null @@ -1,13 +0,0 @@ -Bug detected by Genode and patch provided by Anna Lyons: -http://sel4.systems/pipermail/devel/2018-September/002161.html ---- src/kernel/sel4/src/arch/x86/c_traps.c -+++ src/kernel/sel4/src/arch/x86/c_traps.c -@@ -111,7 +111,7 @@ slowpath(syscall_t syscall) - { - - #ifdef CONFIG_VTX -- if (syscall == SysVMEnter) { -+ if (syscall == SysVMEnter && NODE_STATE(ksCurThread)->tcbArch.tcbVCPU) { - vcpu_update_state_sysvmenter(NODE_STATE(ksCurThread)->tcbArch.tcbVCPU); - if (NODE_STATE(ksCurThread)->tcbBoundNotification && notification_ptr_get_state(NODE_STATE(ksCurThread)->tcbBoundNotification) == NtfnState_Active) { - completeSignal(NODE_STATE(ksCurThread)->tcbBoundNotification, NODE_STATE(ksCurThread)); diff --git a/repos/base-sel4/ports/sel4.hash b/repos/base-sel4/ports/sel4.hash index c6c5bc033c..75b061c2ed 100644 --- a/repos/base-sel4/ports/sel4.hash +++ b/repos/base-sel4/ports/sel4.hash @@ -1 +1 @@ -9ab19376285d865052c2b5021560306306bf19a8 +e6fe0a48d0479e6f7ba8243f3e1e860c7d42407a diff --git a/repos/base-sel4/ports/sel4.port b/repos/base-sel4/ports/sel4.port index 5e969b66eb..94b95b62f6 100644 --- a/repos/base-sel4/ports/sel4.port +++ b/repos/base-sel4/ports/sel4.port @@ -3,31 +3,19 @@ VERSION := git DOWNLOADS := sel4.git URL(sel4) := https://github.com/seL4/seL4.git -# master branch, version 9.0.1 -REV(sel4) := 0dd40b6c43a290173ea7782b97afbbbddfa23b36 +# master branch, version 12.1.0 +REV(sel4) := 21c1a2ca7a9786d1297e1ff0a132bc57eeb55530 DIR(sel4) := src/kernel/sel4 +$(call check_tool,cmake) +$(call check_tool,ninja) $(call check_tool,python) $(call check_python_module,future) -$(call check_python_module,tempita) +$(call check_python_module,jinja2) $(call check_python_module,ply) $(call check_python_module,six) +# required for ARM +$(call check_python_module,pyfdt) +$(call check_python_module,jsonschema) PATCHES := $(sort $(wildcard $(REP_DIR)/patches/*.patch)) - -HASH_INPUT += $(REP_DIR)/patches/imx6q_sabrelite.config -HASH_INPUT += $(REP_DIR)/patches/imx7d_sabre.config - -# adjust kernel config usable on qemu and on native hw, and add a 32bit version -default: $(DOWNLOADS) - $(VERBOSE)mkdir -p src/kernel/sel4/configs/pc99/x86_64 - $(VERBOSE)mkdir -p src/kernel/sel4/configs/pc99/ia32 - $(VERBOSE)cp src/kernel/sel4/configs/pc99/autoconf.h src/kernel/sel4/configs/pc99/x86_64/autoconf.h - $(VERBOSE)mv src/kernel/sel4/configs/pc99/autoconf.h src/kernel/sel4/configs/pc99/ia32/autoconf.h - $(VERBOSE)sed -i "s.^ \*/. \*/\n#ifndef ARCH_IA32\n#define ARCH_IA32\n#endif\n." src/kernel/sel4/configs/pc99/ia32/autoconf.h - $(VERBOSE)mkdir -p src/kernel/sel4/configs/imx6/imx6q_sabrelite - $(VERBOSE)mv src/kernel/sel4/configs/imx6/autoconf.h src/kernel/sel4/configs/imx6/imx6q_sabrelite/autoconf.h - $(VERBOSE)patch -p0 <$(REP_DIR)/patches/imx6q_sabrelite.config - $(VERBOSE)mkdir -p src/kernel/sel4/configs/imx7/imx7d_sabre - $(VERBOSE)mv src/kernel/sel4/configs/imx7/autoconf.h src/kernel/sel4/configs/imx7/imx7d_sabre/autoconf.h - $(VERBOSE)patch -p0 <$(REP_DIR)/patches/imx7d_sabre.config diff --git a/repos/base-sel4/recipes/src/base-sel4-imx6q_sabrelite/content.mk b/repos/base-sel4/recipes/src/base-sel4-imx6q_sabrelite/content.mk index 3e4a0c2acb..cf9a157eb8 100644 --- a/repos/base-sel4/recipes/src/base-sel4-imx6q_sabrelite/content.mk +++ b/repos/base-sel4/recipes/src/base-sel4-imx6q_sabrelite/content.mk @@ -35,7 +35,8 @@ etc/board.conf: content: mv lib/mk/spec/arm/ld-sel4.mk lib/mk/spec/arm/ld.mk; - sed -i "s/imx6_timer_drv/timer/" src/timer/epit/imx6/target.inc + cp -r $(GENODE_DIR)/repos/imx/src/timer/epit src/timer/epit + sed -i "s/imx6_timer/timer/" src/timer/epit/target.mk find lib/mk/spec -name kernel-sel4-*.mk -o -name syscall-sel4-*.mk |\ grep -v "sel4-imx6q_sabrelite.mk" | xargs rm -rf diff --git a/repos/base-sel4/recipes/src/base-sel4-imx6q_sabrelite/hash b/repos/base-sel4/recipes/src/base-sel4-imx6q_sabrelite/hash index 9b27295d9e..7fc8d755b8 100644 --- a/repos/base-sel4/recipes/src/base-sel4-imx6q_sabrelite/hash +++ b/repos/base-sel4/recipes/src/base-sel4-imx6q_sabrelite/hash @@ -1 +1 @@ -2022-10-11 6966c1e6595fec6e545ae729b9a5893e745a9fc9 +2024-08-28 6a6ef31c10a65d90eaba97c45324b4e6835f14db diff --git a/repos/base-sel4/recipes/src/base-sel4-imx7d_sabre/README b/repos/base-sel4/recipes/src/base-sel4-imx7d_sabre/README deleted file mode 100644 index fac8785ba6..0000000000 --- a/repos/base-sel4/recipes/src/base-sel4-imx7d_sabre/README +++ /dev/null @@ -1,7 +0,0 @@ -This archive contains the seL4-specific part of Genode. - -It also contains the source code of the seL4 kernel in the -'src/kernel/sel4' directory. - -Please note that seL4 has a license distinct from Genode. seL4's -license can be found at 'src/kernel/sel4/LICENSE_GPLv2.txt'. diff --git a/repos/base-sel4/recipes/src/base-sel4-imx7d_sabre/content.mk b/repos/base-sel4/recipes/src/base-sel4-imx7d_sabre/content.mk deleted file mode 100644 index d339aec070..0000000000 --- a/repos/base-sel4/recipes/src/base-sel4-imx7d_sabre/content.mk +++ /dev/null @@ -1,41 +0,0 @@ -include $(GENODE_DIR)/repos/base/recipes/src/base_content.inc - -content: include/os/attached_mmio.h - -include/%.h: - mkdir -p $(dir $@) - cp $(GENODE_DIR)/repos/os/$@ $@ - -content: README -README: - cp $(REP_DIR)/recipes/src/base-sel4-imx7d_sabre/README $@ - -content: lib/import etc include/sel4 -lib/import etc include/sel4: - $(mirror_from_rep_dir) - -content: src/tool/sel4_tools -src/kernel: - $(mirror_from_rep_dir) - -KERNEL_PORT_DIR := $(call port_dir,$(REP_DIR)/ports/sel4) - -src/kernel/sel4: src/kernel - cp -r $(KERNEL_PORT_DIR)/src/kernel/sel4/* $@ - -ELFLOADER_PORT_DIR := $(call port_dir,$(REP_DIR)/ports/sel4_tools) -src/tool/sel4_tools: src/kernel/sel4 - mkdir -p $@ - cp -r $(ELFLOADER_PORT_DIR)/src/tool/sel4_tools/* $@ - -content: etc/board.conf - -etc/board.conf: - echo "BOARD = imx7d_sabre" > etc/board.conf - -content: - mv lib/mk/spec/arm/ld-sel4.mk lib/mk/spec/arm/ld.mk; - sed -i "s/imx7_timer_drv/timer/" src/timer/gpt/imx7/target.inc - find lib/mk/spec -name kernel-sel4-*.mk -o -name syscall-sel4-*.mk |\ - grep -v "sel4-imx7d_sabre.mk" | xargs rm -rf - diff --git a/repos/base-sel4/recipes/src/base-sel4-imx7d_sabre/hash b/repos/base-sel4/recipes/src/base-sel4-imx7d_sabre/hash deleted file mode 100644 index bfb3e928ec..0000000000 --- a/repos/base-sel4/recipes/src/base-sel4-imx7d_sabre/hash +++ /dev/null @@ -1 +0,0 @@ -2022-10-11 e11873b5f947ab3013208e8b4ad7621113b00580 diff --git a/repos/base-sel4/recipes/src/base-sel4-x86/content.mk b/repos/base-sel4/recipes/src/base-sel4-x86/content.mk index cca289d09e..8f77228f0d 100644 --- a/repos/base-sel4/recipes/src/base-sel4-x86/content.mk +++ b/repos/base-sel4/recipes/src/base-sel4-x86/content.mk @@ -23,10 +23,8 @@ etc/board.conf: echo "BOARD = pc" > etc/board.conf content: - for spec in x86_32 x86_64 arm; do \ - mv lib/mk/spec/$$spec/ld-sel4.mk lib/mk/spec/$$spec/ld.mk; \ - done; - sed -i "s/pit_timer_drv/timer/" src/timer/pit/target.inc + mv lib/mk/spec/x86_64/ld-sel4.mk lib/mk/spec/x86_64/ld.mk; + sed -i "s/pit_timer/timer/" src/timer/pit/target.inc find lib/mk/spec -name kernel-sel4-*.mk -o -name syscall-sel4-*.mk |\ grep -v "sel4-pc.mk" | xargs rm -rf diff --git a/repos/base-sel4/recipes/src/base-sel4-x86/hash b/repos/base-sel4/recipes/src/base-sel4-x86/hash index 44aa295142..7f91bc2faf 100644 --- a/repos/base-sel4/recipes/src/base-sel4-x86/hash +++ b/repos/base-sel4/recipes/src/base-sel4-x86/hash @@ -1 +1 @@ -2022-10-11 b816b62207fc76123ce72f844fa3914163949f56 +2024-08-28 5656ef6d7282894b67b9aab50364f12f42aded49 diff --git a/repos/base-sel4/src/core/capability_space.cc b/repos/base-sel4/src/core/capability_space.cc index c30dd7359c..f13085c187 100644 --- a/repos/base-sel4/src/core/capability_space.cc +++ b/repos/base-sel4/src/core/capability_space.cc @@ -48,7 +48,7 @@ class Genode::Native_capability::Data : public Capability_data }; -using namespace Genode; +using namespace Core; /** diff --git a/repos/base-sel4/src/core/core_log_out.cc b/repos/base-sel4/src/core/core_log_out.cc index d334474115..138bc96d0e 100644 --- a/repos/base-sel4/src/core/core_log_out.cc +++ b/repos/base-sel4/src/core/core_log_out.cc @@ -15,7 +15,6 @@ #include /* seL4 includes */ -#include -#include +#include -void Genode::Core_log::out(char const c) { seL4_DebugPutChar(c); } +void Core::Core_log::out(char const c) { seL4_DebugPutChar(c); } diff --git a/repos/base-sel4/src/core/core_region_map.cc b/repos/base-sel4/src/core/core_region_map.cc index 63e923a6c0..c0c70aab2c 100644 --- a/repos/base-sel4/src/core/core_region_map.cc +++ b/repos/base-sel4/src/core/core_region_map.cc @@ -11,70 +11,56 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* Genode includes */ -#include - /* core includes */ #include #include #include -using namespace Genode; +using namespace Core; -Region_map::Local_addr -Core_region_map::attach(Dataspace_capability ds_cap, size_t size, off_t offset, - bool use_local_addr, Region_map::Local_addr, bool, bool) +Region_map::Attach_result +Core_region_map::attach(Dataspace_capability ds_cap, Attr const &attr) { - return _ep.apply(ds_cap, [&] (Dataspace_component *ds) -> Local_addr { - + return _ep.apply(ds_cap, [&] (Dataspace_component *ds) -> Attach_result { if (!ds) - throw Invalid_dataspace(); + return Attach_error::INVALID_DATASPACE; - if (size == 0) - size = ds->size(); + size_t const size = (attr.size == 0) ? ds->size() : attr.size; + size_t const page_rounded_size = (size + get_page_size() - 1) & get_page_mask(); - size_t page_rounded_size = (size + get_page_size() - 1) & get_page_mask(); - - if (use_local_addr) { - error(__func__, ": 'use_local_addr' not supported within core"); - return nullptr; - } - - if (offset) { - error(__func__, ": 'offset' not supported within core"); - return nullptr; - } + /* attach attributes 'use_at' and 'offset' not supported within core */ + if (attr.use_at || attr.offset) + return Attach_error::REGION_CONFLICT; /* allocate range in core's virtual address space */ - return platform().region_alloc().try_alloc(page_rounded_size).convert( + return platform().region_alloc().try_alloc(page_rounded_size).convert( [&] (void *virt_ptr) { /* map the dataspace's physical pages to core-local virtual addresses */ size_t num_pages = page_rounded_size >> get_page_size_log2(); map_local(ds->phys_addr(), (addr_t)virt_ptr, num_pages); - return virt_ptr; + return Range { .start = addr_t(virt_ptr), .num_bytes = page_rounded_size }; }, - [&] (Range_allocator::Alloc_error) -> Local_addr { + [&] (Range_allocator::Alloc_error) -> Attach_result { error("could not allocate virtual address range in core of size ", page_rounded_size); - return nullptr; + return Attach_error::REGION_CONFLICT; } ); }); } -void Core_region_map::detach(Local_addr core_local_addr) +void Core_region_map::detach(addr_t const at) { - size_t size = platform_specific().region_alloc_size_at(core_local_addr); + size_t const size = platform_specific().region_alloc_size_at((void *)at); - if (!unmap_local(core_local_addr, size >> get_page_size_log2())) { - Genode::error("could not unmap core virtual address ", - Hex(core_local_addr), " in ", __PRETTY_FUNCTION__); + if (!unmap_local(at, size >> get_page_size_log2())) { + error("could not unmap core virtual address ", Hex(at), " in ", __PRETTY_FUNCTION__); return; } - platform().region_alloc().free(core_local_addr); + platform().region_alloc().free((void *)at); } diff --git a/repos/base-sel4/src/core/include/cap_sel_alloc.h b/repos/base-sel4/src/core/include/cap_sel_alloc.h index baaf531b10..37787a1eba 100644 --- a/repos/base-sel4/src/core/include/cap_sel_alloc.h +++ b/repos/base-sel4/src/core/include/cap_sel_alloc.h @@ -20,10 +20,13 @@ /* base-internal includes */ #include -namespace Genode { struct Cap_sel_alloc; } +/* core includes */ +#include + +namespace Core { struct Cap_sel_alloc; } -struct Genode::Cap_sel_alloc : Interface +struct Core::Cap_sel_alloc : Interface { struct Alloc_failed : Exception { }; diff --git a/repos/base-sel4/src/core/include/cnode.h b/repos/base-sel4/src/core/include/cnode.h index e905ed4f1b..70d97c7a26 100644 --- a/repos/base-sel4/src/core/include/cnode.h +++ b/repos/base-sel4/src/core/include/cnode.h @@ -15,21 +15,20 @@ #define _CORE__INCLUDE__CNODE_H_ /* Genode includes */ -#include #include #include /* core includes */ #include -namespace Genode { +namespace Core { class Cnode_base; class Cnode; } -class Genode::Cnode_base +class Core::Cnode_base { private: @@ -38,7 +37,7 @@ class Genode::Cnode_base public: - typedef Cnode_index Index; + using Index = Cnode_index; Cap_sel sel() const { return _sel; } uint8_t size_log2() const { return _size_log2; } @@ -127,7 +126,7 @@ class Genode::Cnode_base }; -class Genode::Cnode : public Cnode_base, Noncopyable +class Core::Cnode : public Cnode_base, Noncopyable { private: diff --git a/repos/base-sel4/src/core/include/core_capability_data.h b/repos/base-sel4/src/core/include/core_capability_data.h index 50262492f3..dc15ad05de 100644 --- a/repos/base-sel4/src/core/include/core_capability_data.h +++ b/repos/base-sel4/src/core/include/core_capability_data.h @@ -17,14 +17,17 @@ /* base-internal includes */ #include -namespace Genode { +/* core includes */ +#include + +namespace Core { class Cap_session; class Core_capability_data; } -class Genode::Core_capability_data : public Capability_data +class Core::Core_capability_data : public Capability_data { private: diff --git a/repos/base-sel4/src/core/include/core_cspace.h b/repos/base-sel4/src/core/include/core_cspace.h index 509b06eea0..0e6802e0ee 100644 --- a/repos/base-sel4/src/core/include/core_cspace.h +++ b/repos/base-sel4/src/core/include/core_cspace.h @@ -16,10 +16,10 @@ #include -namespace Genode { class Core_cspace; } +namespace Core { class Core_cspace; } -class Genode::Core_cspace +class Core::Core_cspace { public: @@ -35,12 +35,13 @@ class Genode::Core_cspace /* selectors for initially created CNodes during core bootup */ static unsigned top_cnode_sel() { return (unsigned)sel4_boot_info().empty.start; } - static unsigned core_pad_cnode_sel() { return top_cnode_sel() + 1; } + static unsigned core_pad_cnode_sel() { return top_cnode_sel() + 1; } static unsigned core_cnode_sel() { return core_pad_cnode_sel() + 1; } - static unsigned phys_cnode_sel() { return core_cnode_sel() + 1; } - static unsigned untyped_cnode_4k() { return phys_cnode_sel() + 1; } - static unsigned untyped_cnode_16k() { return untyped_cnode_4k() + 1; } - static unsigned core_static_sel_end() { return untyped_cnode_16k() + 1; } + static unsigned phys_cnode_sel() { return core_cnode_sel() + 1; } + static unsigned untyped_cnode_4k() { return phys_cnode_sel() + 1; } + static unsigned untyped_cnode_16k() { return untyped_cnode_4k() + 1; } + static unsigned io_port_sel() { return untyped_cnode_16k() + 1; } + static unsigned core_static_sel_end() { return io_port_sel() + 1; } /* indices within top-level CNode */ enum Top_cnode_idx { diff --git a/repos/base-sel4/src/core/include/initial_untyped_pool.h b/repos/base-sel4/src/core/include/initial_untyped_pool.h index 024dfab5ce..89093c486b 100644 --- a/repos/base-sel4/src/core/include/initial_untyped_pool.h +++ b/repos/base-sel4/src/core/include/initial_untyped_pool.h @@ -16,18 +16,18 @@ /* Genode includes */ #include -#include -/* core-local includes */ +/* core includes */ +#include #include /* seL4 includes */ #include -namespace Genode { class Initial_untyped_pool; } +namespace Core { class Initial_untyped_pool; } -class Genode::Initial_untyped_pool +class Core::Initial_untyped_pool { private: @@ -72,7 +72,7 @@ class Genode::Initial_untyped_pool /** * Calculate free index after allocation */ - addr_t _align_offset(Range &range, unsigned size_log2) + addr_t _align_offset(Range const &range, unsigned size_log2) { /* * The seL4 kernel naturally aligns allocations within untuped @@ -90,13 +90,12 @@ class Genode::Initial_untyped_pool * * The functor is called with 'Range &' as argument. */ - template - void for_each_range(FUNC const &func) + void for_each_range(auto const &fn) { seL4_BootInfo const &bi = sel4_boot_info(); for (addr_t sel = bi.untyped.start; sel < bi.untyped.end; sel++) { Range range(*this, (unsigned)sel); - func(range); + fn(range); } } @@ -124,7 +123,7 @@ class Genode::Initial_untyped_pool * Go through the known initial untyped memory ranges to find * a range that is able to host a kernel object of 'size'. */ - for_each_range([&] (Range &range) { + for_each_range([&] (Range const &range) { /* ignore device memory */ if (range.device) return; @@ -176,13 +175,12 @@ class Genode::Initial_untyped_pool * Convert (remainder) of the initial untyped memory into untyped * objects of size_log2 and up to a maximum as specified by max_memory */ - template void turn_into_untyped_object(addr_t const node_index, - FUNC const & func, - uint8_t const size_log2 = get_page_size_log2(), + auto const &fn, + size_t const size_log2 = get_page_size_log2(), addr_t max_memory = 0UL - 0x1000UL) { - for_each_range([&] (Range &range) { + for_each_range([&] (Range const &range) { /* * The kernel limits the maximum number of kernel objects to @@ -193,7 +191,7 @@ class Genode::Initial_untyped_pool for (;;) { addr_t const page_aligned_free_offset = - align_addr(range.free_offset, size_log2); + align_addr(range.free_offset, (int)size_log2); /* back out if no further page can be allocated */ if (page_aligned_free_offset + (1UL << size_log2) > range.size) @@ -206,9 +204,6 @@ class Genode::Initial_untyped_pool size_t const retype_size_limit = get_page_size()*256; size_t const batch_size = min(min(remaining_size, retype_size_limit), max_memory); - /* mark consumed untyped memory range as allocated */ - range.free_offset += batch_size; - addr_t const phys_addr = range.phys + page_aligned_free_offset; size_t const num_pages = batch_size / (1UL << size_log2); @@ -228,6 +223,13 @@ class Genode::Initial_untyped_pool return; } + /* invoke callback about the range */ + bool const used = fn(phys_addr, num_pages << size_log2, + range.device); + + if (!used) + return; + long const ret = seL4_Untyped_Retype(service, type, size_bits, @@ -243,17 +245,11 @@ class Genode::Initial_untyped_pool return; } + /* mark consumed untyped memory range as allocated */ + range.free_offset += batch_size; + /* track memory left to be converted */ max_memory -= batch_size; - - /* convert device memory directly into page frames */ - if (range.device) { - size_t const num_pages = batch_size >> get_page_size_log2(); - Untyped_memory::convert_to_page_frames(phys_addr, num_pages); - } - - /* invoke callback about the range */ - func(phys_addr, num_pages << size_log2, range.device); } }); } diff --git a/repos/base-sel4/src/core/include/install_mapping.h b/repos/base-sel4/src/core/include/install_mapping.h index 8fb62c33a7..362e9f6117 100644 --- a/repos/base-sel4/src/core/include/install_mapping.h +++ b/repos/base-sel4/src/core/include/install_mapping.h @@ -14,13 +14,13 @@ #ifndef _CORE__INCLUDE__INSTALL_MAPPING_H_ #define _CORE__INCLUDE__INSTALL_MAPPING_H_ -/* Core includes */ +/* core includes */ #include #include -namespace Genode { +namespace Core { - bool install_mapping(Mapping const &mapping, unsigned long pager_object_badge); + bool install_mapping(Mapping const &, unsigned long pager_object_badge); } #endif /* _CORE__INCLUDE__INSTALL_MAPPING_H_ */ diff --git a/repos/base-sel4/src/core/include/ipc_pager.h b/repos/base-sel4/src/core/include/ipc_pager.h index 0f3838a974..1b7b874436 100644 --- a/repos/base-sel4/src/core/include/ipc_pager.h +++ b/repos/base-sel4/src/core/include/ipc_pager.h @@ -17,13 +17,13 @@ /* Genode includes */ #include -/* core-local includes */ +/* core includes */ #include -namespace Genode { class Ipc_pager; } +namespace Core { class Ipc_pager; } -class Genode::Ipc_pager : public Native_capability +class Core::Ipc_pager : public Native_capability { private: @@ -31,10 +31,10 @@ class Genode::Ipc_pager : public Native_capability addr_t _reply_sel = 0; /* selector to save reply cap */ addr_t _pf_addr = 0; /* page-fault address */ addr_t _pf_ip = 0; /* instruction pointer of faulter */ - addr_t _fault_type = 0; /* type of fault */ - bool _pf_write = false; /* true on write fault */ - bool _pf_exec = false; /* true on exec fault */ - bool _pf_align = false; /* true on unaligned fault */ + bool _exception = false; /* true on non page fault */ + bool _pf_write = false; /* true on write fault */ + bool _pf_exec = false; /* true on exec fault */ + bool _pf_align = false; /* true on unaligned fault */ Mapping _reply_mapping { }; @@ -99,6 +99,11 @@ class Genode::Ipc_pager : public Native_capability * Install memory mapping after pager code executed. */ bool install_mapping(); + + /** + * Return true if last fault was an exception + */ + bool exception() const { return _exception; } }; #endif /* _CORE__INCLUDE__IPC_PAGER_H_ */ diff --git a/repos/base-sel4/src/core/include/irq_object.h b/repos/base-sel4/src/core/include/irq_object.h index c5ca670c2d..e5fa51aad7 100644 --- a/repos/base-sel4/src/core/include/irq_object.h +++ b/repos/base-sel4/src/core/include/irq_object.h @@ -14,13 +14,20 @@ #ifndef _CORE__INCLUDE__IRQ_OBJECT_H_ #define _CORE__INCLUDE__IRQ_OBJECT_H_ +/* Genode includes */ #include -#include #include -namespace Genode { class Irq_object; } +/* base internal includes */ +#include -class Genode::Irq_object : public Thread { +/* core includes */ +#include + +namespace Core { class Irq_object; } + + +class Core::Irq_object : public Thread { private: @@ -42,10 +49,10 @@ class Genode::Irq_object : public Thread { Irq_object(unsigned irq); void sigh(Signal_context_capability cap) { _sig_cap = cap; } - void notify() { Genode::Signal_transmitter(_sig_cap).submit(1); } + void notify() { Signal_transmitter(_sig_cap).submit(1); } void ack_irq(); - void start() override; + Start_result start() override; bool associate(Irq_session::Trigger const, Irq_session::Polarity const); }; diff --git a/repos/base-sel4/src/core/include/kernel_object.h b/repos/base-sel4/src/core/include/kernel_object.h index 7b9fc31336..d32dc9b112 100644 --- a/repos/base-sel4/src/core/include/kernel_object.h +++ b/repos/base-sel4/src/core/include/kernel_object.h @@ -21,7 +21,7 @@ #include #include -namespace Genode { +namespace Core { /** * Index referring to a slot in a CNode diff --git a/repos/base-sel4/src/core/include/map_local.h b/repos/base-sel4/src/core/include/map_local.h index bc56afba76..18a86b52ae 100644 --- a/repos/base-sel4/src/core/include/map_local.h +++ b/repos/base-sel4/src/core/include/map_local.h @@ -18,8 +18,7 @@ #include #include - -namespace Genode { +namespace Core { /** * Map physical pages to core-local virtual address range diff --git a/repos/base-sel4/src/core/include/page_table_registry.h b/repos/base-sel4/src/core/include/page_table_registry.h index c6f5b6c3c0..134771b729 100644 --- a/repos/base-sel4/src/core/include/page_table_registry.h +++ b/repos/base-sel4/src/core/include/page_table_registry.h @@ -16,18 +16,18 @@ /* Genode includes */ #include -#include -#include #include +#include #include /* core includes */ #include #include -namespace Genode { class Page_table_registry; } +namespace Core { class Page_table_registry; } -class Genode::Page_table_registry + +class Core::Page_table_registry { public: @@ -179,15 +179,15 @@ class Genode::Page_table_registry level_log2_size)); break; } - } catch (Genode::Allocator::Out_of_memory) { + } catch (Allocator::Out_of_memory) { throw Mapping_cache_full(Mapping_cache_full::Type::MEMORY); - } catch (Genode::Out_of_caps) { + } catch (Out_of_caps) { throw Mapping_cache_full(Mapping_cache_full::Type::CAPS); } } - template - void _flush_high(FN const &fn, Avl_tree &tree, Allocator &alloc) + template + void _flush_high(auto const &fn, Avl_tree &tree, Allocator &alloc) { for (T *element; (element = tree.first());) { @@ -248,8 +248,7 @@ class Genode::Page_table_registry * The functor is called with the selector of the page table entry * (the copy of the phys frame selector) as argument. */ - template - void flush_page(addr_t vaddr, FN const &fn) + void flush_page(addr_t vaddr, auto const &fn) { Frame * frame = Frame::lookup(_frames, vaddr, LEVEL_0); if (!frame) @@ -260,8 +259,7 @@ class Genode::Page_table_registry destroy(_alloc_frames, frame); } - template - void flush_pages(FN const &fn) + void flush_pages(auto const &fn) { Avl_tree tmp; @@ -282,8 +280,7 @@ class Genode::Page_table_registry } } - template - void flush_all(PG const &pages, LV const &level) + void flush_all(auto const &pages, auto const &level) { flush_pages(pages); _flush_high(level, _level1, _alloc_high); diff --git a/repos/base-sel4/src/core/include/pager.h b/repos/base-sel4/src/core/include/pager.h index c26f8960e9..3c90bc8f19 100644 --- a/repos/base-sel4/src/core/include/pager.h +++ b/repos/base-sel4/src/core/include/pager.h @@ -23,11 +23,11 @@ #include #include -/* core-local includes */ +/* core includes */ #include #include -namespace Genode { +namespace Core { /** * Special server object for paging @@ -43,11 +43,13 @@ namespace Genode { */ class Pager_entrypoint; + using Pager_capability = Capability; + enum { PAGER_EP_STACK_SIZE = sizeof(addr_t) * 2048 }; } -class Genode::Pager_object : public Object_pool::Entry +class Core::Pager_object : public Object_pool::Entry { protected: @@ -58,7 +60,7 @@ class Genode::Pager_object : public Object_pool::Entry Cpu_session_capability _cpu_session_cap; Thread_capability _thread_cap; - Genode::Cap_sel _reply_cap; + Cap_sel _reply_cap; /** * User-level signal handler registered for this pager object via @@ -92,6 +94,8 @@ class Genode::Pager_object : public Object_pool::Entry unsigned long reply_cap_sel() const { return _reply_cap.value(); } + enum class Pager_result { STOP, CONTINUE }; + /** * Interface to be implemented by a derived class * @@ -99,7 +103,7 @@ class Genode::Pager_object : public Object_pool::Entry * * Returns !0 on error and pagefault will not be answered. */ - virtual int pager(Ipc_pager &ps) = 0; + virtual Pager_result pager(Ipc_pager &ps) = 0; /** * Wake up the faulter @@ -155,8 +159,7 @@ class Genode::Pager_object : public Object_pool::Entry }; -class Genode::Pager_entrypoint : public Object_pool, - public Thread +class Core::Pager_entrypoint : public Object_pool, public Thread { private: diff --git a/repos/base-sel4/src/core/include/platform.h b/repos/base-sel4/src/core/include/platform.h index 6822fe1fca..e91cf3f438 100644 --- a/repos/base-sel4/src/core/include/platform.h +++ b/repos/base-sel4/src/core/include/platform.h @@ -22,7 +22,8 @@ #include #include -namespace Genode { +namespace Core { + class Platform; template class Static_allocator; class Address_space; @@ -37,7 +38,7 @@ namespace Genode { * The size of a single ELEM must be a multiple of sizeof(long). */ template -class Genode::Static_allocator : public Allocator +class Core::Static_allocator : public Allocator { private: @@ -76,7 +77,8 @@ class Genode::Static_allocator : public Allocator bool need_size_for_free() const override { return false; } }; -class Genode::Platform : public Platform_generic + +class Core::Platform : public Platform_generic { private: @@ -156,7 +158,7 @@ class Genode::Platform : public Platform_generic * XXX Consider making Bit_allocator::_reserve public so that we can * turn the bit allocator into a private member of 'Core_sel_alloc'. */ - typedef Bit_allocator<1 << Core_cspace::NUM_CORE_SEL_LOG2> Core_sel_bit_alloc; + using Core_sel_bit_alloc = Bit_allocator<1 << Core_cspace::NUM_CORE_SEL_LOG2>; struct Core_sel_alloc : Cap_sel_alloc, private Core_sel_bit_alloc { @@ -223,6 +225,11 @@ class Genode::Platform : public Platform_generic */ long _unmap_page_frame(Cap_sel const &); + /** + * Initialize I/O ports on x86 + */ + void _init_io_ports(); + public: /** diff --git a/repos/base-sel4/src/core/include/platform_pd.h b/repos/base-sel4/src/core/include/platform_pd.h index 2eb1053602..338652b257 100644 --- a/repos/base-sel4/src/core/include/platform_pd.h +++ b/repos/base-sel4/src/core/include/platform_pd.h @@ -25,11 +25,21 @@ /* base-internal includes */ #include -namespace Genode { class Platform_pd; } +namespace Core { class Platform_pd; } -class Genode::Platform_pd : public Address_space +class Core::Platform_pd : public Address_space { + public: + + /* + * Allocator for core-managed selectors within the PD's CSpace + */ + struct Sel_alloc : Bit_allocator<1 << NUM_CORE_MANAGED_SEL_LOG2> + { + Sel_alloc() { _reserve(0, INITIAL_SEL_END); } + }; + private: unsigned const _id; /* used as index in top-level CNode */ @@ -47,22 +57,9 @@ class Genode::Platform_pd : public Address_space Native_capability _parent { }; - /* - * Allocator for core-managed selectors within the PD's CSpace - */ - typedef Bit_allocator<1 << NUM_CORE_MANAGED_SEL_LOG2> Sel_bit_alloc; - - struct Sel_alloc : Sel_bit_alloc - { - Sel_alloc() { _reserve(0, INITIAL_SEL_END); } - }; - Sel_alloc _sel_alloc { }; Mutex _sel_alloc_mutex { }; - Cap_sel alloc_sel(); - void free_sel(Cap_sel sel); - addr_t _init_page_directory() const; void _deinit_page_directory(addr_t) const; @@ -79,16 +76,24 @@ class Genode::Platform_pd : public Address_space ~Platform_pd(); /** - * Bind thread to protection domain + * Allocate capability selector */ - bool bind_thread(Platform_thread &); + Cap_sel alloc_sel(); /** - * Unbind thread from protection domain - * - * Free the thread's slot and update thread object. + * Release capability selector */ - void unbind_thread(Platform_thread &); + void free_sel(Cap_sel); + + /** + * Map physical IPC buffer to virtual UTCB address + */ + void map_ipc_buffer(Ipc_buffer_phys, Utcb_virt); + + /** + * Unmap IPC buffer from PD, at 'Platform_thread' destruction time + */ + void unmap_ipc_buffer(Utcb_virt); /** * Assign parent interface to protection domain diff --git a/repos/base-sel4/src/core/include/platform_thread.h b/repos/base-sel4/src/core/include/platform_thread.h index 28bbc797f3..447ac953a2 100644 --- a/repos/base-sel4/src/core/include/platform_thread.h +++ b/repos/base-sel4/src/core/include/platform_thread.h @@ -26,14 +26,14 @@ #include #include -namespace Genode { +namespace Core { class Platform_pd; class Platform_thread; } -class Genode::Platform_thread : public List::Element +class Core::Platform_thread : public List::Element { private: @@ -50,10 +50,10 @@ class Genode::Platform_thread : public List::Element /** * Virtual address of the IPC buffer within the PDs address space * - * The value is 0 for the PD's main thread. For all other threads, - * the value is somewhere within the stack area. + * The value for the PD's main thread is INITIAL_IPC_BUFFER_VIRT. + * For all other threads, the value is somewhere within the stack area. */ - addr_t const _utcb; + Utcb_virt const _utcb; Thread_info _info { }; @@ -72,19 +72,23 @@ class Genode::Platform_thread : public List::Element friend class Platform_pd; - Platform_pd *_pd = nullptr; + Platform_pd &_pd; enum { INITIAL_IPC_BUFFER_VIRT = 0x1000 }; Affinity::Location _location; uint16_t _priority; + bool _bound_to_pd = false; + + bool main_thread() const { return _utcb.addr == INITIAL_IPC_BUFFER_VIRT; } + public: /** * Constructor */ - Platform_thread(size_t, const char *name, unsigned priority, + Platform_thread(Platform_pd &pd, size_t, const char *name, unsigned priority, Affinity::Location, addr_t utcb); /** @@ -92,17 +96,19 @@ class Genode::Platform_thread : public List::Element */ ~Platform_thread(); + /** + * Return true if thread creation succeeded + */ + bool valid() const { return _bound_to_pd; } + /** * Start thread * * \param ip instruction pointer to start at * \param sp stack pointer to use * \param cpu_no target cpu - * - * \retval 0 successful - * \retval -1 thread could not be started */ - int start(void *ip, void *sp, unsigned int cpu_no = 0); + void start(void *ip, void *sp, unsigned int cpu_no = 0); /** * Pause this thread @@ -121,15 +127,11 @@ class Genode::Platform_thread : public List::Element /** * Override thread state with 's' - * - * \throw Cpu_session::State_access_failed */ void state(Thread_state s); /** * Read thread state - * - * \throw Cpu_session::State_access_failed */ Thread_state state(); diff --git a/repos/base-sel4/src/core/include/rpc_cap_factory.h b/repos/base-sel4/src/core/include/rpc_cap_factory.h index fa0b91035d..be357df6b5 100644 --- a/repos/base-sel4/src/core/include/rpc_cap_factory.h +++ b/repos/base-sel4/src/core/include/rpc_cap_factory.h @@ -14,12 +14,17 @@ #ifndef _CORE__INCLUDE__RPC_CAP_FACTORY_H_ #define _CORE__INCLUDE__RPC_CAP_FACTORY_H_ +/* Genode includes */ #include #include -namespace Genode { class Rpc_cap_factory; } +/* core includes */ +#include -class Genode::Rpc_cap_factory +namespace Core { class Rpc_cap_factory; } + + +class Core::Rpc_cap_factory { private: diff --git a/repos/base-sel4/src/core/include/sel4_boot_info.h b/repos/base-sel4/src/core/include/sel4_boot_info.h index 66cbb14c06..11c8dae114 100644 --- a/repos/base-sel4/src/core/include/sel4_boot_info.h +++ b/repos/base-sel4/src/core/include/sel4_boot_info.h @@ -15,8 +15,11 @@ #define _CORE__INCLUDE__SEL4_BOOT_INFO_H_ /* seL4 includes */ -#include +#include -namespace Genode { seL4_BootInfo const &sel4_boot_info(); } +/* core includes */ +#include + +namespace Core { seL4_BootInfo const &sel4_boot_info(); } #endif /* _CORE__INCLUDE__SEL4_BOOT_INFO_H_ */ diff --git a/repos/base-sel4/src/core/include/thread_sel4.h b/repos/base-sel4/src/core/include/thread_sel4.h index eae57818f4..1eb9bd8053 100644 --- a/repos/base-sel4/src/core/include/thread_sel4.h +++ b/repos/base-sel4/src/core/include/thread_sel4.h @@ -19,48 +19,61 @@ /* base-internal includes */ #include +#include /* core includes */ #include #include #include -namespace Genode { +namespace Genode { struct Thread_info; } - struct Thread_info - { - Cap_sel tcb_sel { 0 }; - Cap_sel ep_sel { 0 }; - Cap_sel lock_sel { 0 }; - Cap_sel vcpu_sel { 0 }; - - addr_t ipc_buffer_phys { 0 }; - addr_t vcpu_state_phys { 0 }; - - inline void write_thread_info_to_ipc_buffer(Cap_sel pd_ep_sel); - - Thread_info() { } - - inline void init_tcb(Platform &, Range_allocator &, - unsigned const prio, unsigned const cpu); - inline void init(addr_t const utcb_virt_addr, unsigned const prio); - inline void destruct(); - - bool init_vcpu(Platform &, Cap_sel ept); - }; +namespace Core { /** * Set register values for the instruction pointer and stack pointer and * start the seL4 thread */ - void start_sel4_thread(Cap_sel tcb_sel, addr_t ip, addr_t sp, unsigned cpu); + void start_sel4_thread(Cap_sel tcb_sel, addr_t ip, addr_t sp, unsigned cpu, + addr_t tls_ipcbuffer); void affinity_sel4_thread(Cap_sel const &tcb_sel, unsigned cpu); + + struct Ipc_buffer_phys { addr_t addr; }; + + using Utcb_virt = Native_utcb::Virt; +} + + +struct Genode::Thread_info +{ + Cap_sel tcb_sel { 0 }; + Cap_sel ep_sel { 0 }; + Cap_sel lock_sel { 0 }; + Cap_sel vcpu_sel { 0 }; + + Core::Ipc_buffer_phys ipc_buffer_phys { 0 }; + + addr_t vcpu_state_phys { 0 }; + + inline void write_thread_info_to_ipc_buffer(Cap_sel pd_ep_sel); + + Thread_info() { } + + inline void init_tcb(Core::Platform &, Range_allocator &, + unsigned const prio, unsigned const cpu); + inline void init(Core::Utcb_virt const utcb_virt, unsigned const prio); + inline void destruct(); + + bool init_vcpu(Core::Platform &, Cap_sel ept); }; -void Genode::Thread_info::init_tcb(Platform &platform, + +void Genode::Thread_info::init_tcb(Core::Platform &platform, Range_allocator &phys_alloc, unsigned const prio, unsigned const cpu) { + using namespace Core; + /* allocate TCB within core's CNode */ addr_t const phys_addr = Untyped_memory::alloc_page(phys_alloc); seL4_Untyped const service = Untyped_memory::untyped_sel(phys_addr).value(); @@ -76,14 +89,17 @@ void Genode::Thread_info::init_tcb(Platform &platform, affinity_sel4_thread(tcb_sel, cpu); } -void Genode::Thread_info::init(addr_t const utcb_virt_addr, unsigned const prio) + +void Genode::Thread_info::init(Core::Utcb_virt const utcb_virt, unsigned const prio) { - Platform &platform = platform_specific(); + using namespace Core; + + Core::Platform &platform = platform_specific(); Range_allocator &phys_alloc = platform.ram_alloc(); /* create IPC buffer of one page */ - ipc_buffer_phys = Untyped_memory::alloc_page(phys_alloc); - Untyped_memory::convert_to_page_frames(ipc_buffer_phys, 1); + ipc_buffer_phys = { Untyped_memory::alloc_page(phys_alloc) }; + Untyped_memory::convert_to_page_frames(ipc_buffer_phys.addr, 1); /* allocate TCB within core's CNode */ init_tcb(platform, phys_alloc, prio, 0); @@ -109,9 +125,9 @@ void Genode::Thread_info::init(addr_t const utcb_virt_addr, unsigned const prio) /* assign IPC buffer to thread */ { /* determine page frame selector of the allocated IPC buffer */ - Cap_sel ipc_buffer_sel = Untyped_memory::frame_sel(ipc_buffer_phys); + Cap_sel ipc_buffer_sel = Untyped_memory::frame_sel(ipc_buffer_phys.addr); - int const ret = seL4_TCB_SetIPCBuffer(tcb_sel.value(), utcb_virt_addr, + int const ret = seL4_TCB_SetIPCBuffer(tcb_sel.value(), utcb_virt.addr, ipc_buffer_sel.value()); ASSERT(ret == 0); } @@ -120,6 +136,8 @@ void Genode::Thread_info::init(addr_t const utcb_virt_addr, unsigned const prio) void Genode::Thread_info::destruct() { + using namespace Core; + if (lock_sel.value()) { seL4_CNode_Delete(seL4_CapInitThreadCNode, lock_sel.value(), 32); platform_specific().core_sel_alloc().free(lock_sel); @@ -138,16 +156,12 @@ void Genode::Thread_info::destruct() platform_specific().core_sel_alloc().free(vcpu_sel); } - if (ipc_buffer_phys) { - Platform &platform = platform_specific(); + if (ipc_buffer_phys.addr) { + Core::Platform &platform = platform_specific(); Range_allocator &phys_alloc = platform.ram_alloc(); - Untyped_memory::convert_to_untyped_frames(ipc_buffer_phys, 4096); - Untyped_memory::free_page(phys_alloc, ipc_buffer_phys); + Untyped_memory::convert_to_untyped_frames(ipc_buffer_phys.addr, 4096); + Untyped_memory::free_page(phys_alloc, ipc_buffer_phys.addr); } } - -void Genode::start_sel4_thread(Cap_sel tcb_sel, addr_t ip, addr_t sp, - unsigned cpu); - #endif /* _CORE__INCLUDE__THREAD_SEL4_H_ */ diff --git a/repos/base-sel4/src/core/include/untyped_memory.h b/repos/base-sel4/src/core/include/untyped_memory.h index beed7cfe5f..53c916d1b4 100644 --- a/repos/base-sel4/src/core/include/untyped_memory.h +++ b/repos/base-sel4/src/core/include/untyped_memory.h @@ -24,9 +24,10 @@ /* seL4 includes */ #include -namespace Genode { struct Untyped_memory; } +namespace Core { struct Untyped_memory; } -struct Genode::Untyped_memory + +struct Core::Untyped_memory { class Phys_alloc_failed : Exception { }; @@ -53,7 +54,7 @@ struct Genode::Untyped_memory } - static inline void free_page(Range_allocator &phys_alloc, Genode::addr_t addr) + static inline void free_page(Range_allocator &phys_alloc, addr_t addr) { phys_alloc.free(reinterpret_cast(addr)); } @@ -121,8 +122,10 @@ struct Genode::Untyped_memory num_objects); if (ret != seL4_NoError) { - error(__FUNCTION__, ": seL4_Untyped_RetypeAtOffset (IA32_4K) " - "returned ", ret); + error(__FUNCTION__, ": seL4_Untyped_RetypeAtOffset " + "returned ", ret, " - physical_range=", + Hex_range(node_offset << get_page_size_log2(), + (num_pages - i) * get_page_size())); return; } } diff --git a/repos/base-sel4/src/core/include/util.h b/repos/base-sel4/src/core/include/util.h index 725b632b41..3893046db8 100644 --- a/repos/base-sel4/src/core/include/util.h +++ b/repos/base-sel4/src/core/include/util.h @@ -20,15 +20,14 @@ /* core includes */ #include - -namespace Genode { +namespace Core { constexpr addr_t get_page_mask() { return ~(get_page_size() - 1); } inline addr_t trunc_page(addr_t addr) { return addr & get_page_mask(); } inline addr_t round_page(addr_t addr) { return trunc_page(addr + get_page_size() - 1); } inline addr_t map_src_addr(addr_t, addr_t phys) { return phys; } - inline size_t constrain_map_size_log2(size_t) { return get_page_size_log2(); } + inline Log2 kernel_constrained_map_size(Log2) { return { get_page_size_log2() }; } } #endif /* _CORE__INCLUDE__UTIL_H_ */ diff --git a/repos/base-sel4/src/core/include/vm_session_component.h b/repos/base-sel4/src/core/include/vm_session_component.h index 77a54bb14f..094da243cf 100644 --- a/repos/base-sel4/src/core/include/vm_session_component.h +++ b/repos/base-sel4/src/core/include/vm_session_component.h @@ -18,17 +18,19 @@ #include #include +/* core includes */ #include #include -namespace Genode { class Vm_session_component; } +namespace Core { class Vm_session_component; } -class Genode::Vm_session_component + +class Core::Vm_session_component : private Ram_quota_guard, private Cap_quota_guard, - public Rpc_object, - public Region_map_detach + public Rpc_object, + private Region_map_detach { private: @@ -59,7 +61,7 @@ class Genode::Vm_session_component Capability state() const { return _ds_cap; } }; - typedef Allocator_avl_tpl Avl_region; + using Avl_region = Allocator_avl_tpl; Rpc_entrypoint &_ep; Constrained_ram_allocator _constrained_md_ram_alloc; @@ -83,6 +85,7 @@ class Genode::Vm_session_component /* helpers for vm_session_common.cc */ void _attach_vm_memory(Dataspace_component &, addr_t, Attach_attr); void _detach_vm_memory(addr_t, size_t); + void _with_region(addr_t, auto const &); protected: @@ -99,13 +102,16 @@ class Genode::Vm_session_component Trace::Source_registry &); ~Vm_session_component(); + /********************************* ** Region_map_detach interface ** *********************************/ /* used on destruction of attached dataspaces */ - void detach(Region_map::Local_addr) override; /* vm_session_common.cc */ - void unmap_region(addr_t, size_t) override; /* vm_session_common.cc */ + void detach_at (addr_t) override; + void unmap_region (addr_t, size_t) override; + void reserve_and_flush (addr_t) override; + /************************** ** Vm session interface ** @@ -114,8 +120,8 @@ class Genode::Vm_session_component Capability create_vcpu(Thread_capability); void attach_pic(addr_t) override { /* unused on seL4 */ } - void attach(Dataspace_capability, addr_t, Attach_attr) override; /* vm_session_common.cc */ - void detach(addr_t, size_t) override; /* vm_session_common.cc */ + void attach(Dataspace_capability, addr_t, Attach_attr) override; + void detach(addr_t, size_t) override; }; #endif /* _CORE__VM_SESSION_COMPONENT_H_ */ diff --git a/repos/base-sel4/src/core/include/vm_space.h b/repos/base-sel4/src/core/include/vm_space.h index de3b53344d..9554943ca7 100644 --- a/repos/base-sel4/src/core/include/vm_space.h +++ b/repos/base-sel4/src/core/include/vm_space.h @@ -16,8 +16,6 @@ /* Genode includes */ #include -#include -#include #include #include @@ -29,10 +27,10 @@ #include #include -namespace Genode { class Vm_space; } +namespace Core { class Vm_space; } -class Genode::Vm_space +class Core::Vm_space { private: @@ -171,8 +169,7 @@ class Genode::Vm_space return Cap_sel((uint32_t)((_id << 20) | idx)); } - template - void _flush(bool const flush_support, FN const &fn) + void _flush(bool const flush_support, auto const &fn) { if (!flush_support) { warning("mapping cache full, but can't flush"); @@ -185,9 +182,8 @@ class Genode::Vm_space _page_table_registry.flush_pages(fn); } - template bool _map_frame(addr_t const from_phys, addr_t const to_dest, - Map_attr const attr, bool guest, FN const &fn) + Map_attr const attr, bool guest, auto const &fn) { if (_page_table_registry.page_frame_at(to_dest)) { /* @@ -410,7 +406,7 @@ class Genode::Vm_space bool ok = true; for (size_t i = 0; i < num_pages; i++) { - off_t const offset = i << get_page_size_log2(); + addr_t const offset = i << get_page_size_log2(); if (_map_frame(from_phys + offset, to_virt + offset, attr, false /* host page table */, fn_unmap)) @@ -444,7 +440,7 @@ class Genode::Vm_space Mutex::Guard guard(_mutex); for (size_t i = 0; i < num_pages; i++) { - off_t const offset = i << get_page_size_log2(); + addr_t const offset = i << get_page_size_log2(); _map_frame(from_phys + offset, guest_phys + offset, attr, true /* guest page table */, fn_unmap); @@ -459,7 +455,7 @@ class Genode::Vm_space Mutex::Guard guard(_mutex); for (size_t i = 0; unmap_success && i < num_pages; i++) { - off_t const offset = i << get_page_size_log2(); + addr_t const offset = i << get_page_size_log2(); _page_table_registry.flush_page(virt + offset, [&] (Cap_sel const &idx, addr_t) { diff --git a/repos/base-sel4/src/core/io_mem_session_support.cc b/repos/base-sel4/src/core/io_mem_session_support.cc index c83341aa9f..008746945c 100644 --- a/repos/base-sel4/src/core/io_mem_session_support.cc +++ b/repos/base-sel4/src/core/io_mem_session_support.cc @@ -13,12 +13,22 @@ /* core includes */ #include +#include -using namespace Genode; +using namespace Core; -void Io_mem_session_component::_unmap_local(addr_t, size_t) { } +void Io_mem_session_component::_unmap_local(addr_t, size_t size, addr_t phys) +{ + Untyped_memory::convert_to_untyped_frames(phys, size); +} -addr_t Io_mem_session_component::_map_local(addr_t, size_t) { return 0; } +addr_t Io_mem_session_component::_map_local(addr_t phys, size_t size) +{ + size_t const num_pages = size >> get_page_size_log2(); + Untyped_memory::convert_to_page_frames(phys, num_pages); + + return 0; +} diff --git a/repos/base-sel4/src/core/irq_session_component.cc b/repos/base-sel4/src/core/irq_session_component.cc index 973d465d69..108f8f9940 100644 --- a/repos/base-sel4/src/core/irq_session_component.cc +++ b/repos/base-sel4/src/core/irq_session_component.cc @@ -11,17 +11,15 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* Genode includes */ -#include - /* core includes */ #include #include #include +/* sel4 includes */ #include -using namespace Genode; +using namespace Core; bool Irq_object::associate(Irq_session::Trigger const irq_trigger, @@ -59,10 +57,11 @@ void Irq_object::_wait_for_irq() } -void Irq_object::start() +Thread::Start_result Irq_object::start() { - ::Thread::start(); + Thread::Start_result const result = ::Thread::start(); _sync_bootup.block(); + return result; } @@ -105,7 +104,8 @@ Irq_session_component::Irq_session_component(Range_allocator &irq_alloc, _irq_alloc(irq_alloc), _irq_object(_irq_number) { - long msi = Arg_string::find_arg(args, "device_config_phys").long_value(0); + Irq_args const irq_args(args); + bool msi { irq_args.type() != Irq_session::TYPE_LEGACY }; if (msi) throw Service_denied(); @@ -115,8 +115,6 @@ Irq_session_component::Irq_session_component(Range_allocator &irq_alloc, } - Irq_args const irq_args(args); - if (!_irq_object.associate(irq_args.trigger(), irq_args.polarity())) { error("could not associate with IRQ ", irq_args.irq_number()); throw Service_denied(); diff --git a/repos/base-sel4/src/core/pager.cc b/repos/base-sel4/src/core/pager.cc index ee1f0d6dca..36f3313c8c 100644 --- a/repos/base-sel4/src/core/pager.cc +++ b/repos/base-sel4/src/core/pager.cc @@ -25,7 +25,7 @@ /* seL4 includes */ #include -using namespace Genode; +using namespace Core; void Mapping::prepare_map_operation() const { } @@ -43,7 +43,7 @@ void Ipc_pager::wait_for_fault() uint8_t const depth = 32; int ret = seL4_CNode_SaveCaller(service, index, depth); if (ret != seL4_NoError) - Genode::error("saving reply cap failed with ", ret); + error("saving reply cap failed with ", ret); } _reply_sel = 0; _badge = 0; @@ -53,7 +53,7 @@ void Ipc_pager::wait_for_fault() bool Ipc_pager::install_mapping() { - _badge = Genode::install_mapping(_reply_mapping, _badge); + _badge = Core::install_mapping(_reply_mapping, _badge); return _badge; } @@ -87,6 +87,8 @@ void Ipc_pager::reply_and_wait_for_fault() addr_t const fault_type = seL4_MessageInfo_get_label(page_fault_msg_info); + _exception = fault_type != seL4_Fault_VMFault; + auto fault_name = [] (addr_t type) { switch (type) { @@ -141,7 +143,7 @@ void Pager_object::wake_up() void Pager_object::unresolved_page_fault_occurred() { - state.unresolved_page_fault = true; + state.state = Thread_state::State::PAGE_FAULT; } @@ -203,31 +205,29 @@ void Pager_entrypoint::entry() if (!obj) return; - /* send reply if page-fault handling succeeded */ - reply_pending = !obj->pager(_pager); - if (!reply_pending) { - warning("page-fault, ", *obj, - " ip=", Hex(_pager.fault_ip()), - " pf-addr=", Hex(_pager.fault_addr())); - _pager.reply_save_caller(obj->reply_cap_sel()); + /* on exception (beside page fault) don't reply and submit signal */ + if (_pager.exception()) { + warning("exception ", _pager.fault_addr(), " ", + *obj, " ip=", Hex(_pager.fault_ip())); + obj->submit_exception_signal(); return; } - try { - /* install memory mappings */ - if (_pager.install_mapping()) - return; - - /* on alignment fault don't reply and submit signal */ - if (_pager.align_fault()) { - warning("alignment fault, addr=", Hex(_pager.fault_addr()), - " ip=", Hex(_pager.fault_ip())); - throw 1; - } - } catch (...) { + /* on alignment fault don't reply and submit signal */ + if (_pager.align_fault()) { + warning("alignment fault, addr=", Hex(_pager.fault_addr()), + " ip=", Hex(_pager.fault_ip())); reply_pending = false; obj->submit_exception_signal(); + return; } + + reply_pending = obj->pager(_pager) == Pager_object::Pager_result::CONTINUE; + + if (reply_pending) + (void)_pager.install_mapping(); + else + _pager.reply_save_caller(obj->reply_cap_sel()); }); } } diff --git a/repos/base-sel4/src/core/platform.cc b/repos/base-sel4/src/core/platform.cc index b15f09fa0f..25b68940cb 100644 --- a/repos/base-sel4/src/core/platform.cc +++ b/repos/base-sel4/src/core/platform.cc @@ -14,7 +14,6 @@ /* Genode includes */ #include #include -#include #include #include @@ -34,7 +33,7 @@ /* seL4 includes */ #include -using namespace Genode; +using namespace Core; static bool const verbose_boot_info = true; @@ -44,7 +43,7 @@ static bool const verbose_boot_info = true; * platform_specific(). May happen if meta data allocator of phys_alloc runs * out of memory. */ -static Platform * platform_in_construction = nullptr; +static Core::Platform * platform_in_construction = nullptr; /* * Memory-layout information provided by the linker script @@ -61,7 +60,7 @@ extern unsigned _prog_img_beg, _prog_img_end; bool Mapped_mem_allocator::_map_local(addr_t virt_addr, addr_t phys_addr, size_t size) { if (platform_in_construction) - Genode::warning("need physical memory, but Platform object not constructed yet"); + warning("need physical memory, but Platform object not constructed yet"); size_t const num_pages = size / get_page_size(); @@ -86,14 +85,14 @@ bool Mapped_mem_allocator::_unmap_local(addr_t virt_addr, addr_t phys_addr, size ** Platform interface ** ************************/ -void Platform::_init_unused_phys_alloc() +void Core::Platform::_init_unused_phys_alloc() { /* the lower physical ram is kept by the kernel and not usable to us */ _unused_phys_alloc.add_range(0x100000, 0UL - 0x100000); } -void Platform::_init_allocators() +void Core::Platform::_init_allocators() { /* interrupt allocator */ _irq_alloc.add_range(0, 256); @@ -104,18 +103,20 @@ void Platform::_init_allocators() /* turn remaining untyped memory ranges into untyped pages */ _initial_untyped_pool.turn_into_untyped_object(Core_cspace::TOP_CNODE_UNTYPED_4K, - [&] (addr_t const phys, addr_t const size, bool const device) { + [&] (addr_t const phys, addr_t const size, bool const device_memory) { /* register to physical or iomem memory allocator */ addr_t const phys_addr = trunc_page(phys); size_t const phys_size = round_page(phys - phys_addr + size); - if (device) + if (device_memory) _io_mem_alloc.add_range(phys_addr, phys_size); else _core_mem_alloc.phys_alloc().add_range(phys_addr, phys_size); _unused_phys_alloc.remove_range(phys_addr, phys_size); + + return true; /* range used by this functor */ }); /* @@ -151,7 +152,7 @@ void Platform::_init_allocators() stack_area_virtual_size()); if (verbose_boot_info) { - typedef Hex_range Hex_range; + using Hex_range = Hex_range; log("virtual address layout of core:"); log(" overall ", Hex_range(_vm_base, _vm_size)); log(" core image ", Hex_range(core_virt_beg, image_elf_size)); @@ -163,7 +164,7 @@ void Platform::_init_allocators() } -void Platform::_switch_to_core_cspace() +void Core::Platform::_switch_to_core_cspace() { Cnode_base const initial_cspace(Cap_sel(seL4_CapInitThreadCNode), CONFIG_WORD_SIZE); @@ -175,7 +176,7 @@ void Platform::_switch_to_core_cspace() _core_cnode.copy(initial_cspace, Cnode_index(seL4_CapASIDControl)); _core_cnode.copy(initial_cspace, Cnode_index(seL4_CapInitThreadASIDPool)); /* XXX io port not available on ARM, causes just a kernel warning XXX */ - _core_cnode.copy(initial_cspace, Cnode_index(seL4_CapIOPort)); + _core_cnode.move(initial_cspace, Cnode_index(seL4_CapIOPortControl)); _core_cnode.copy(initial_cspace, Cnode_index(seL4_CapBootInfoFrame)); _core_cnode.copy(initial_cspace, Cnode_index(seL4_CapInitThreadIPCBuffer)); _core_cnode.copy(initial_cspace, Cnode_index(seL4_CapDomain)); @@ -266,13 +267,13 @@ void Platform::_switch_to_core_cspace() } -Cap_sel Platform::_init_asid_pool() +Cap_sel Core::Platform::_init_asid_pool() { return Cap_sel(seL4_CapInitThreadASIDPool); } -void Platform::_init_rom_modules() +void Core::Platform::_init_rom_modules() { seL4_BootInfo const &bi = sel4_boot_info(); @@ -344,11 +345,9 @@ void Platform::_init_rom_modules() * Register ROM module, the base address refers to location of the * ROM module within the phys CNode address space. */ - Rom_module * rom_module = new (rom_module_slab) - Rom_module(dst_frame << get_page_size_log2(), header->size, - (const char*)header->name); - - _rom_fs.insert(rom_module); + new (rom_module_slab) + Rom_module(_rom_fs, (const char*)header->name, + dst_frame << get_page_size_log2(), header->size); }; auto gen_platform_info = [&] (Xml_generator &xml) @@ -378,23 +377,23 @@ void Platform::_init_rom_modules() tsc_freq const * boot_freq = reinterpret_cast(reinterpret_cast(element) + sizeof(* element)); - xml.node("kernel", [&] () { + xml.node("kernel", [&] { xml.attribute("name", "sel4"); xml.attribute("acpi", true); }); - xml.node("hardware", [&] () { - xml.node("features", [&] () { + xml.node("hardware", [&] { + xml.node("features", [&] { #ifdef CONFIG_VTX xml.attribute("vmx", true); #else xml.attribute("vmx", false); #endif }); - xml.node("tsc", [&] () { + xml.node("tsc", [&] { xml.attribute("freq_khz" , boot_freq->freq_mhz * 1000UL); }); }); - xml.node("affinity-space", [&] () { + xml.node("affinity-space", [&] { xml.attribute("width", affinity_space().width()); xml.attribute("height", affinity_space().height()); }); @@ -417,8 +416,8 @@ void Platform::_init_rom_modules() mbi2_framebuffer const * boot_fb = reinterpret_cast(reinterpret_cast(element) + sizeof(*element)); - xml.node("boot", [&] () { - xml.node("framebuffer", [&] () { + xml.node("boot", [&] { + xml.node("framebuffer", [&] { xml.attribute("phys", String<32>(Hex(boot_fb->addr))); xml.attribute("width", boot_fb->width); xml.attribute("height", boot_fb->height); @@ -432,7 +431,7 @@ void Platform::_init_rom_modules() if (element->id != SEL4_BOOTINFO_HEADER_X86_ACPI_RSDP) continue; - xml.node("acpi", [&] () { + xml.node("acpi", [&] { struct Acpi_rsdp { @@ -447,7 +446,7 @@ void Platform::_init_rom_modules() bool valid() const { const char sign[] = "RSD PTR "; - return signature == *(Genode::uint64_t *)sign; + return signature == *(uint64_t *)sign; } } __attribute__((packed)); @@ -508,8 +507,8 @@ void Platform::_init_rom_modules() memset(core_local_ptr, 0, size); content_fn((char *)core_local_ptr, size); - _rom_fs.insert( - new (core_mem_alloc()) Rom_module(phys.addr, size, rom_name)); + new (core_mem_alloc()) + Rom_module(_rom_fs, rom_name, phys.addr, size); phys.keep = true; }, @@ -521,7 +520,7 @@ void Platform::_init_rom_modules() }; export_page_as_rom_module("platform_info", [&] (char *ptr, size_t size) { - Xml_generator xml(ptr, size, "platform_info", [&] () { + Xml_generator xml(ptr, size, "platform_info", [&] { gen_platform_info(xml); }); }); export_page_as_rom_module("core_log", [&] (char *ptr, size_t size) { @@ -529,9 +528,8 @@ void Platform::_init_rom_modules() } -Platform::Platform() +Core::Platform::Platform() : - _io_mem_alloc(&core_mem_alloc()), _io_port_alloc(&core_mem_alloc()), _irq_alloc(&core_mem_alloc()), _unused_phys_alloc(&core_mem_alloc()), @@ -556,7 +554,7 @@ Platform::Platform() { platform_in_construction = this; - /* start benchmarking for CPU utilization in Genode TRACE service */ + /* start benchmarking for CPU utilization in TRACE service */ seL4_BenchmarkResetLog(); /* create notification object for Genode::Lock used by this first thread */ @@ -618,7 +616,7 @@ Platform::Platform() */ Info trace_source_info() const override { - Genode::Thread &myself = *Genode::Thread::myself(); + Thread &myself = *Thread::myself(); addr_t const ipc_buffer = reinterpret_cast(myself.utcb()); seL4_IPCBuffer * ipcbuffer = reinterpret_cast(ipc_buffer); uint64_t const * buf = reinterpret_cast(ipcbuffer->msg); @@ -632,7 +630,7 @@ Platform::Platform() } Idle_trace_source(Trace::Source_registry ®istry, - Platform &platform, Range_allocator &phys_alloc, + Core::Platform &platform, Range_allocator &phys_alloc, Affinity::Location affinity) : Trace::Control(), @@ -651,8 +649,8 @@ Platform::Platform() affinity_space().height())); } - /* I/O port allocator (only meaningful for x86) */ - _io_port_alloc.add_range(0, 0x10000); + /* solely meaningful for x86 */ + _init_io_ports(); _init_rom_modules(); @@ -660,7 +658,7 @@ Platform::Platform() } -unsigned Platform::alloc_core_rcv_sel() +unsigned Core::Platform::alloc_core_rcv_sel() { Cap_sel rcv_sel = _core_sel_alloc.alloc(); @@ -671,13 +669,13 @@ unsigned Platform::alloc_core_rcv_sel() } -void Platform::reset_sel(unsigned sel) +void Core::Platform::reset_sel(unsigned sel) { _core_cnode.remove(Cap_sel(sel)); } -void Platform::wait_for_exit() +void Core::Platform::wait_for_exit() { sleep_forever(); } diff --git a/repos/base-sel4/src/core/platform_pd.cc b/repos/base-sel4/src/core/platform_pd.cc index c6044f03df..deebe71345 100644 --- a/repos/base-sel4/src/core/platform_pd.cc +++ b/repos/base-sel4/src/core/platform_pd.cc @@ -11,9 +11,6 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* Genode includes */ -#include - /* core includes */ #include #include @@ -24,7 +21,7 @@ /* base-internal includes */ #include -using namespace Genode; +using namespace Core; /***************************************** @@ -52,39 +49,8 @@ Bit_allocator<1024> &Platform_pd::pd_id_alloc() } -bool Platform_pd::bind_thread(Platform_thread &thread) +void Platform_pd::map_ipc_buffer(Ipc_buffer_phys const from, Utcb_virt const to) { - try { - /* allocate fault handler selector in the PD's CSpace */ - thread._fault_handler_sel = alloc_sel(); - /* allocate endpoint selector in the PD's CSpace */ - thread._ep_sel = alloc_sel(); - thread._vcpu_sel = alloc_sel(); - /* allocate asynchronous selector used for locks in the PD's CSpace */ - thread._lock_sel = thread._utcb ? alloc_sel() : Cap_sel(INITIAL_SEL_LOCK); - thread._vcpu_notify_sel = alloc_sel(); - } catch (Platform_pd::Sel_bit_alloc::Out_of_indices) { - if (thread._fault_handler_sel.value()) { - free_sel(thread._fault_handler_sel); - thread._fault_handler_sel = Cap_sel(0); - } - if (thread._ep_sel.value()) { - free_sel(thread._ep_sel); - thread._ep_sel = Cap_sel(0); - } - if (thread._vcpu_sel.value()) { - free_sel(thread._vcpu_sel); - thread._vcpu_sel = Cap_sel(0); - } - if (thread._vcpu_notify_sel.value()) { - free_sel(thread._vcpu_notify_sel); - thread._vcpu_notify_sel = Cap_sel(0); - } - return false; - } - - thread._pd = this; - /* * Map IPC buffer * @@ -95,35 +61,20 @@ bool Platform_pd::bind_thread(Platform_thread &thread) * to attach the UTCB as a dataspace to the stack area to make the RM * session aware to the mapping. This code is missing. */ - addr_t const utcb = (thread._utcb) ? thread._utcb - : (addr_t)thread.INITIAL_IPC_BUFFER_VIRT; - Vm_space::Map_attr const attr { .cached = true, .write_combined = false, .writeable = true, .executable = false, .flush_support = true }; enum { ONE_PAGE = 1 }; - _vm_space.alloc_page_tables(utcb, get_page_size()); - _vm_space.map(thread._info.ipc_buffer_phys, utcb, ONE_PAGE, attr); - return true; + _vm_space.alloc_page_tables(to.addr, get_page_size()); + _vm_space.map(from.addr, to.addr, ONE_PAGE, attr); } -void Platform_pd::unbind_thread(Platform_thread &thread) +void Platform_pd::unmap_ipc_buffer(Utcb_virt const utcb) { - if (thread._utcb) - free_sel(thread._lock_sel); - - free_sel(thread._fault_handler_sel); - free_sel(thread._ep_sel); - free_sel(thread._vcpu_sel); - free_sel(thread._vcpu_notify_sel); - - if (thread._utcb) - _vm_space.unmap(thread._utcb, 1); - else - _vm_space.unmap(thread.INITIAL_IPC_BUFFER_VIRT, 1); + _vm_space.unmap(utcb.addr, 1); } diff --git a/repos/base-sel4/src/core/platform_thread.cc b/repos/base-sel4/src/core/platform_thread.cc index 6d0a593941..6b97b81bd4 100644 --- a/repos/base-sel4/src/core/platform_thread.cc +++ b/repos/base-sel4/src/core/platform_thread.cc @@ -11,10 +11,6 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* Genode includes */ -#include -#include - /* core includes */ #include #include @@ -26,7 +22,7 @@ /* seL4 includes */ #include -using namespace Genode; +using namespace Core; /***************************************************** @@ -88,7 +84,7 @@ Platform_thread_registry &platform_thread_registry() } -bool Genode::install_mapping(Mapping const &mapping, unsigned long pager_object_badge) +bool Core::install_mapping(Mapping const &mapping, unsigned long pager_object_badge) { return platform_thread_registry().install_mapping(mapping, pager_object_badge); } @@ -98,8 +94,10 @@ bool Genode::install_mapping(Mapping const &mapping, unsigned long pager_object_ ** Utilities to support the Platform_thread interface ** ********************************************************/ -static void prepopulate_ipc_buffer(addr_t ipc_buffer_phys, Cap_sel ep_sel, - Cap_sel lock_sel) +static void prepopulate_ipc_buffer(Ipc_buffer_phys const ipc_buffer_phys, + Cap_sel const ep_sel, + Cap_sel const lock_sel, + Utcb_virt const utcb_virt) { /* IPC buffer is one page */ size_t const page_rounded_size = get_page_size(); @@ -110,12 +108,13 @@ static void prepopulate_ipc_buffer(addr_t ipc_buffer_phys, Cap_sel ep_sel, [&] (void *virt_ptr) { /* map the IPC buffer to core-local virtual addresses */ - map_local(ipc_buffer_phys, (addr_t)virt_ptr, 1); + map_local(ipc_buffer_phys.addr, (addr_t)virt_ptr, 1); /* populate IPC buffer with thread information */ Native_utcb &utcb = *(Native_utcb *)virt_ptr; utcb.ep_sel (ep_sel .value()); utcb.lock_sel(lock_sel.value()); + utcb.ipcbuffer(utcb_virt); /* unmap IPC buffer from core */ if (!unmap_local((addr_t)virt_ptr, 1)) { @@ -140,49 +139,48 @@ static void prepopulate_ipc_buffer(addr_t ipc_buffer_phys, Cap_sel ep_sel, ** Platform_thread interface ** *******************************/ -int Platform_thread::start(void *ip, void *sp, unsigned int) +void Platform_thread::start(void *ip, void *sp, unsigned int) { - ASSERT(_pd); ASSERT(_pager); /* pager endpoint in core */ Cap_sel const pager_sel(Capability_space::ipc_cap_data(_pager->cap()).sel); /* install page-fault handler endpoint selector to the PD's CSpace */ - _pd->cspace_cnode(_fault_handler_sel).copy(platform_specific().core_cnode(), - pager_sel, _fault_handler_sel); + _pd.cspace_cnode(_fault_handler_sel).copy(platform_specific().core_cnode(), + pager_sel, _fault_handler_sel); /* install the thread's endpoint selector to the PD's CSpace */ - _pd->cspace_cnode(_ep_sel).copy(platform_specific().core_cnode(), - _info.ep_sel, _ep_sel); + _pd.cspace_cnode(_ep_sel).copy(platform_specific().core_cnode(), + _info.ep_sel, _ep_sel); /* install the thread's notification object to the PD's CSpace */ - _pd->cspace_cnode(_lock_sel).mint(platform_specific().core_cnode(), - _info.lock_sel, _lock_sel); + _pd.cspace_cnode(_lock_sel).mint(platform_specific().core_cnode(), + _info.lock_sel, _lock_sel); /* * Populate the thread's IPC buffer with initial information about the * thread. Once started, the thread picks up this information in the * 'Thread::_thread_bootstrap' method. */ - prepopulate_ipc_buffer(_info.ipc_buffer_phys, _ep_sel, _lock_sel); + prepopulate_ipc_buffer(_info.ipc_buffer_phys, _ep_sel, _lock_sel, _utcb); /* bind thread to PD and CSpace */ seL4_CNode_CapData const guard_cap_data = - seL4_CNode_CapData_new(0, CONFIG_WORD_SIZE - _pd->cspace_size_log2()); + seL4_CNode_CapData_new(0, CONFIG_WORD_SIZE - _pd.cspace_size_log2()); seL4_CNode_CapData const no_cap_data = { { 0 } }; int const ret = seL4_TCB_SetSpace(_info.tcb_sel.value(), _fault_handler_sel.value(), - _pd->cspace_cnode_1st().sel().value(), + _pd.cspace_cnode_1st().sel().value(), guard_cap_data.words[0], - _pd->page_directory_sel().value(), + _pd.page_directory_sel().value(), no_cap_data.words[0]); ASSERT(ret == 0); - start_sel4_thread(_info.tcb_sel, (addr_t)ip, (addr_t)(sp), _location.xpos()); - return 0; + start_sel4_thread(_info.tcb_sel, (addr_t)ip, (addr_t)(sp), _location.xpos(), + _utcb.addr); } @@ -202,26 +200,23 @@ void Platform_thread::resume() } -void Platform_thread::state(Thread_state) -{ - warning(__PRETTY_FUNCTION__, " not implemented"); - throw Cpu_thread::State_access_failed(); -} +void Platform_thread::state(Thread_state) { } bool Platform_thread::install_mapping(Mapping const &mapping) { - return _pd->install_mapping(mapping, name()); + return _pd.install_mapping(mapping, name()); } -Platform_thread::Platform_thread(size_t, const char *name, unsigned priority, - Affinity::Location location, addr_t utcb) +Platform_thread::Platform_thread(Platform_pd &pd, size_t, const char *name, + unsigned priority, Affinity::Location location, + addr_t utcb) : _name(name), - _utcb(utcb), + _utcb(utcb ? utcb : addr_t(INITIAL_IPC_BUFFER_VIRT)), _pager_obj_sel(platform_specific().core_sel_alloc().alloc()), - _location(location), + _pd(pd), _location(location), _priority((uint16_t)(Cpu_session::scale_priority(CONFIG_NUM_PRIORITIES, priority))) { @@ -230,16 +225,54 @@ Platform_thread::Platform_thread(size_t, const char *name, unsigned priority, if (_priority > 0) _priority -= 1; - _info.init(_utcb ? _utcb : (addr_t)INITIAL_IPC_BUFFER_VIRT, _priority); + _info.init(_utcb, _priority); platform_thread_registry().insert(*this); + + try { + /* allocate fault handler selector in the PD's CSpace */ + _fault_handler_sel = _pd.alloc_sel(); + /* allocate endpoint selector in the PD's CSpace */ + _ep_sel = _pd.alloc_sel(); + _vcpu_sel = _pd.alloc_sel(); + /* allocate asynchronous selector used for locks in the PD's CSpace */ + _lock_sel = main_thread() ? Cap_sel(INITIAL_SEL_LOCK) + : _pd.alloc_sel(); + _vcpu_notify_sel = _pd.alloc_sel(); + + _pd.map_ipc_buffer(_info.ipc_buffer_phys, _utcb); + _bound_to_pd = true; + } catch (Platform_pd::Sel_alloc::Out_of_indices) { + + /* revert allocations */ + if (_fault_handler_sel.value()) _pd.free_sel(_fault_handler_sel); + if (_ep_sel.value()) _pd.free_sel(_ep_sel); + if (_vcpu_sel.value()) _pd.free_sel(_vcpu_sel); + if (_vcpu_notify_sel.value()) _pd.free_sel(_vcpu_notify_sel); + + _fault_handler_sel = Cap_sel { 0 }; + _ep_sel = Cap_sel { 0 }; + _vcpu_sel = Cap_sel { 0 }; + _vcpu_notify_sel = Cap_sel { 0 }; + + _bound_to_pd = false; + } } Platform_thread::~Platform_thread() { - if (_pd) { - seL4_TCB_Suspend(_info.tcb_sel.value()); - _pd->unbind_thread(*this); + seL4_TCB_Suspend(_info.tcb_sel.value()); + + if (_bound_to_pd) { + if (!main_thread()) + _pd.free_sel(_lock_sel); + + _pd.free_sel(_fault_handler_sel); + _pd.free_sel(_ep_sel); + _pd.free_sel(_vcpu_sel); + _pd.free_sel(_vcpu_notify_sel); + + _pd.unmap_ipc_buffer(_utcb); } if (_pager) { @@ -256,6 +289,7 @@ Platform_thread::~Platform_thread() platform_specific().core_sel_alloc().free(_pager_obj_sel); } + Trace::Execution_time Platform_thread::execution_time() const { if (!Thread::myself() || !Thread::myself()->utcb()) { @@ -275,18 +309,20 @@ Trace::Execution_time Platform_thread::execution_time() const return { ec_time, sc_time, 10000, _priority}; } + void Platform_thread::setup_vcpu(Cap_sel ept, Cap_sel notification) { if (!_info.init_vcpu(platform_specific(), ept)) { - Genode::error("creating vCPU failed"); + error("creating vCPU failed"); return; } /* install the thread's endpoint selector to the PD's CSpace */ - _pd->cspace_cnode(_vcpu_sel).copy(platform_specific().core_cnode(), - _info.vcpu_sel, _vcpu_sel); - _pd->cspace_cnode(_vcpu_notify_sel).copy(platform_specific().core_cnode(), - notification, _vcpu_notify_sel); + _pd.cspace_cnode(_vcpu_sel).copy(platform_specific().core_cnode(), + _info.vcpu_sel, _vcpu_sel); + _pd.cspace_cnode(_vcpu_notify_sel).copy(platform_specific().core_cnode(), + notification, _vcpu_notify_sel); - prepopulate_ipc_buffer(_info.ipc_buffer_phys, _vcpu_sel, _vcpu_notify_sel); + prepopulate_ipc_buffer(_info.ipc_buffer_phys, _vcpu_sel, _vcpu_notify_sel, + _utcb); } diff --git a/repos/base-sel4/src/core/ram_dataspace_support.cc b/repos/base-sel4/src/core/ram_dataspace_support.cc index 814db791ae..660eecb1de 100644 --- a/repos/base-sel4/src/core/ram_dataspace_support.cc +++ b/repos/base-sel4/src/core/ram_dataspace_support.cc @@ -17,7 +17,7 @@ #include #include -using namespace Genode; +using namespace Core; void Ram_dataspace_factory::_export_ram_ds(Dataspace_component &ds) diff --git a/repos/base-sel4/src/core/rpc_cap_factory.cc b/repos/base-sel4/src/core/rpc_cap_factory.cc index 806711d515..bcdc174062 100644 --- a/repos/base-sel4/src/core/rpc_cap_factory.cc +++ b/repos/base-sel4/src/core/rpc_cap_factory.cc @@ -23,7 +23,7 @@ /* base-internal include */ #include -using namespace Genode; +using namespace Core; static unsigned unique_id_cnt; diff --git a/repos/base-sel4/src/core/signal_source_component.cc b/repos/base-sel4/src/core/signal_source_component.cc index 69df522588..87a4953d6d 100644 --- a/repos/base-sel4/src/core/signal_source_component.cc +++ b/repos/base-sel4/src/core/signal_source_component.cc @@ -11,9 +11,6 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* Genode includes */ -#include - /* core includes */ #include #include @@ -21,13 +18,8 @@ /* base-internal include */ #include +using namespace Core; -using namespace Genode; - - -/***************************** - ** Signal-source component ** - *****************************/ void Signal_source_component::release(Signal_context_component &context) { diff --git a/repos/base-sel4/src/core/spec/arm/arch_kernel_object.h b/repos/base-sel4/src/core/spec/arm/arch_kernel_object.h index 83951b2817..9178ef3488 100644 --- a/repos/base-sel4/src/core/spec/arm/arch_kernel_object.h +++ b/repos/base-sel4/src/core/spec/arm/arch_kernel_object.h @@ -16,7 +16,10 @@ #include -namespace Genode { +/* core includes */ +#include + +namespace Core { enum { PAGE_TABLE_LOG2_SIZE = 20 /* 1M region */ diff --git a/repos/base-sel4/src/core/spec/arm/boot_info.cc b/repos/base-sel4/src/core/spec/arm/boot_info.cc index dc30965ae6..d72e924755 100644 --- a/repos/base-sel4/src/core/spec/arm/boot_info.cc +++ b/repos/base-sel4/src/core/spec/arm/boot_info.cc @@ -11,20 +11,20 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* Genode includes */ -#include - /* core includes */ +#include #include +using namespace Core; + /* provided by the assembly startup code */ -extern Genode::addr_t __initial_r0; +extern addr_t __initial_r0; /** * Obtain seL4 boot info structure */ -seL4_BootInfo const & Genode::sel4_boot_info() +seL4_BootInfo const &Core::sel4_boot_info() { return *(seL4_BootInfo const *)__initial_r0; } diff --git a/repos/base-sel4/src/core/spec/arm/fault_info.h b/repos/base-sel4/src/core/spec/arm/fault_info.h index 4a6ceebaa0..29cee4b3d4 100644 --- a/repos/base-sel4/src/core/spec/arm/fault_info.h +++ b/repos/base-sel4/src/core/spec/arm/fault_info.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2017 Genode Labs GmbH + * Copyright (C) 2017-2023 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -26,10 +26,29 @@ struct Fault_info DFSR_WRITE_FAULT = 1UL << 11 }; - Fault_info(seL4_MessageInfo_t) + Genode::addr_t _ip_from_message(seL4_MessageInfo_t &info) const + { + auto const fault_type = seL4_MessageInfo_get_label(info); + + if (fault_type == seL4_Fault_UserException) + return seL4_Fault_UserException_get_FaultIP(seL4_getFault(info)); + else + return seL4_GetMR(0); + } + + Genode::addr_t _pf_from_message(seL4_MessageInfo_t &info) const + { + auto const fault_type = seL4_MessageInfo_get_label(info); + if (fault_type == seL4_Fault_UserException) + return seL4_Fault_UserException_get_Number(seL4_getFault(info)); + else + return seL4_GetMR(1); + } + + Fault_info(seL4_MessageInfo_t info) : - ip(seL4_GetMR(0)), - pf(seL4_GetMR(1)), + ip(_ip_from_message(info)), + pf(_pf_from_message(info)), data_abort(seL4_GetMR(2) != IFSR_FAULT), /* Instruction Fault Status Register (IFSR) resp. Data FSR (DFSR) */ write(data_abort && (seL4_GetMR(3) & DFSR_WRITE_FAULT)), diff --git a/repos/base-sel4/src/core/spec/arm/irq.cc b/repos/base-sel4/src/core/spec/arm/irq.cc index 05eab2a132..a16be9edd6 100644 --- a/repos/base-sel4/src/core/spec/arm/irq.cc +++ b/repos/base-sel4/src/core/spec/arm/irq.cc @@ -8,8 +8,11 @@ #include -long Genode::Irq_object::_associate(Irq_session::Trigger const &, - Irq_session::Polarity const &) +using namespace Core; + + +long Irq_object::_associate(Irq_session::Trigger const &, + Irq_session::Polarity const &) { seL4_CNode const root = seL4_CapInitThreadCNode; seL4_Word const index = _kernel_irq_sel.value(); diff --git a/repos/base-sel4/src/core/spec/arm/platform.cc b/repos/base-sel4/src/core/spec/arm/platform.cc index 70f60d05d1..a2caed4f52 100644 --- a/repos/base-sel4/src/core/spec/arm/platform.cc +++ b/repos/base-sel4/src/core/spec/arm/platform.cc @@ -21,7 +21,8 @@ #include "arch_kernel_object.h" -using namespace Genode; +using namespace Core; + static Phys_allocator *_phys_alloc_16k_ptr; @@ -35,18 +36,26 @@ static Phys_allocator &phys_alloc_16k() } -seL4_Word Genode::Untyped_memory::smallest_page_type() { +seL4_Word Untyped_memory::smallest_page_type() { return seL4_ARM_SmallPageObject; } -void Genode::Platform::init_sel4_ipc_buffer() { } +void Platform::init_sel4_ipc_buffer() +{ + /* + * Setup tls pointer such, that it points to the (kernel created) core + * main thread IPC buffer. It is used in seL4_GetIPCBuffer(). + */ + seL4_BootInfo const &bi = sel4_boot_info(); + seL4_SetTLSBase((unsigned long)&bi.ipcBuffer); +} -long Genode::Platform::_unmap_page_frame(Cap_sel const &sel) { +long Platform::_unmap_page_frame(Cap_sel const &sel) { return seL4_ARM_Page_Unmap(sel.value()); } -void Genode::Platform::_init_core_page_table_registry() +void Platform::_init_core_page_table_registry() { seL4_BootInfo const &bi = sel4_boot_info(); @@ -68,7 +77,7 @@ void Genode::Platform::_init_core_page_table_registry() /* initialize 16k memory allocator */ { - static Genode::Phys_allocator inst(&core_mem_alloc()); + static Phys_allocator inst(&core_mem_alloc()); _phys_alloc_16k_ptr = &inst; } @@ -77,9 +86,15 @@ void Genode::Platform::_init_core_page_table_registry() addr_t const max_pd_mem = MAX_PROCESS_COUNT * (1UL << Page_directory_kobj::SIZE_LOG2); _initial_untyped_pool.turn_into_untyped_object(Core_cspace::TOP_CNODE_UNTYPED_16K, - [&] (addr_t const phys, addr_t const size, bool) { + [&] (addr_t const phys, addr_t const size, bool const device_memory) { + + if (device_memory) + return false; + phys_alloc_16k().add_range(phys, size); _unused_phys_alloc.remove_range(phys, size); + + return true; }, Page_directory_kobj::SIZE_LOG2, max_pd_mem); @@ -87,7 +102,7 @@ void Genode::Platform::_init_core_page_table_registry() } -Genode::addr_t Genode::Platform_pd::_init_page_directory() const +addr_t Platform_pd::_init_page_directory() const { /* page directory table contains 4096 elements of 32bits -> 16k required */ enum { PAGES_16K = (1UL << Page_directory_kobj::SIZE_LOG2) / 4096 }; @@ -109,7 +124,7 @@ Genode::addr_t Genode::Platform_pd::_init_page_directory() const } -void Genode::Platform_pd::_deinit_page_directory(addr_t phys_addr) const +void Platform_pd::_deinit_page_directory(addr_t phys_addr) const { int ret = seL4_CNode_Delete(seL4_CapInitThreadCNode, _page_directory_sel.value(), 32); @@ -121,3 +136,8 @@ void Genode::Platform_pd::_deinit_page_directory(addr_t phys_addr) const Untyped_memory::free_page(phys_alloc_16k(), phys_addr); } + + +void Platform::_init_io_ports() +{ +} diff --git a/repos/base-sel4/src/core/spec/arm/platform_thread.cc b/repos/base-sel4/src/core/spec/arm/platform_thread.cc index 2f7500487e..5b7a48fccd 100644 --- a/repos/base-sel4/src/core/spec/arm/platform_thread.cc +++ b/repos/base-sel4/src/core/spec/arm/platform_thread.cc @@ -13,7 +13,10 @@ #include -void Genode::Platform_thread::affinity(Affinity::Location const location) +using namespace Core; + + +void Platform_thread::affinity(Affinity::Location const location) { #if CONFIG_MAX_NUM_NODES > 1 seL4_Error const res = seL4_TCB_SetAffinity(tcb_sel().value(), location.xpos()); diff --git a/repos/base-sel4/src/core/spec/arm/thread.cc b/repos/base-sel4/src/core/spec/arm/thread.cc index 5ab1a951d1..1d4630aa4f 100644 --- a/repos/base-sel4/src/core/spec/arm/thread.cc +++ b/repos/base-sel4/src/core/spec/arm/thread.cc @@ -15,18 +15,22 @@ */ /* base includes */ +#include #include /* core includes */ #include #include -void Genode::start_sel4_thread(Cap_sel tcb_sel, addr_t ip, addr_t sp, - unsigned cpu) +using namespace Core; + + +void Core::start_sel4_thread(Cap_sel tcb_sel, addr_t ip, addr_t sp, + unsigned cpu, addr_t const virt_utcb) { /* set register values for the instruction pointer and stack pointer */ seL4_UserContext regs; - Genode::memset(®s, 0, sizeof(regs)); + memset(®s, 0, sizeof(regs)); size_t const num_regs = sizeof(regs)/sizeof(seL4_Word); regs.pc = ip; @@ -38,16 +42,26 @@ void Genode::start_sel4_thread(Cap_sel tcb_sel, addr_t ip, addr_t sp, affinity_sel4_thread(tcb_sel, cpu); + /* + * Set tls pointer to location, where ipcbuffer address is stored, so + * that it can be used by seL4_GetIPCBuffer() + */ + auto error = seL4_TCB_SetTLSBase(tcb_sel.value(), + virt_utcb + Native_utcb::tls_ipcbuffer_offset); + ASSERT(not error); + seL4_TCB_Resume(tcb_sel.value()); } -void Genode::affinity_sel4_thread(Cap_sel const &, unsigned cpu) + +void Core::affinity_sel4_thread(Cap_sel const &, unsigned cpu) { if (cpu != 0) error("could not set affinity of thread"); } -Genode::Thread_state Genode::Platform_thread::state() + +Thread_state Platform_thread::state() { seL4_TCB const thread = _info.tcb_sel.value(); seL4_Bool const suspend_source = false; @@ -57,32 +71,29 @@ Genode::Thread_state Genode::Platform_thread::state() long const ret = seL4_TCB_ReadRegisters(thread, suspend_source, arch_flags, register_count, ®isters); - if (ret != seL4_NoError) { - error("reading thread state ", ret); - throw Cpu_thread::State_access_failed(); - } + if (ret != seL4_NoError) + return { .state = Thread_state::State::UNAVAILABLE, .cpu = { } }; - Thread_state state; - Genode::memset(&state, 0, sizeof(state)); + Thread_state state { }; - state.r0 = registers.r0; - state.r1 = registers.r1; - state.r2 = registers.r2; - state.r3 = registers.r3; - state.r4 = registers.r4; - state.r5 = registers.r5; - state.r6 = registers.r6; - state.r7 = registers.r7; - state.r8 = registers.r8; - state.r9 = registers.r9; - state.r10 = registers.r10; - state.r11 = registers.r11; - state.r12 = registers.r12; - state.sp = registers.sp; - state.lr = registers.r14; - state.ip = registers.pc; - state.cpsr = registers.cpsr; - state.cpu_exception = 0; /* XXX detect/track if in exception and report here */ + state.cpu.r0 = registers.r0; + state.cpu.r1 = registers.r1; + state.cpu.r2 = registers.r2; + state.cpu.r3 = registers.r3; + state.cpu.r4 = registers.r4; + state.cpu.r5 = registers.r5; + state.cpu.r6 = registers.r6; + state.cpu.r7 = registers.r7; + state.cpu.r8 = registers.r8; + state.cpu.r9 = registers.r9; + state.cpu.r10 = registers.r10; + state.cpu.r11 = registers.r11; + state.cpu.r12 = registers.r12; + state.cpu.sp = registers.sp; + state.cpu.lr = registers.r14; + state.cpu.ip = registers.pc; + state.cpu.cpsr = registers.cpsr; + state.cpu.cpu_exception = 0; /* XXX detect/track if in exception and report here */ return state; } diff --git a/repos/base-sel4/src/core/spec/arm/vm_space.cc b/repos/base-sel4/src/core/spec/arm/vm_space.cc index 5d28c2eee0..5c6e8b6b99 100644 --- a/repos/base-sel4/src/core/spec/arm/vm_space.cc +++ b/repos/base-sel4/src/core/spec/arm/vm_space.cc @@ -15,19 +15,22 @@ #include #include -static long map_page_table(Genode::Cap_sel const pagetable, - Genode::Cap_sel const vroot, - Genode::addr_t const virt) +using namespace Core; + + +static long map_page_table(Cap_sel const pagetable, + Cap_sel const vroot, + addr_t const virt) { return seL4_ARM_PageTable_Map(pagetable.value(), vroot.value(), virt, seL4_ARM_Default_VMAttributes); } -long Genode::Vm_space::_map_page(Genode::Cap_sel const &idx, - Genode::addr_t const virt, - Map_attr const map_attr, - bool) +long Vm_space::_map_page(Cap_sel const &idx, + addr_t const virt, + Map_attr const map_attr, + bool) { seL4_ARM_Page const service = _idx_to_sel(idx.value()).value(); seL4_ARM_PageDirectory const pd = _pd_sel.value(); @@ -45,16 +48,16 @@ long Genode::Vm_space::_map_page(Genode::Cap_sel const &idx, } -long Genode::Vm_space::_unmap_page(Genode::Cap_sel const &idx) +long Vm_space::_unmap_page(Cap_sel const &idx) { seL4_ARM_Page const service = _idx_to_sel(idx.value()).value(); return seL4_ARM_Page_Unmap(service); } -long Genode::Vm_space::_invalidate_page(Genode::Cap_sel const &idx, - seL4_Word const start, - seL4_Word const end) +long Vm_space::_invalidate_page(Cap_sel const &idx, + seL4_Word const start, + seL4_Word const end) { seL4_ARM_Page const service = _idx_to_sel(idx.value()).value(); long error = seL4_ARM_Page_CleanInvalidate_Data(service, 0, end - start); @@ -68,8 +71,8 @@ long Genode::Vm_space::_invalidate_page(Genode::Cap_sel const &idx, } -void Genode::Vm_space::unsynchronized_alloc_page_tables(addr_t const start, - addr_t const size) +void Vm_space::unsynchronized_alloc_page_tables(addr_t const start, + addr_t const size) { addr_t constexpr PAGE_TABLE_AREA = 1UL << PAGE_TABLE_LOG2_SIZE; addr_t virt = start & ~(PAGE_TABLE_AREA - 1); diff --git a/repos/base-sel4/src/core/spec/x86/fault_info.h b/repos/base-sel4/src/core/spec/x86/fault_info.h index 00e7be1822..6c2de35b4c 100644 --- a/repos/base-sel4/src/core/spec/x86/fault_info.h +++ b/repos/base-sel4/src/core/spec/x86/fault_info.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2017 Genode Labs GmbH + * Copyright (C) 2017-2023 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -13,9 +13,9 @@ struct Fault_info { - Genode::addr_t ip = 0; - Genode::addr_t pf = 0; - bool write = 0; + Genode::addr_t const ip; + Genode::addr_t const pf; + bool const write; /* * Intel manual: 6.15 EXCEPTION AND INTERRUPT REFERENCE @@ -29,10 +29,30 @@ struct Fault_info ERR_P = 1 << 0, }; - Fault_info(seL4_MessageInfo_t) + Genode::addr_t _ip_from_message(seL4_MessageInfo_t &info) const + { + auto const fault_type = seL4_MessageInfo_get_label(info); + + if (fault_type == seL4_Fault_UserException) + return seL4_Fault_UserException_get_FaultIP(seL4_getFault(info)); + else + return seL4_GetMR(0); + } + + Genode::addr_t _pf_from_message(seL4_MessageInfo_t &info) const + { + auto const fault_type = seL4_MessageInfo_get_label(info); + + if (fault_type == seL4_Fault_UserException) + return seL4_Fault_UserException_get_Number(seL4_getFault(info)); + else + return seL4_GetMR(1); + } + + Fault_info(seL4_MessageInfo_t info) : - ip(seL4_GetMR(0)), - pf(seL4_GetMR(1)), + ip(_ip_from_message(info)), + pf(_pf_from_message(info)), write(seL4_GetMR(3) & ERR_W) { } diff --git a/repos/base-sel4/src/core/spec/x86/io_port_session_support.cc b/repos/base-sel4/src/core/spec/x86/io_port_session_support.cc index c8c039fbf2..f1230a7965 100644 --- a/repos/base-sel4/src/core/spec/x86/io_port_session_support.cc +++ b/repos/base-sel4/src/core/spec/x86/io_port_session_support.cc @@ -11,16 +11,13 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* Genode includes */ -#include - /* core includes */ #include /* base-internal includes */ #include -using namespace Genode; +using namespace Core; unsigned char Io_port_session_component::inb(unsigned short address) @@ -28,11 +25,11 @@ unsigned char Io_port_session_component::inb(unsigned short address) /* check boundaries */ if (!_in_bounds(address, sizeof(unsigned char))) return 0; - seL4_X86_IOPort_In8_t v = seL4_X86_IOPort_In8(seL4_CapIOPort, address); + auto const v = seL4_X86_IOPort_In8(Core_cspace::io_port_sel(), address); if (v.error == seL4_NoError) return v.result; - Genode::error(__PRETTY_FUNCTION__, " failed ", v.error); + error(__PRETTY_FUNCTION__, " failed ", v.error); return 0; } @@ -42,11 +39,11 @@ unsigned short Io_port_session_component::inw(unsigned short address) /* check boundaries */ if (!_in_bounds(address, sizeof(unsigned short))) return 0; - seL4_X86_IOPort_In16_t v = seL4_X86_IOPort_In16(seL4_CapIOPort, address); + auto const v = seL4_X86_IOPort_In16(Core_cspace::io_port_sel(), address); if (v.error == seL4_NoError) return v.result; - Genode::error(__PRETTY_FUNCTION__, " failed ", v.error); + error(__PRETTY_FUNCTION__, " failed ", v.error); return 0; } @@ -56,11 +53,11 @@ unsigned Io_port_session_component::inl(unsigned short address) /* check boundaries */ if (!_in_bounds(address, sizeof(unsigned))) return 0; - seL4_X86_IOPort_In32_t v = seL4_X86_IOPort_In32(seL4_CapIOPort, address); + auto const v = seL4_X86_IOPort_In32(Core_cspace::io_port_sel(), address); if (v.error == seL4_NoError) return v.result; - Genode::error(__PRETTY_FUNCTION__, " failed ", v.error); + error(__PRETTY_FUNCTION__, " failed ", v.error); return 0; } @@ -70,10 +67,10 @@ void Io_port_session_component::outb(unsigned short address, unsigned char value /* check boundaries */ if (!_in_bounds(address, sizeof(unsigned char))) return; - int error = seL4_X86_IOPort_Out8(seL4_CapIOPort, address, value); + int result = seL4_X86_IOPort_Out8(Core_cspace::io_port_sel(), address, value); - if (error != seL4_NoError) - Genode::error(__PRETTY_FUNCTION__, " failed ", error); + if (result != seL4_NoError) + error(__PRETTY_FUNCTION__, " failed ", result); } @@ -82,10 +79,10 @@ void Io_port_session_component::outw(unsigned short address, unsigned short valu /* check boundaries */ if (!_in_bounds(address, sizeof(unsigned short))) return; - int error = seL4_X86_IOPort_Out16(seL4_CapIOPort, address, value); + int result = seL4_X86_IOPort_Out16(Core_cspace::io_port_sel(), address, value); - if (error != seL4_NoError) - Genode::error(__PRETTY_FUNCTION__, " failed ", error); + if (result != seL4_NoError) + error(__PRETTY_FUNCTION__, " failed ", result); } @@ -94,8 +91,8 @@ void Io_port_session_component::outl(unsigned short address, unsigned value) /* check boundaries */ if (!_in_bounds(address, sizeof(unsigned))) return; - int error = seL4_X86_IOPort_Out32(seL4_CapIOPort, address, value); + int result = seL4_X86_IOPort_Out32(Core_cspace::io_port_sel(), address, value); - if (error != seL4_NoError) - Genode::error(__PRETTY_FUNCTION__, " failed ", error); + if (result != seL4_NoError) + error(__PRETTY_FUNCTION__, " failed ", result); } diff --git a/repos/base-sel4/src/core/spec/x86/irq.cc b/repos/base-sel4/src/core/spec/x86/irq.cc index 2ea442911a..e0f6c9715c 100644 --- a/repos/base-sel4/src/core/spec/x86/irq.cc +++ b/repos/base-sel4/src/core/spec/x86/irq.cc @@ -4,12 +4,16 @@ * \date 2017-07-07 */ +/* core includes */ #include #include -long Genode::Irq_object::_associate(Irq_session::Trigger const &irq_trigger, - Irq_session::Polarity const &irq_polarity) +using namespace Core; + + +long Irq_object::_associate(Irq_session::Trigger const &irq_trigger, + Irq_session::Polarity const &irq_polarity) { enum { IRQ_EDGE = 0, IRQ_LEVEL = 1 }; enum { IRQ_HIGH = 0, IRQ_LOW = 1 }; diff --git a/repos/base-sel4/src/core/spec/x86/platform_services.cc b/repos/base-sel4/src/core/spec/x86/platform_services.cc index b542eef89a..2e779a438d 100644 --- a/repos/base-sel4/src/core/spec/x86/platform_services.cc +++ b/repos/base-sel4/src/core/spec/x86/platform_services.cc @@ -20,10 +20,10 @@ /* * Add x86 specific services */ -void Genode::platform_add_local_services(Rpc_entrypoint &ep, - Sliced_heap &heap, - Registry &services, - Trace::Source_registry &trace_sources) +void Core::platform_add_local_services(Rpc_entrypoint &ep, + Sliced_heap &heap, + Registry &services, + Core::Trace::Source_registry &trace_sources) { static Vm_root vm_root(ep, heap, core_env().ram_allocator(), core_env().local_rm(), trace_sources); diff --git a/repos/base-sel4/src/core/spec/x86/platform_thread.cc b/repos/base-sel4/src/core/spec/x86/platform_thread.cc index 7da93a0e75..14057cd21d 100644 --- a/repos/base-sel4/src/core/spec/x86/platform_thread.cc +++ b/repos/base-sel4/src/core/spec/x86/platform_thread.cc @@ -14,23 +14,25 @@ #include #include -using Genode::Phys_allocator; -using Genode::Allocator; +using namespace Core; -Phys_allocator& Genode::phys_alloc_16k(Allocator * core_mem_alloc) + +Phys_allocator &Core::phys_alloc_16k(Allocator *core_mem_alloc) { - static Genode::Phys_allocator phys_alloc_16k(core_mem_alloc); + static Phys_allocator phys_alloc_16k(core_mem_alloc); return phys_alloc_16k; } -void Genode::Platform_thread::affinity(Affinity::Location const location) + +void Platform_thread::affinity(Affinity::Location const location) { seL4_Error const res = seL4_TCB_SetAffinity(tcb_sel().value(), location.xpos()); if (res == seL4_NoError) _location = location; } -bool Genode::Thread_info::init_vcpu(Platform &platform, Cap_sel ept) + +bool Thread_info::init_vcpu(Platform &platform, Cap_sel ept) { enum { PAGES_16K = (1UL << Vcpu_kobj::SIZE_LOG2) / 4096 }; diff --git a/repos/base-sel4/src/core/spec/x86/vm_session_component.cc b/repos/base-sel4/src/core/spec/x86/vm_session_component.cc index b241430fcb..510f59cd1f 100644 --- a/repos/base-sel4/src/core/spec/x86/vm_session_component.cc +++ b/repos/base-sel4/src/core/spec/x86/vm_session_component.cc @@ -22,8 +22,7 @@ #include #include - -using namespace Genode; +using namespace Core; /******************************** @@ -41,7 +40,7 @@ void Vm_session_component::Vcpu::_free_up() if (ret == seL4_NoError) platform_specific().core_sel_alloc().free(_notification); else - Genode::error(__func__, " cnode delete error ", ret); + error(__func__, " cnode delete error ", ret); } } @@ -53,7 +52,7 @@ Vm_session_component::Vcpu::Vcpu(Rpc_entrypoint &ep, : _ep(ep), _ram_alloc(ram_alloc), - _ds_cap (_ram_alloc.alloc(align_addr(sizeof(Genode::Vcpu_state), 12), + _ds_cap (_ram_alloc.alloc(align_addr(sizeof(Vcpu_state), 12), Cache::CACHED)) { try { @@ -186,7 +185,7 @@ Vm_session_component::~Vm_session_component() if (!_map.any_block_addr(&out_addr)) break; - detach(out_addr); + detach_at(out_addr); } if (_vm_page_table.value()) @@ -209,7 +208,7 @@ Capability Vm_session_component::create_vcpu(Thread_cap return; /* code to revert partial allocations in case of Out_of_ram/_quota */ - auto free_up = [&] () { if (vcpu) destroy(_heap, vcpu); }; + auto free_up = [&] { if (vcpu) destroy(_heap, vcpu); }; try { vcpu = new (_heap) Registered(_vcpus, @@ -232,7 +231,7 @@ Capability Vm_session_component::create_vcpu(Thread_cap free_up(); throw; } catch (...) { - Genode::error("unexpected exception occurred"); + error("unexpected exception occurred"); free_up(); return; } @@ -248,25 +247,31 @@ void Vm_session_component::_attach_vm_memory(Dataspace_component &dsc, addr_t const guest_phys, Attach_attr const attribute) { - Vm_space::Map_attr const attr { + Vm_space::Map_attr const attr_noflush { .cached = (dsc.cacheability() == CACHED), .write_combined = (dsc.cacheability() == WRITE_COMBINED), .writeable = dsc.writeable() && attribute.writeable, .executable = attribute.executable, .flush_support = false }; + Vm_space::Map_attr const attr_flush { + .cached = (dsc.cacheability() == CACHED), + .write_combined = (dsc.cacheability() == WRITE_COMBINED), + .writeable = dsc.writeable() && attribute.writeable, + .executable = attribute.executable, + .flush_support = true }; + Flexpage_iterator flex(dsc.phys_addr() + attribute.offset, attribute.size, guest_phys, attribute.size, guest_phys); Flexpage page = flex.page(); while (page.valid()) { - enum { NO_FLUSH = false, FLUSH = true }; try { try { _vm_space.alloc_guest_page_tables(page.hotspot, 1 << page.log2_order); _vm_space.map_guest(page.addr, page.hotspot, - (1 << page.log2_order) / 4096, attr); + (1 << page.log2_order) / 4096, attr_noflush); } catch (Page_table_registry::Mapping_cache_full full) { if (full.reason == Page_table_registry::Mapping_cache_full::MEMORY) { if (_ram_quota_guard().limit().value > 4 * 1024 * 1024) @@ -279,14 +284,14 @@ void Vm_session_component::_attach_vm_memory(Dataspace_component &dsc, return; } } catch (Vm_space::Selector_allocator::Out_of_indices) { - Genode::warning("run out of indices - flush all - cap=", - _cap_quota_guard().used(), "/", - _cap_quota_guard().avail(), "/", - _cap_quota_guard().limit(), " ram=", - _ram_quota_guard().used(), "/", - _ram_quota_guard().avail(), "/", - _ram_quota_guard().limit(), " guest=", - Genode::Hex(0UL - _map.avail())); + warning("run out of indices - flush all - cap=", + _cap_quota_guard().used(), "/", + _cap_quota_guard().avail(), "/", + _cap_quota_guard().limit(), " ram=", + _ram_quota_guard().used(), "/", + _ram_quota_guard().avail(), "/", + _ram_quota_guard().limit(), " guest=", + Hex(0UL - _map.avail())); /* drop all attachment to limit ram usage of this session */ while (true) { @@ -295,13 +300,13 @@ void Vm_session_component::_attach_vm_memory(Dataspace_component &dsc, if (!_map.any_block_addr(&out_addr)) break; - detach(out_addr); + detach_at(out_addr); } _vm_space.map_guest(page.addr, page.hotspot, - (1 << page.log2_order) / 4096, attr); + (1 << page.log2_order) / 4096, attr_flush); } catch (Vm_space::Alloc_page_table_failed) { - Genode::error("alloc page table failed"); + error("alloc page table failed"); return; } diff --git a/repos/base-sel4/src/core/spec/x86/vm_space.cc b/repos/base-sel4/src/core/spec/x86/vm_space.cc index ed06ab9f80..9016120cc5 100644 --- a/repos/base-sel4/src/core/spec/x86/vm_space.cc +++ b/repos/base-sel4/src/core/spec/x86/vm_space.cc @@ -14,10 +14,13 @@ /* core includes */ #include -long Genode::Vm_space::_map_page(Genode::Cap_sel const &idx, - Genode::addr_t const virt, - Map_attr const map_attr, - bool const ept) +using namespace Core; + + +long Vm_space::_map_page(Cap_sel const &idx, + addr_t const virt, + Map_attr const map_attr, + bool const ept) { seL4_X86_Page const service = _idx_to_sel(idx.value()).value(); seL4_X86_PageDirectory const pd = _pd_sel.value(); @@ -38,14 +41,13 @@ long Genode::Vm_space::_map_page(Genode::Cap_sel const &idx, return seL4_X86_Page_Map(service, pd, virt, rights, attr); } -long Genode::Vm_space::_unmap_page(Genode::Cap_sel const &idx) +long Vm_space::_unmap_page(Cap_sel const &idx) { seL4_X86_Page const service = _idx_to_sel(idx.value()).value(); return seL4_X86_Page_Unmap(service); } -long Genode::Vm_space::_invalidate_page(Genode::Cap_sel const &, - seL4_Word const, seL4_Word const) +long Vm_space::_invalidate_page(Cap_sel const &, seL4_Word const, seL4_Word const) { return seL4_NoError; } @@ -85,32 +87,31 @@ struct Ept_page_map_kobj static char const *name() { return "ept page-map level-4 table"; } }; -static long map_page_table(Genode::Cap_sel const pagetable, - Genode::Cap_sel const vroot, - Genode::addr_t const virt) +static long map_page_table(Cap_sel const pagetable, + Cap_sel const vroot, + addr_t const virt) { return seL4_X86_EPTPT_Map(pagetable.value(), vroot.value(), virt, seL4_X86_Default_VMAttributes); } -static long map_pdpt(Genode::Cap_sel const pdpt, - Genode::Cap_sel const vroot, - Genode::addr_t const virt) +static long map_pdpt(Cap_sel const pdpt, + Cap_sel const vroot, + addr_t const virt) { return seL4_X86_EPTPDPT_Map(pdpt.value(), vroot.value(), virt, seL4_X86_Default_VMAttributes); } -static long map_directory(Genode::Cap_sel const pd, - Genode::Cap_sel const vroot, - Genode::addr_t const virt) +static long map_directory(Cap_sel const pd, + Cap_sel const vroot, + addr_t const virt) { return seL4_X86_EPTPD_Map(pd.value(), vroot.value(), virt, seL4_X86_Default_VMAttributes); } -void Genode::Vm_space::unsynchronized_alloc_guest_page_tables(addr_t const start, - addr_t size) +void Vm_space::unsynchronized_alloc_guest_page_tables(addr_t const start, addr_t size) { addr_t constexpr PAGE_TABLE_AREA = 1UL << EPT_PAGE_TABLE_LOG2_SIZE; addr_t virt = start & ~(PAGE_TABLE_AREA - 1); diff --git a/repos/base-sel4/src/core/spec/x86_32/arch_kernel_object.h b/repos/base-sel4/src/core/spec/x86_32/arch_kernel_object.h deleted file mode 100644 index 1075b4003c..0000000000 --- a/repos/base-sel4/src/core/spec/x86_32/arch_kernel_object.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * \brief Utilities for creating seL4 kernel objects - * \author Norman Feske - * \date 2015-05-08 - */ - -/* - * Copyright (C) 2015-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _CORE__X86_32_ARCH_KERNEL_OBJECT_H_ -#define _CORE__X86_32_ARCH_KERNEL_OBJECT_H_ - -#include -#include - -namespace Genode { - - Phys_allocator &phys_alloc_16k(Allocator * core_mem_alloc = nullptr); - - enum { - PAGE_TABLE_LOG2_SIZE = 22 /* 4M region */ - }; - - struct Page_table_kobj - { - enum { SEL4_TYPE = seL4_X86_PageTableObject, SIZE_LOG2 = 12 }; - static char const *name() { return "page table"; } - }; - - - struct Page_directory_kobj - { - enum { SEL4_TYPE = seL4_X86_PageDirectoryObject, SIZE_LOG2 = 12 }; - static char const *name() { return "page directory"; } - }; - - struct Vcpu_kobj - { - enum { SEL4_TYPE = seL4_X86_VCPUObject, SIZE_LOG2 = 14 }; - static char const *name() { return "vcpu"; } - }; - - struct Ept_kobj - { - enum { SEL4_TYPE = seL4_X86_EPTPML4Object, SIZE_LOG = 12 }; - static char const *name() { return "ept pml4"; } - }; -}; - -#endif /* _CORE__X86_32_ARCH_KERNEL_OBJECT_H_ */ diff --git a/repos/base-sel4/src/core/spec/x86_32/boot_info.cc b/repos/base-sel4/src/core/spec/x86_32/boot_info.cc deleted file mode 100644 index e0d6b4e824..0000000000 --- a/repos/base-sel4/src/core/spec/x86_32/boot_info.cc +++ /dev/null @@ -1,30 +0,0 @@ -/* - * \brief Access to seL4 boot info - * \author Norman Feske - * \date 2015-05-04 - */ - -/* - * Copyright (C) 2015-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -/* Genode includes */ -#include - -/* core includes */ -#include - - -/* provided by the assembly startup code */ -extern Genode::addr_t __initial_bx; - -/** - * Obtain seL4 boot info structure - */ -seL4_BootInfo const & Genode::sel4_boot_info() -{ - return *(seL4_BootInfo const *)__initial_bx; -} diff --git a/repos/base-sel4/src/core/spec/x86_32/platform.cc b/repos/base-sel4/src/core/spec/x86_32/platform.cc deleted file mode 100644 index 006aa2560e..0000000000 --- a/repos/base-sel4/src/core/spec/x86_32/platform.cc +++ /dev/null @@ -1,88 +0,0 @@ -/* - * \brief Platform interface implementation - x86_32 specific - * \author Norman Feske - * \date 2015-05-01 - */ - -/* - * Copyright (C) 2015-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -/* base includes */ -#include - -/* core includes */ -#include -#include - -#include -#include "arch_kernel_object.h" - -seL4_Word Genode::Untyped_memory::smallest_page_type() { return seL4_X86_4K; } - -void Genode::Platform::init_sel4_ipc_buffer() -{ - asm volatile ("movl %0, %%fs" :: "r"(IPCBUF_GDT_SELECTOR) : "memory"); -} - -long Genode::Platform::_unmap_page_frame(Cap_sel const &sel) { - return seL4_X86_Page_Unmap(sel.value()); } - -void Genode::Platform::_init_core_page_table_registry() -{ - seL4_BootInfo const &bi = sel4_boot_info(); - - addr_t virt_addr = (addr_t)(&_prog_img_beg); - unsigned sel = bi.userImagePaging.start; - - /* we don't know the physical location of some objects XXX */ - enum { XXX_PHYS_UNKNOWN = ~0UL }; - - /* - * Register initial page tables - */ - for (; sel < bi.userImagePaging.end; sel++) { - _core_page_table_registry.insert_page_table(virt_addr, Cap_sel(sel), - XXX_PHYS_UNKNOWN, - PAGE_TABLE_LOG2_SIZE); - virt_addr += 1024 * get_page_size(); - } - - /* initialize 16k memory allocator */ - phys_alloc_16k(&core_mem_alloc()); - - /* reserve some memory for VCPUs - must be 16k */ - enum { MAX_VCPU_COUNT = 16 }; - addr_t const max_pd_mem = MAX_VCPU_COUNT * (1UL << Vcpu_kobj::SIZE_LOG2); - - _initial_untyped_pool.turn_into_untyped_object(Core_cspace::TOP_CNODE_UNTYPED_16K, - [&] (addr_t const phys, addr_t const size, bool) { - phys_alloc_16k().add_range(phys, size); - _unused_phys_alloc.remove_range(phys, size); - }, - Vcpu_kobj::SIZE_LOG2, max_pd_mem); - - log(":phys_mem_16k: ", phys_alloc_16k()); - /* - * Register initial page frames - * - actually we don't use them in core -> skip - */ -#if 0 - addr_t const modules_start = reinterpret_cast(&_boot_modules_binaries_begin); - addr_t const modules_end = reinterpret_cast(&_boot_modules_binaries_end); - - virt_addr = (addr_t)(&_prog_img_beg); - for (unsigned sel = bi.userImageFrames.start; - sel < bi.userImageFrames.end; - sel++, virt_addr += get_page_size()) { - /* skip boot modules */ - if (modules_start <= virt_addr && virt_addr <= modules_end) - continue; - - _core_page_table_registry.insert_page_table_entry(virt_addr, sel); - } -#endif -} diff --git a/repos/base-sel4/src/core/spec/x86_32/platform_pd.cc b/repos/base-sel4/src/core/spec/x86_32/platform_pd.cc deleted file mode 100644 index 358cabb79d..0000000000 --- a/repos/base-sel4/src/core/spec/x86_32/platform_pd.cc +++ /dev/null @@ -1,50 +0,0 @@ -/* - * \brief Protection-domain facility - * \author Norman Feske - * \date 2015-05-01 - */ - -/* - * Copyright (C) 2015-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -/* core includes */ -#include - -#include "arch_kernel_object.h" - - -Genode::addr_t Genode::Platform_pd::_init_page_directory() const -{ - addr_t const phys_addr = Untyped_memory::alloc_page(platform().ram_alloc()); - seL4_Untyped const service = Untyped_memory::untyped_sel(phys_addr).value(); - - create(service, - platform_specific().core_cnode().sel(), - _page_directory_sel); - - long ret = seL4_X86_ASIDPool_Assign(platform_specific().asid_pool().value(), - _page_directory_sel.value()); - - if (ret != seL4_NoError) - error("seL4_X86_ASIDPool_Assign returned ", ret); - - return phys_addr; -} - - -void Genode::Platform_pd::_deinit_page_directory(addr_t phys_addr) const -{ - int ret = seL4_CNode_Delete(seL4_CapInitThreadCNode, - _page_directory_sel.value(), 32); - if (ret != seL4_NoError) { - error(__FUNCTION__, ": could not free ASID entry, " - "leaking physical memory ", ret); - return; - } - - Untyped_memory::free_page(platform().ram_alloc(), phys_addr); -} diff --git a/repos/base-sel4/src/core/spec/x86_32/thread.cc b/repos/base-sel4/src/core/spec/x86_32/thread.cc deleted file mode 100644 index 191f8a2b7a..0000000000 --- a/repos/base-sel4/src/core/spec/x86_32/thread.cc +++ /dev/null @@ -1,84 +0,0 @@ -/* - * \brief Utilities for thread creation on seL4 - * \author Norman Feske - * \date 2015-05-12 - * - * This file is used by both the core-specific implementation of the Thread API - * and the platform-thread implementation for managing threads outside of core. - */ - -/* - * Copyright (C) 2015-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -/* base includes */ -#include - -/* core includes */ -#include -#include - -void Genode::start_sel4_thread(Cap_sel tcb_sel, addr_t ip, addr_t sp, - unsigned cpu) -{ - /* set register values for the instruction pointer and stack pointer */ - seL4_UserContext regs; - Genode::memset(®s, 0, sizeof(regs)); - size_t const num_regs = sizeof(regs)/sizeof(seL4_Word); - - regs.eip = ip; - regs.esp = sp; - regs.fs = IPCBUF_GDT_SELECTOR; - - long const ret = seL4_TCB_WriteRegisters(tcb_sel.value(), false, 0, - num_regs, ®s); - ASSERT(ret == 0); - - affinity_sel4_thread(tcb_sel, cpu); - - seL4_TCB_Resume(tcb_sel.value()); -} - -void Genode::affinity_sel4_thread(Cap_sel const &tcb_sel, unsigned cpu) -{ - seL4_TCB_SetAffinity(tcb_sel.value(), cpu); -} - -Genode::Thread_state Genode::Platform_thread::state() -{ - seL4_TCB const thread = _info.tcb_sel.value(); - seL4_Bool const suspend_source = false; - seL4_Uint8 const arch_flags = 0; - seL4_UserContext registers; - seL4_Word const register_count = sizeof(registers) / sizeof(registers.eip); - - long const ret = seL4_TCB_ReadRegisters(thread, suspend_source, arch_flags, - register_count, ®isters); - if (ret != seL4_NoError) { - error("reading thread state ", ret); - throw Cpu_thread::State_access_failed(); - } - - Thread_state state; - Genode::memset(&state, 0, sizeof(state)); - - state.ip = registers.eip; - state.sp = registers.esp; - state.edi = registers.edi; - state.esi = registers.esi; - state.ebp = registers.ebp; - state.ebx = registers.ebx; - state.edx = registers.edx; - state.ecx = registers.ecx; - state.eax = registers.eax; - state.gs = registers.gs; - state.fs = registers.fs; - state.eflags = registers.eflags; - state.trapno = 0; /* XXX detect/track if in exception and report here */ - /* registers.tls_base unused */ - - return state; -} diff --git a/repos/base-sel4/src/core/spec/x86_32/vm_space.cc b/repos/base-sel4/src/core/spec/x86_32/vm_space.cc deleted file mode 100644 index c67a953e01..0000000000 --- a/repos/base-sel4/src/core/spec/x86_32/vm_space.cc +++ /dev/null @@ -1,44 +0,0 @@ -/* - * \brief Virtual-memory space - * \author Norman Feske - * \date 2015-05-04 - */ - -/* - * Copyright (C) 2015-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -/* core includes */ -#include - -#include "arch_kernel_object.h" - -static long map_page_table(Genode::Cap_sel const pagetable, - Genode::Cap_sel const vroot, - Genode::addr_t const virt) -{ - return seL4_X86_PageTable_Map(pagetable.value(), vroot.value(), virt, - seL4_X86_Default_VMAttributes); -} - -void Genode::Vm_space::unsynchronized_alloc_page_tables(addr_t const start, - addr_t const size) -{ - addr_t constexpr PAGE_TABLE_AREA = 1UL << PAGE_TABLE_LOG2_SIZE; - addr_t virt = start & ~(PAGE_TABLE_AREA - 1); - for (; virt < start + size; virt += PAGE_TABLE_AREA) { - - if (_page_table_registry.page_table_at(virt, PAGE_TABLE_LOG2_SIZE)) - continue; - - addr_t phys = 0; - - /* 4 MB range - page table */ - Cap_sel const pt = _alloc_and_map(virt, map_page_table, phys); - _page_table_registry.insert_page_table(virt, pt, phys, - PAGE_TABLE_LOG2_SIZE); - } -} diff --git a/repos/base-sel4/src/core/spec/x86_64/arch_kernel_object.h b/repos/base-sel4/src/core/spec/x86_64/arch_kernel_object.h index bc3ce04ae0..ccf2673585 100644 --- a/repos/base-sel4/src/core/spec/x86_64/arch_kernel_object.h +++ b/repos/base-sel4/src/core/spec/x86_64/arch_kernel_object.h @@ -17,7 +17,7 @@ #include #include -namespace Genode { +namespace Core { Phys_allocator &phys_alloc_16k(Allocator * core_mem_alloc = nullptr); diff --git a/repos/base-sel4/src/core/spec/x86_64/boot_info.cc b/repos/base-sel4/src/core/spec/x86_64/boot_info.cc index f176d67cfc..cfa977497f 100644 --- a/repos/base-sel4/src/core/spec/x86_64/boot_info.cc +++ b/repos/base-sel4/src/core/spec/x86_64/boot_info.cc @@ -17,14 +17,16 @@ /* core includes */ #include +using namespace Core; + /* provided by the assembly startup code */ -extern Genode::addr_t __initial_di; +extern addr_t __initial_di; /** * Obtain seL4 boot info structure */ -seL4_BootInfo const & Genode::sel4_boot_info() +seL4_BootInfo const &Core::sel4_boot_info() { return *(seL4_BootInfo const *)__initial_di; } diff --git a/repos/base-sel4/src/core/spec/x86_64/platform.cc b/repos/base-sel4/src/core/spec/x86_64/platform.cc index 9e15b8e274..1a2052b1d5 100644 --- a/repos/base-sel4/src/core/spec/x86_64/platform.cc +++ b/repos/base-sel4/src/core/spec/x86_64/platform.cc @@ -21,15 +21,28 @@ #include #include "arch_kernel_object.h" +using namespace Core; -seL4_Word Genode::Untyped_memory::smallest_page_type() { return seL4_X86_4K; } -void Genode::Platform::init_sel4_ipc_buffer() { } +seL4_Word Untyped_memory::smallest_page_type() { return seL4_X86_4K; } -long Genode::Platform::_unmap_page_frame(Cap_sel const &sel) { + +void Platform::init_sel4_ipc_buffer() +{ + /* + * Setup tls pointer such, that it points to the (kernel created) core + * main thread IPC buffer. The fs register is used in seL4_GetIPCBuffer(). + */ + seL4_BootInfo const &bi = sel4_boot_info(); + seL4_SetTLSBase((unsigned long)&bi.ipcBuffer); +} + + +long Platform::_unmap_page_frame(Cap_sel const &sel) { return seL4_X86_Page_Unmap(sel.value()); } -void Genode::Platform::_init_core_page_table_registry() + +void Platform::_init_core_page_table_registry() { seL4_BootInfo const &bi = sel4_boot_info(); @@ -69,31 +82,37 @@ void Genode::Platform::_init_core_page_table_registry() addr_t const max_pd_mem = MAX_VCPU_COUNT * (1UL << Vcpu_kobj::SIZE_LOG2); _initial_untyped_pool.turn_into_untyped_object(Core_cspace::TOP_CNODE_UNTYPED_16K, - [&] (addr_t const phys, addr_t const size, bool) { + [&] (addr_t const phys, addr_t const size, bool const device_memory) { + + if (device_memory) + return false; + phys_alloc_16k().add_range(phys, size); _unused_phys_alloc.remove_range(phys, size); + + return true; }, Vcpu_kobj::SIZE_LOG2, max_pd_mem); log(":phys_mem_16k: ", phys_alloc_16k()); - - /* - * Register initial page frames - * - actually we don't use them in core -> skip - */ -#if 0 - addr_t const modules_start = reinterpret_cast(&_boot_modules_binaries_begin); - addr_t const modules_end = reinterpret_cast(&_boot_modules_binaries_end); - - virt_addr = (addr_t)(&_prog_img_beg); - for (unsigned sel = bi.userImageFrames.start; - sel < bi.userImageFrames.end; - sel++, virt_addr += get_page_size()) { - /* skip boot modules */ - if (modules_start <= virt_addr && virt_addr <= modules_end) - continue; - - _core_page_table_registry.insert_page_table_entry(virt_addr, sel); - } -#endif +} + + +void Platform::_init_io_ports() +{ + enum { PORTS = 0x10000, PORT_FIRST = 0, PORT_LAST = PORTS - 1 }; + + /* I/O port allocator (only meaningful for x86) */ + _io_port_alloc.add_range(PORT_FIRST, PORTS); + + /* create I/O port capability used by io_port_session_support.cc */ + auto const root = _core_cnode.sel().value(); + auto const index = Core_cspace::io_port_sel(); + auto const depth = CONFIG_ROOT_CNODE_SIZE_BITS; + + auto const result = seL4_X86_IOPortControl_Issue(seL4_CapIOPortControl, + PORT_FIRST, PORT_LAST, + root, index, depth); + if (result != 0) + error("IO Port access not available"); } diff --git a/repos/base-sel4/src/core/spec/x86_64/platform_pd.cc b/repos/base-sel4/src/core/spec/x86_64/platform_pd.cc index bf14ba27ee..2c7d1c69ee 100644 --- a/repos/base-sel4/src/core/spec/x86_64/platform_pd.cc +++ b/repos/base-sel4/src/core/spec/x86_64/platform_pd.cc @@ -16,7 +16,10 @@ #include "arch_kernel_object.h" -Genode::addr_t Genode::Platform_pd::_init_page_directory() const +using namespace Core; + + +addr_t Platform_pd::_init_page_directory() const { addr_t const phys_addr = Untyped_memory::alloc_page(platform().ram_alloc()); seL4_Untyped const service = Untyped_memory::untyped_sel(phys_addr).value(); @@ -33,7 +36,7 @@ Genode::addr_t Genode::Platform_pd::_init_page_directory() const return phys_addr; } -void Genode::Platform_pd::_deinit_page_directory(addr_t phys_addr) const +void Platform_pd::_deinit_page_directory(addr_t phys_addr) const { int ret = seL4_CNode_Delete(seL4_CapInitThreadCNode, _page_directory_sel.value(), 32); diff --git a/repos/base-sel4/src/core/spec/x86_64/thread.cc b/repos/base-sel4/src/core/spec/x86_64/thread.cc index dce39cc3f7..8ebb022f4a 100644 --- a/repos/base-sel4/src/core/spec/x86_64/thread.cc +++ b/repos/base-sel4/src/core/spec/x86_64/thread.cc @@ -15,18 +15,22 @@ */ /* base includes */ +#include #include /* core includes */ #include #include -void Genode::start_sel4_thread(Cap_sel tcb_sel, addr_t ip, addr_t sp, - unsigned cpu) +using namespace Core; + + +void Core::start_sel4_thread(Cap_sel tcb_sel, addr_t ip, addr_t sp, + unsigned cpu, addr_t const virt_utcb) { /* set register values for the instruction pointer and stack pointer */ seL4_UserContext regs; - Genode::memset(®s, 0, sizeof(regs)); + memset(®s, 0, sizeof(regs)); size_t const num_regs = sizeof(regs)/sizeof(seL4_Word); regs.rip = ip; @@ -38,15 +42,25 @@ void Genode::start_sel4_thread(Cap_sel tcb_sel, addr_t ip, addr_t sp, affinity_sel4_thread(tcb_sel, cpu); + /* + * Set tls pointer to location, where ipcbuffer address is stored, so + * that it can be used by register fs (seL4_GetIPCBuffer()) + */ + auto error = seL4_TCB_SetTLSBase(tcb_sel.value(), + virt_utcb + Native_utcb::tls_ipcbuffer_offset); + ASSERT(not error); + seL4_TCB_Resume(tcb_sel.value()); } -void Genode::affinity_sel4_thread(Cap_sel const &tcb_sel, unsigned cpu) + +void Core::affinity_sel4_thread(Cap_sel const &tcb_sel, unsigned cpu) { seL4_TCB_SetAffinity(tcb_sel.value(), cpu); } -Genode::Thread_state Genode::Platform_thread::state() + +Thread_state Platform_thread::state() { seL4_TCB const thread = _info.tcb_sel.value(); seL4_Bool const suspend_source = false; @@ -56,33 +70,30 @@ Genode::Thread_state Genode::Platform_thread::state() long const ret = seL4_TCB_ReadRegisters(thread, suspend_source, arch_flags, register_count, ®isters); - if (ret != seL4_NoError) { - error("reading thread state ", ret); - throw Cpu_thread::State_access_failed(); - } + if (ret != seL4_NoError) + return { .state = Thread_state::State::UNAVAILABLE, .cpu = { } }; - Thread_state state; - Genode::memset(&state, 0, sizeof(state)); + Thread_state state { }; - state.ip = registers.rip; - state.sp = registers.rsp; - state.rdi = registers.rdi; - state.rsi = registers.rsi; - state.rbp = registers.rbp; - state.rbx = registers.rbx; - state.rdx = registers.rdx; - state.rcx = registers.rcx; - state.rax = registers.rax; - state.r8 = registers.r8; - state.r9 = registers.r9; - state.r10 = registers.r10; - state.r11 = registers.r11; - state.r12 = registers.r12; - state.r13 = registers.r13; - state.r14 = registers.r14; - state.r15 = registers.r15; - state.eflags = registers.rflags; - state.trapno = 0; /* XXX detect/track if in exception and report here */ + state.cpu.ip = registers.rip; + state.cpu.sp = registers.rsp; + state.cpu.rdi = registers.rdi; + state.cpu.rsi = registers.rsi; + state.cpu.rbp = registers.rbp; + state.cpu.rbx = registers.rbx; + state.cpu.rdx = registers.rdx; + state.cpu.rcx = registers.rcx; + state.cpu.rax = registers.rax; + state.cpu.r8 = registers.r8; + state.cpu.r9 = registers.r9; + state.cpu.r10 = registers.r10; + state.cpu.r11 = registers.r11; + state.cpu.r12 = registers.r12; + state.cpu.r13 = registers.r13; + state.cpu.r14 = registers.r14; + state.cpu.r15 = registers.r15; + state.cpu.eflags = registers.rflags; + state.cpu.trapno = 0; /* XXX detect/track if in exception and report here */ /* registers.tls_base unused */ return state; diff --git a/repos/base-sel4/src/core/spec/x86_64/vm_space.cc b/repos/base-sel4/src/core/spec/x86_64/vm_space.cc index de206eeaa1..8e1d33380b 100644 --- a/repos/base-sel4/src/core/spec/x86_64/vm_space.cc +++ b/repos/base-sel4/src/core/spec/x86_64/vm_space.cc @@ -16,32 +16,35 @@ #include "arch_kernel_object.h" -static long map_page_table(Genode::Cap_sel const pagetable, - Genode::Cap_sel const vroot, - Genode::addr_t const virt) +using namespace Core; + + +static long map_page_table(Cap_sel const pagetable, + Cap_sel const vroot, + addr_t const virt) { return seL4_X86_PageTable_Map(pagetable.value(), vroot.value(), virt, seL4_X86_Default_VMAttributes); } -static long map_pdpt(Genode::Cap_sel const pdpt, - Genode::Cap_sel const vroot, +static long map_pdpt(Cap_sel const pdpt, + Cap_sel const vroot, seL4_Word const virt) { return seL4_X86_PDPT_Map(pdpt.value(), vroot.value(), virt, seL4_X86_Default_VMAttributes); } -static long map_directory(Genode::Cap_sel const pd, - Genode::Cap_sel const vroot, +static long map_directory(Cap_sel const pd, + Cap_sel const vroot, seL4_Word const virt) { return seL4_X86_PageDirectory_Map(pd.value(), vroot.value(), virt, seL4_X86_Default_VMAttributes); } -void Genode::Vm_space::unsynchronized_alloc_page_tables(addr_t const start, - addr_t const size) +void Vm_space::unsynchronized_alloc_page_tables(addr_t const start, + addr_t const size) { addr_t constexpr PAGE_TABLE_AREA = 1UL << PAGE_TABLE_LOG2_SIZE; addr_t virt = start & ~(PAGE_TABLE_AREA - 1); diff --git a/repos/base-sel4/src/core/stack_area.cc b/repos/base-sel4/src/core/stack_area.cc index ac0bebe97b..c687a89d16 100644 --- a/repos/base-sel4/src/core/stack_area.cc +++ b/repos/base-sel4/src/core/stack_area.cc @@ -15,7 +15,6 @@ /* Genode includes */ #include #include -#include #include #include @@ -47,53 +46,53 @@ class Stack_area_region_map : public Region_map { private: - using Ds_slab = Synced_allocator >; - Ds_slab _ds_slab { platform().core_mem_alloc() }; + Ds_slab _ds_slab { Core::platform().core_mem_alloc() }; public: /** * Allocate and attach on-the-fly backing store to the stack area */ - Local_addr attach(Dataspace_capability, size_t size, off_t, - bool, Local_addr local_addr, bool, bool) override + Attach_result attach(Dataspace_capability, Attr const &attr) override { - size = round_page(size); + using namespace Core; + + size_t const size = round_page(attr.size); + size_t const num_pages = size >> get_page_size_log2(); /* allocate physical memory */ - Range_allocator &phys_alloc = platform_specific().ram_alloc(); - size_t const num_pages = size >> get_page_size_log2(); + Range_allocator &phys_alloc = Core::platform_specific().ram_alloc(); addr_t const phys = Untyped_memory::alloc_pages(phys_alloc, num_pages); Untyped_memory::convert_to_page_frames(phys, num_pages); Dataspace_component &ds = *new (&_ds_slab) Dataspace_component(size, 0, phys, CACHED, true, 0); - addr_t const core_local_addr = - stack_area_virtual_base() + (addr_t)local_addr; + addr_t const core_local_addr = stack_area_virtual_base() + attr.at; if (!map_local(ds.phys_addr(), core_local_addr, ds.size() >> get_page_size_log2())) { error(__func__, ": could not map phys ", Hex(ds.phys_addr()), " " "at local ", Hex(core_local_addr)); - return (addr_t)0; + return Attach_error::INVALID_DATASPACE; } ds.assign_core_local_addr((void*)core_local_addr); - return local_addr; + return Range { .start = attr.at, .num_bytes = size }; } - void detach(Local_addr local_addr) override + void detach(addr_t at) override { - using Genode::addr_t; + using namespace Core; - if ((addr_t)local_addr >= stack_area_virtual_size()) + if (at >= stack_area_virtual_size()) return; - addr_t const detach = stack_area_virtual_base() + (addr_t)local_addr; + addr_t const detach = stack_area_virtual_base() + at; addr_t const stack = stack_virtual_size(); addr_t const pages = ((detach & ~(stack - 1)) + stack - detach) >> get_page_size_log2(); @@ -106,9 +105,9 @@ class Stack_area_region_map : public Region_map void fault_handler(Signal_context_capability) override { } - State state() override { return State(); } + Fault fault() override { return { }; } - Dataspace_capability dataspace() override { return Dataspace_capability(); } + Dataspace_capability dataspace() override { return { }; } }; diff --git a/repos/base-sel4/src/core/thread_start.cc b/repos/base-sel4/src/core/thread_start.cc index ba09822c7c..4d4deca40c 100644 --- a/repos/base-sel4/src/core/thread_start.cc +++ b/repos/base-sel4/src/core/thread_start.cc @@ -13,7 +13,6 @@ /* Genode includes */ #include -#include #include /* base-internal includes */ @@ -28,12 +27,12 @@ /* seL4 includes */ #include -using namespace Genode; +using namespace Core; void Thread::_init_platform_thread(size_t, Type type) { - addr_t const utcb_virt_addr = (addr_t)&_stack->utcb(); + Utcb_virt const utcb_virt { (addr_t)&_stack->utcb() }; if (type == MAIN) { native_thread().tcb_sel = seL4_CapInitThreadTCB; @@ -42,12 +41,12 @@ void Thread::_init_platform_thread(size_t, Type type) } Thread_info thread_info; - thread_info.init(utcb_virt_addr, CONFIG_NUM_PRIORITIES - 1); + thread_info.init(utcb_virt, CONFIG_NUM_PRIORITIES - 1); - if (!map_local(thread_info.ipc_buffer_phys, utcb_virt_addr, 1)) { + if (!map_local(thread_info.ipc_buffer_phys.addr, utcb_virt.addr, 1)) { error(__func__, ": could not map IPC buffer " - "phys=", Hex(thread_info.ipc_buffer_phys), " " - "local=%", Hex(utcb_virt_addr)); + "phys=", Hex(thread_info.ipc_buffer_phys.addr), " " + "local=%", Hex(utcb_virt.addr)); } native_thread().tcb_sel = thread_info.tcb_sel.value(); @@ -100,14 +99,17 @@ void Thread::_thread_start() } -void Thread::start() +Thread::Start_result Thread::start() { - start_sel4_thread(Cap_sel(native_thread().tcb_sel), (addr_t)&_thread_start, - (addr_t)stack_top(), _affinity.xpos()); + /* write ipcbuffer address to utcb*/ + utcb()->ipcbuffer(Native_utcb::Virt { addr_t(utcb()) }); - struct Core_trace_source : public Trace::Source::Info_accessor, - private Trace::Control, - private Trace::Source + start_sel4_thread(Cap_sel(native_thread().tcb_sel), (addr_t)&_thread_start, + (addr_t)stack_top(), _affinity.xpos(), addr_t(utcb())); + + struct Core_trace_source : public Core::Trace::Source::Info_accessor, + private Core::Trace::Control, + private Core::Trace::Source { Thread &_thread; @@ -129,17 +131,19 @@ void Thread::start() } - Core_trace_source(Trace::Source_registry ®istry, Thread &t) + Core_trace_source(Core::Trace::Source_registry ®istry, Thread &t) : - Trace::Control(), - Trace::Source(*this, *this), _thread(t) + Core::Trace::Control(), + Core::Trace::Source(*this, *this), _thread(t) { registry.insert(this); } }; new (platform().core_mem_alloc()) - Core_trace_source(Trace::sources(), *this); + Core_trace_source(Core::Trace::sources(), *this); + + return Start_result::OK; } diff --git a/repos/base-sel4/src/include/base/internal/assert.h b/repos/base-sel4/src/include/base/internal/assert.h index 17c1bbbf7d..f6e86e541c 100644 --- a/repos/base-sel4/src/include/base/internal/assert.h +++ b/repos/base-sel4/src/include/base/internal/assert.h @@ -18,18 +18,16 @@ #define _INCLUDE__BASE__INTERNAL__ASSERT_H_ /* Genode includes */ -#include +#include /* base-internal includes */ #include #define ASSERT(e) \ do { if (!(e)) { \ - char line_buf[32]; \ - Genode::snprintf(line_buf, sizeof(line_buf), "%d", __LINE__); \ kernel_debugger_outstring("Assertion failed: " #e "\n"); \ kernel_debugger_outstring(__FILE__ ":"); \ - kernel_debugger_outstring(line_buf); \ + kernel_debugger_outstring(Genode::String<32>(__LINE__).string()); \ kernel_debugger_panic("\n"); \ } \ } while(0) diff --git a/repos/base-sel4/src/include/base/internal/capability_space_sel4.h b/repos/base-sel4/src/include/base/internal/capability_space_sel4.h index 1c414d8b00..4d6320340a 100644 --- a/repos/base-sel4/src/include/base/internal/capability_space_sel4.h +++ b/repos/base-sel4/src/include/base/internal/capability_space_sel4.h @@ -139,7 +139,7 @@ class Genode::Capability_space_sel4 private: - typedef CAP_DATA Data; + using Data = CAP_DATA; /** * Supplement Native_capability::Data with the meta data needed to @@ -147,8 +147,7 @@ class Genode::Capability_space_sel4 */ struct Tree_managed_data : Data, Avl_node { - template - Tree_managed_data(ARGS... args) : Data(args...) { } + Tree_managed_data(auto &&... args) : Data(args...) { } Tree_managed_data() { } @@ -210,8 +209,7 @@ class Genode::Capability_space_sel4 * The arguments following the selector are passed to the constructor * of the 'Native_capability::Data' type. */ - template - Native_capability::Data &create_capability(Cap_sel cap_sel, ARGS... args) + Native_capability::Data &create_capability(Cap_sel cap_sel, auto &&... args) { addr_t const sel = cap_sel.value(); diff --git a/repos/base-sel4/src/include/base/internal/native_utcb.h b/repos/base-sel4/src/include/base/internal/native_utcb.h index a38f761f84..8e62a8bb90 100644 --- a/repos/base-sel4/src/include/base/internal/native_utcb.h +++ b/repos/base-sel4/src/include/base/internal/native_utcb.h @@ -35,6 +35,12 @@ struct Genode::Native_utcb void ep_sel (addr_t sel) { _raw[ELEMENTS - 1] = sel; } void lock_sel(addr_t sel) { _raw[ELEMENTS - 2] = sel; } + + static addr_t constexpr tls_ipcbuffer_offset = (ELEMENTS - 3) * sizeof(_raw[0]); + + struct Virt { addr_t addr; }; + + void ipcbuffer(Virt const virt) { _raw[ELEMENTS - 3] = virt.addr; } }; #endif /* _INCLUDE__BASE__INTERNAL__NATIVE_UTCB_H_ */ diff --git a/repos/base-sel4/src/include/base/internal/raw_write_string.h b/repos/base-sel4/src/include/base/internal/raw_write_string.h index b26e8b4b7c..2bc61fe66c 100644 --- a/repos/base-sel4/src/include/base/internal/raw_write_string.h +++ b/repos/base-sel4/src/include/base/internal/raw_write_string.h @@ -15,8 +15,7 @@ #define _INCLUDE__BASE__INTERNAL__RAW_WRITE_STRING_H_ /* seL4 includes */ -#include -#include +#include namespace Genode { diff --git a/repos/base-sel4/src/include/signal_source/client.h b/repos/base-sel4/src/include/signal_source/client.h index aed4ec5bbf..bb9c5c7143 100644 --- a/repos/base-sel4/src/include/signal_source/client.h +++ b/repos/base-sel4/src/include/signal_source/client.h @@ -18,6 +18,7 @@ #include #include #include +#include namespace Genode { class Signal_source_client; } @@ -38,9 +39,12 @@ class Genode::Signal_source_client : public Rpc_client /** * Constructor */ - Signal_source_client(Capability cap) - : Rpc_client(static_cap_cast(cap)) - { _init_notify(); } + Signal_source_client(Cpu_session &, Capability cap) + : + Rpc_client(static_cap_cast(cap)) + { + _init_notify(); + } /***************************** diff --git a/repos/base-sel4/src/lib/base/arm/cache.cc b/repos/base-sel4/src/lib/base/arm/cache.cc index 331f8b09e3..378a8ec549 100644 --- a/repos/base-sel4/src/lib/base/arm/cache.cc +++ b/repos/base-sel4/src/lib/base/arm/cache.cc @@ -14,19 +14,28 @@ #include #include +/* seL4 includes */ +#include + + void Genode::cache_coherent(Genode::addr_t, Genode::size_t) { - error(__func__, " not implemented for this kernel!"); + seL4_BenchmarkFlushCaches(); } void Genode::cache_clean_invalidate_data(Genode::addr_t, Genode::size_t) { - error(__func__, " not implemented for this kernel!"); + seL4_BenchmarkFlushCaches(); } void Genode::cache_invalidate_data(Genode::addr_t, Genode::size_t) { - error(__func__, " not implemented for this kernel!"); + static bool warned_once; + + if (!warned_once) { + error(__func__, " not implemented for this kernel!"); + warned_once = true; + } } diff --git a/repos/base-sel4/src/lib/base/ipc.cc b/repos/base-sel4/src/lib/base/ipc.cc index fe1a4b1580..f4c79cf5a1 100644 --- a/repos/base-sel4/src/lib/base/ipc.cc +++ b/repos/base-sel4/src/lib/base/ipc.cc @@ -12,7 +12,6 @@ */ /* Genode includes */ -#include #include #include #include diff --git a/repos/base-sel4/src/lib/base/thread_bootstrap.cc b/repos/base-sel4/src/lib/base/thread_bootstrap.cc index 0aa24ebaa1..035b612d58 100644 --- a/repos/base-sel4/src/lib/base/thread_bootstrap.cc +++ b/repos/base-sel4/src/lib/base/thread_bootstrap.cc @@ -17,13 +17,14 @@ /* base-internal includes */ #include +#include /***************************** ** Startup library support ** *****************************/ -void prepare_init_main_thread() { } +void Genode::prepare_init_main_thread() { } /************ @@ -37,3 +38,6 @@ void Genode::Thread::_thread_bootstrap() native_thread().lock_sel = (unsigned)_stack->utcb().lock_sel(); } } + + +void Genode::init_thread_bootstrap(Cpu_session &, Thread_capability) { } diff --git a/repos/base-sel4/src/lib/base/x86/vm.cc b/repos/base-sel4/src/lib/base/x86/vm.cc index 0ced3693af..e263ef9b9a 100644 --- a/repos/base-sel4/src/lib/base/x86/vm.cc +++ b/repos/base-sel4/src/lib/base/x86/vm.cc @@ -1,11 +1,12 @@ /* * \brief Client-side VM session interface * \author Alexander Boettcher + * \author Benjamin Lamowski * \date 2018-08-27 */ /* - * Copyright (C) 2018-2021 Genode Labs GmbH + * Copyright (C) 2018-2023 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -16,6 +17,7 @@ #include #include #include +#include #include #include @@ -36,6 +38,7 @@ using namespace Genode; using Exit_config = Vm_connection::Exit_config; +using Call_with_state = Vm_connection::Call_with_state; struct Sel4_vcpu; @@ -46,7 +49,7 @@ struct Sel4_native_rpc : Rpc_client, Noncopyable Capability _create_vcpu(Vm_connection &vm, Thread_capability &cap) { - return vm.with_upgrade([&] () { + return vm.with_upgrade([&] { return vm.call(cap); }); } @@ -71,11 +74,16 @@ struct Sel4_vcpu : Genode::Thread, Noncopyable private: Vcpu_handler_base &_vcpu_handler; + Vcpu_handler _exit_handler; Vcpu_state _state __attribute__((aligned(0x10))) { }; Semaphore _wake_up { 0 }; Blockade _startup { }; addr_t _recall { 0 }; uint64_t _tsc_offset { 0 }; + Semaphore _state_ready { 0 }; + bool _dispatching { false }; + bool _extra_dispatch_up { false }; + void *_ep_handler { nullptr }; Constructible _rpc { }; @@ -133,7 +141,7 @@ struct Sel4_vcpu : Genode::Thread, Noncopyable /* get selector to call back a vCPU into VMM */ _recall = _stack->utcb().lock_sel(); - Vcpu_state &state = this->state(); + Vcpu_state &state = _state; state.discharge(); /* wait for first user resume() */ @@ -148,9 +156,10 @@ struct Sel4_vcpu : Genode::Thread, Noncopyable state.exit_reason = VMEXIT_STARTUP; _read_sel4_state(service, state); - Genode::Signal_transmitter(_vcpu_handler.signal_cap()).submit(); + _state_ready.up(); + Signal_transmitter(_exit_handler.signal_cap()).submit(); - _vcpu_handler.ready_semaphore().down(); + _exit_handler.ready_semaphore().down(); _wake_up.down(); State local_state { NONE }; @@ -163,7 +172,7 @@ struct Sel4_vcpu : Genode::Thread, Noncopyable { Mutex::Guard guard(_remote_mutex); - local_state = _remote; + local_state = _remote; _remote = NONE; if (local_state == PAUSE) { @@ -192,14 +201,13 @@ struct Sel4_vcpu : Genode::Thread, Noncopyable _read_sel4_state(service, state); - /* notify VM handler */ - Genode::Signal_transmitter(_vcpu_handler.signal_cap()).submit(); + _state_ready.up(); + + if (_extra_dispatch_up) { + _extra_dispatch_up = false; + _exit_handler.ready_semaphore().down(); + } - /* - * Wait until VM handler is really really done, - * otherwise we lose state. - */ - _vcpu_handler.ready_semaphore().down(); continue; } @@ -219,8 +227,18 @@ struct Sel4_vcpu : Genode::Thread, Noncopyable state.discharge(); - if (res != SEL4_VMENTER_RESULT_FAULT) + /* + * If a VMEXIT_RECALL is dispatched here, it comes from a + * pause request sent by an already running asynchronous signal + * handler. + * In that case, don't dispatch an extra exit signal. + */ + bool skip_dispatch = false; + + if (res != SEL4_VMENTER_RESULT_FAULT) { state.exit_reason = VMEXIT_RECALL; + skip_dispatch = true; + } else state.exit_reason = (unsigned)seL4_GetMR(SEL4_VMENTER_FAULT_REASON_MR); @@ -233,15 +251,18 @@ struct Sel4_vcpu : Genode::Thread, Noncopyable _wake_up.down(); } } + _state_ready.up(); + if (skip_dispatch) + continue; /* notify VM handler */ - Genode::Signal_transmitter(_vcpu_handler.signal_cap()).submit(); + Genode::Signal_transmitter(_exit_handler.signal_cap()).submit(); /* * Wait until VM handler is really really done, * otherwise we lose state. */ - _vcpu_handler.ready_semaphore().down(); + _exit_handler.ready_semaphore().down(); } } @@ -655,8 +676,8 @@ struct Sel4_vcpu : Genode::Thread, Noncopyable _write_vmcs(service, Vmcs::CR4_SHADOW, state.cr4.value()); } - typedef Genode::Vcpu_state::Segment Segment; - typedef Genode::Vcpu_state::Range Range; + using Segment = Genode::Vcpu_state::Segment; + using Range = Genode::Vcpu_state::Range; state.cs.charge(Segment{_read_vmcs_16(service, Vmcs::CS_SEL), _convert_ar_16(_read_vmcs(service, Vmcs::CS_AR)), @@ -747,6 +768,13 @@ struct Sel4_vcpu : Genode::Thread, Noncopyable return ep->affinity(); } + void _wrapper_dispatch() + { + _dispatching = true; + _vcpu_handler.dispatch(1); + _dispatching = false; + } + public: Sel4_vcpu(Env &env, Vm_connection &vm, @@ -754,12 +782,14 @@ struct Sel4_vcpu : Genode::Thread, Noncopyable : Thread(env, "vcpu_thread", STACK_SIZE, _location(handler), Weight(), env.cpu()), - _vcpu_handler(handler) + _vcpu_handler(handler), + _exit_handler(handler.ep(), *this, &Sel4_vcpu::_wrapper_dispatch) { Thread::start(); /* wait until thread is alive, e.g. Thread::cap() is valid */ _startup.block(); + _ep_handler = reinterpret_cast(&handler.rpc_ep()); _rpc.construct(vm, this->cap(), *this); @@ -767,6 +797,9 @@ struct Sel4_vcpu : Genode::Thread, Noncopyable _wake_up.up(); } + const Sel4_vcpu& operator=(const Sel4_vcpu &) = delete; + Sel4_vcpu(const Sel4_vcpu&) = delete; + void resume() { Mutex::Guard guard(_remote_mutex); @@ -778,21 +811,52 @@ struct Sel4_vcpu : Genode::Thread, Noncopyable _wake_up.up(); } - void pause() + void with_state(Call_with_state &cw) { - Mutex::Guard guard(_remote_mutex); + if (!_dispatching) { + if (Thread::myself() != _ep_handler) { + error("vCPU state requested outside of vcpu_handler EP"); + sleep_forever(); + } - if (_remote == PAUSE) - return; + _remote_mutex.acquire(); - _remote = PAUSE; + /* Trigger pause exit */ + _remote = PAUSE; + seL4_Signal(_recall); + _wake_up.up(); - seL4_Signal(_recall); + _remote_mutex.release(); + _state_ready.down(); - _wake_up.up(); + /* + * We're in the async dispatch, yet processing a non-pause exit. + * Signal that we have to wrap the dispatch loop around. + */ + if (_state.exit_reason != VMEXIT_RECALL) { + _extra_dispatch_up = true; + } + } else { + _state_ready.down(); + } + + if (cw.call_with_state(_state) + || _extra_dispatch_up) + resume(); + + /* + * The regular exit was handled by the asynchronous dispatch handler + * triggered by the pause request. + * + * Fake finishing the exit dispatch so that the vCPU loop + * processes the asynchronously dispatched exit and provides + * the VMEXIT_RECALL to the already pending dispatch function + * for the exit code. + */ + if (!_dispatching && _extra_dispatch_up) + _exit_handler.ready_semaphore().up(); } - Vcpu_state & state() { return _state; } Sel4_native_rpc * rpc() { return &*_rpc; } }; @@ -800,13 +864,13 @@ struct Sel4_vcpu : Genode::Thread, Noncopyable ** vCPU API ** **************/ -void Vm_connection::Vcpu::run() { static_cast(_native_vcpu).vcpu.resume(); } -void Vm_connection::Vcpu::pause() { static_cast(_native_vcpu).vcpu.pause(); } -Vcpu_state & Vm_connection::Vcpu::state() { return static_cast(_native_vcpu).vcpu.state(); } +void Vm_connection::Vcpu::_with_state(Call_with_state &cw) { static_cast(_native_vcpu).vcpu.with_state(cw); } Vm_connection::Vcpu::Vcpu(Vm_connection &vm, Allocator &alloc, Vcpu_handler_base &handler, Exit_config const &exit_config) : _native_vcpu(*((new (alloc) Sel4_vcpu(vm._env, vm, handler, exit_config))->rpc())) -{ } +{ + static_cast(_native_vcpu).vcpu.resume(); +} diff --git a/repos/base-sel4/src/timer/epit/imx6q_sabrelite/target.mk b/repos/base-sel4/src/timer/epit/imx6q_sabrelite/target.mk deleted file mode 100644 index e7199f8433..0000000000 --- a/repos/base-sel4/src/timer/epit/imx6q_sabrelite/target.mk +++ /dev/null @@ -1 +0,0 @@ -include $(call select_from_repositories,src/timer/epit/imx6/target.inc) diff --git a/repos/base-sel4/src/timer/gpt/imx7d_sabre/target.mk b/repos/base-sel4/src/timer/gpt/imx7d_sabre/target.mk deleted file mode 100644 index 9964666a42..0000000000 --- a/repos/base-sel4/src/timer/gpt/imx7d_sabre/target.mk +++ /dev/null @@ -1 +0,0 @@ -include $(call select_from_repositories,src/timer/gpt/imx7/target.inc) diff --git a/repos/base/README b/repos/base/README index 6356c8599f..4c9f74bf56 100644 --- a/repos/base/README +++ b/repos/base/README @@ -1,19 +1,18 @@ -This is generic part of the Genode implementation. It consists of two parts: +This is the generic Genode base system, which consists of two parts: -:_Core_: is the ultimate root of the Genode application tree - and provides abstractions for the lowest-level hardware resources - such as RAM, ROM, CPU, and generic device access. All generic parts of Core - can be found here - for system-specific implementations refer to the - appropriate 'base-' directory. +:_Core_: is the root of the Genode component tree. It provides abstractions for + the lowest-level hardware resources such as RAM, ROM, CPU, and device access. + All generic parts of core can be found here. For kernel-specific parts, + refer to the appropriate 'base-' directory. -:_Base libraries and protocols_: that are used by each Genode component +:_Base libraries and interfaces: that are used by each Genode component to interact with other components. This is the glue that holds everything together. -_Core_ may export information about the hardware platform by an ROM -called 'platform_info'. Depending on the platform, e.g. ARM or x86 or riscv, -and depending on the boot mode and boot loader and kernel, some nodes may not -be populated. +Depending on the used kernel, core may export information about the hardware +platform as a ROM called 'platform_info'. For example, if the ACPI RSDT and +XSDT physical pointer are reported by the used kernel and/or bootloader, core +provides this information in the ROM as follows. ! ! @@ -22,9 +21,6 @@ be populated. ! ! -If the ACPI RSDT and XSDT physical pointer is reported by the used kernel -and/or bootloader, _Core_ may provide this information by the ROM. - -If the graphic device is initialised and can be directly used by a framebuffer -driver, _Core_ may provide the physical pointer to the framebuffer, the -resolution and color depth in bits. +If the graphics device is initialised and can be directly used by a +framebuffer driver, core provides the physical pointer to the framebuffer, the +resolution, and color depth in bits. diff --git a/repos/base/board/pc/devices b/repos/base/board/pc/devices index b5ca5a1261..4143922c1b 100644 --- a/repos/base/board/pc/devices +++ b/repos/base/board/pc/devices @@ -1,13 +1,3 @@ - - - - - - - - - - - + diff --git a/repos/base/board/pc/qemu_args b/repos/base/board/pc/qemu_args index 7232ed8d4b..7c03fe4ad9 100644 --- a/repos/base/board/pc/qemu_args +++ b/repos/base/board/pc/qemu_args @@ -1,2 +1,3 @@ -machine q35 +-cpu Nehalem-v2 -net nic,model=e1000,netdev=net0 -netdev user,id=net0 diff --git a/repos/base/etc/tools.conf b/repos/base/etc/tools.conf index cd957963f5..e87df01c5f 100644 --- a/repos/base/etc/tools.conf +++ b/repos/base/etc/tools.conf @@ -19,19 +19,19 @@ # package build tool. # ifeq ($(filter-out $(SPECS),x86_32),) -CROSS_DEV_PREFIX ?= /usr/local/genode/tool/21.05/bin/genode-x86- +CROSS_DEV_PREFIX ?= /usr/local/genode/tool/23.05/bin/genode-x86- endif ifeq ($(filter-out $(SPECS),x86_64),) -CROSS_DEV_PREFIX ?= /usr/local/genode/tool/21.05/bin/genode-x86- +CROSS_DEV_PREFIX ?= /usr/local/genode/tool/23.05/bin/genode-x86- endif ifeq ($(filter-out $(SPECS),arm_64),) -CROSS_DEV_PREFIX ?= /usr/local/genode/tool/21.05/bin/genode-aarch64- +CROSS_DEV_PREFIX ?= /usr/local/genode/tool/23.05/bin/genode-aarch64- endif ifeq ($(filter-out $(SPECS),arm),) -CROSS_DEV_PREFIX ?= /usr/local/genode/tool/21.05/bin/genode-arm- +CROSS_DEV_PREFIX ?= /usr/local/genode/tool/23.05/bin/genode-arm- endif ifeq ($(filter-out $(SPECS),riscv),) -CROSS_DEV_PREFIX ?= /usr/local/genode/tool/21.05/bin/genode-riscv- +CROSS_DEV_PREFIX ?= /usr/local/genode/tool/23.05/bin/genode-riscv- endif # diff --git a/repos/base/include/README b/repos/base/include/README deleted file mode 100644 index b17d4a69b5..0000000000 --- a/repos/base/include/README +++ /dev/null @@ -1,3 +0,0 @@ -This directory contains include files of interfaces that are exported -by components to be used by other components. Each subdirectory corresponds -to the component exporting the interface. diff --git a/repos/base/include/base/allocator.h b/repos/base/include/base/allocator.h index eafae2d8e6..5eec8bb397 100644 --- a/repos/base/include/base/allocator.h +++ b/repos/base/include/base/allocator.h @@ -26,7 +26,7 @@ namespace Genode { struct Allocator; struct Range_allocator; - template void destroy(DEALLOC && dealloc, T *obj); + template void destroy(auto && dealloc, T *obj); } @@ -276,8 +276,8 @@ inline void operator delete (void *ptr, Genode::Allocator &a) { * was allocated * \param obj object to destroy */ -template -void Genode::destroy(DEALLOC && dealloc, T *obj) +template +void Genode::destroy(auto && dealloc, T *obj) { if (!obj) return; diff --git a/repos/base/include/base/allocator_avl.h b/repos/base/include/base/allocator_avl.h index 4fa66e1660..60524803bb 100644 --- a/repos/base/include/base/allocator_avl.h +++ b/repos/base/include/base/allocator_avl.h @@ -39,7 +39,7 @@ namespace Genode { * Define AVL-based allocator without any meta data attached to each block */ class Empty { }; - typedef Allocator_avl_tpl Allocator_avl; + using Allocator_avl = Allocator_avl_tpl; } @@ -207,11 +207,9 @@ class Genode::Allocator_avl_base : public Range_allocator */ void _cut_from_block(Block &b, addr_t cut_addr, size_t cut_size, Two_blocks); - template - bool _revert_block_ranges(ANY_BLOCK_FN const &); + bool _revert_block_ranges(auto const &any_block_fn); - template - Alloc_result _allocate(size_t, unsigned, Range, SEARCH_FN const &); + Alloc_result _allocate(size_t, unsigned, Range, auto const &search_fn); protected: @@ -386,10 +384,9 @@ class Genode::Allocator_avl_tpl : public Allocator_avl_base /** * Construct meta-data object in place * - * \param ARGS arguments passed to the meta-data constuctor + * \param args arguments passed to the meta-data constuctor */ - template - void construct_metadata(void *addr, ARGS &&... args) + void construct_metadata(void *addr, auto &&... args) { Block * const b = static_cast(_find_by_address((addr_t)addr)); if (b) construct_at(static_cast(b), args...); @@ -427,8 +424,7 @@ class Genode::Allocator_avl_tpl : public Allocator_avl_base * the method repeatedly without removing or inserting * members will produce the same member. */ - template - bool apply_any(FUNC const &fn) + bool apply_any(auto const &fn) { addr_t addr = 0; if (any_block_addr(&addr)) { diff --git a/repos/base/include/base/attached_dataspace.h b/repos/base/include/base/attached_dataspace.h index ade39b1a64..8adaba4d48 100644 --- a/repos/base/include/base/attached_dataspace.h +++ b/repos/base/include/base/attached_dataspace.h @@ -24,7 +24,8 @@ class Genode::Attached_dataspace : Noncopyable { public: - typedef Region_map::Invalid_dataspace Invalid_dataspace; + struct Invalid_dataspace : Exception { }; + struct Region_conflict : Exception { }; private: @@ -32,16 +33,25 @@ class Genode::Attached_dataspace : Noncopyable Region_map &_rm; - size_t const _size = { Dataspace_client(_ds).size() }; - - void * _local_addr = nullptr; - Dataspace_capability _check(Dataspace_capability ds) { if (ds.valid()) return ds; - throw Region_map::Invalid_dataspace(); + throw Invalid_dataspace(); + } + + Region_map::Attach_result _attached = _rm.attach(_ds, { + .size = { }, .offset = { }, + .use_at = { }, .at = { }, + .executable = { }, .writeable = true }); + + template + T *_ptr() const + { + return _attached.convert( + [&] (Region_map::Range range) { return (T *)range.start; }, + [&] (Region_map::Attach_error) { return nullptr; }); } /* @@ -55,21 +65,30 @@ class Genode::Attached_dataspace : Noncopyable /** * Constructor * - * \throw Region_map::Region_conflict - * \throw Region_map::Invalid_dataspace + * \throw Region_conflict + * \throw Invalid_dataspace * \throw Out_of_caps * \throw Out_of_ram */ Attached_dataspace(Region_map &rm, Dataspace_capability ds) - : _ds(_check(ds)), _rm(rm), _local_addr(_rm.attach(_ds)) { } + : + _ds(_check(ds)), _rm(rm) + { + _attached.with_error([&] (Region_map::Attach_error e) { + if (e == Region_map::Attach_error::OUT_OF_RAM) throw Out_of_ram(); + if (e == Region_map::Attach_error::OUT_OF_CAPS) throw Out_of_caps(); + throw Region_conflict(); + }); + } /** * Destructor */ ~Attached_dataspace() { - if (_local_addr) - _rm.detach(_local_addr); + _attached.with_result( + [&] (Region_map::Range range) { _rm.detach(range.start); }, + [&] (Region_map::Attach_error) { }); } /** @@ -84,15 +103,20 @@ class Genode::Attached_dataspace : Noncopyable * A newly attached dataspace is untyped memory anyway. */ template - T *local_addr() { return static_cast(_local_addr); } + T *local_addr() { return _ptr(); } template - T const *local_addr() const { return static_cast(_local_addr); } + T const *local_addr() const { return _ptr(); } /** * Return size */ - size_t size() const { return _size; } + size_t size() const + { + return _attached.convert( + [&] (Region_map::Range range) { return range.num_bytes; }, + [&] (Region_map::Attach_error) { return 0UL; }); + } /** * Forget dataspace, thereby skipping the detachment on destruction @@ -103,7 +127,7 @@ class Genode::Attached_dataspace : Noncopyable * removed the memory mappings of the dataspace. So we have to omit the * detach operation in '~Attached_dataspace'. */ - void invalidate() { _local_addr = nullptr; } + void invalidate() { _attached = Region_map::Attach_error::INVALID_DATASPACE; } }; #endif /* _INCLUDE__BASE__ATTACHED_DATASPACE_H_ */ diff --git a/repos/base/include/base/attached_io_mem_dataspace.h b/repos/base/include/base/attached_io_mem_dataspace.h index 315761a2e0..4052444f11 100644 --- a/repos/base/include/base/attached_io_mem_dataspace.h +++ b/repos/base/include/base/attached_io_mem_dataspace.h @@ -15,7 +15,7 @@ #define _INCLUDE__BASE__ATTACHED_IO_MEM_DATASPACE_H_ #include -#include +#include namespace Genode { class Attached_io_mem_dataspace; } @@ -34,11 +34,23 @@ class Genode::Attached_io_mem_dataspace Region_map &_env_rm; Io_mem_connection _mmio; Io_mem_dataspace_capability _ds; - Region_map::Local_addr _local_addr; + addr_t const _at; - static void *_with_sub_page_offset(void *local, addr_t io_base) + static addr_t _with_sub_page_offset(addr_t local, addr_t io_base) { - return (void *)((addr_t)local | (io_base & (addr_t)0xfff)); + return local | (io_base & 0xfffUL); + } + + addr_t _attach() + { + return _env_rm.attach(_ds, { + .size = { }, .offset = { }, + .use_at = { }, .at = { }, + .executable = { }, .writeable = true + }).convert( + [&] (Region_map::Range range) { return range.start; }, + [&] (Region_map::Attach_error) { return 0UL; } + ); } public: @@ -55,8 +67,8 @@ class Genode::Attached_io_mem_dataspace * \throw Insufficient_cap_quota * \throw Out_of_ram * \throw Out_of_caps - * \throw Region_map::Region_conflict - * \throw Region_map::Invalid_dataspace + * \throw Attached_dataspace::Region_conflict + * \throw Attached_dataspace::Invalid_dataspace */ Attached_io_mem_dataspace(Env &env, Genode::addr_t base, Genode::size_t size, bool write_combined = false) @@ -64,13 +76,16 @@ class Genode::Attached_io_mem_dataspace _env_rm(env.rm()), _mmio(env, base, size, write_combined), _ds(_mmio.dataspace()), - _local_addr(_with_sub_page_offset(env.rm().attach(_ds), base)) - { } + _at(_with_sub_page_offset(_attach(), base)) + { + if (!_ds.valid()) throw Attached_dataspace::Invalid_dataspace(); + if (!_at) throw Attached_dataspace::Region_conflict(); + } /** * Destructor */ - ~Attached_io_mem_dataspace() { _env_rm.detach(_local_addr); } + ~Attached_io_mem_dataspace() { if (_at) _env_rm.detach(_at); } /** * Return capability of the used RAM dataspace @@ -84,7 +99,7 @@ class Genode::Attached_io_mem_dataspace * A newly allocated I/O MEM dataspace is untyped memory anyway. */ template - T *local_addr() { return static_cast(_local_addr); } + T *local_addr() { return reinterpret_cast(_at); } }; #endif /* _INCLUDE__BASE__ATTACHED_IO_MEM_DATASPACE_H_ */ diff --git a/repos/base/include/base/attached_ram_dataspace.h b/repos/base/include/base/attached_ram_dataspace.h index 10f1026cc8..f6b316ef94 100644 --- a/repos/base/include/base/attached_ram_dataspace.h +++ b/repos/base/include/base/attached_ram_dataspace.h @@ -17,6 +17,7 @@ #include #include #include +#include namespace Genode { class Attached_ram_dataspace; } @@ -34,11 +35,11 @@ class Genode::Attached_ram_dataspace { private: - size_t _size = 0; - Ram_allocator *_ram = nullptr; - Region_map *_rm = nullptr; + size_t _size = 0; + Ram_allocator *_ram = nullptr; + Region_map *_rm = nullptr; Ram_dataspace_capability _ds { }; - void *_local_addr = nullptr; + addr_t _at = 0; Cache const _cache = CACHED; template @@ -46,8 +47,8 @@ class Genode::Attached_ram_dataspace void _detach_and_free_dataspace() { - if (_local_addr) - _rm->detach(_local_addr); + if (_at) + _rm->detach(_at); if (_ds.valid()) _ram->free(_ds); @@ -57,13 +58,19 @@ class Genode::Attached_ram_dataspace { if (!_size) return; - try { - _ds = _ram->alloc(_size, _cache); - _local_addr = _rm->attach(_ds); - } - /* revert allocation if attaching the dataspace failed */ - catch (Region_map::Region_conflict) { _ram->free(_ds); throw; } - catch (Region_map::Invalid_dataspace) { _ram->free(_ds); throw; } + _ds = _ram->alloc(_size, _cache); + + Region_map::Attr attr { }; + attr.writeable = true; + _rm->attach(_ds, attr).with_result( + [&] (Region_map::Range range) { _at = range.start; }, + [&] (Region_map::Attach_error e) { + /* revert allocation if attaching the dataspace failed */ + _ram->free(_ds); + if (e == Region_map::Attach_error::OUT_OF_RAM) throw Out_of_ram(); + if (e == Region_map::Attach_error::OUT_OF_CAPS) throw Out_of_caps(); + throw Attached_dataspace::Region_conflict(); + }); /* * Eagerly map dataspace if used for DMA @@ -77,7 +84,7 @@ class Genode::Attached_ram_dataspace */ if (_cache != CACHED) { enum { PAGE_SIZE = 4096 }; - unsigned char volatile *base = (unsigned char volatile *)_local_addr; + unsigned char volatile *base = (unsigned char volatile *)_at; for (size_t i = 0; i < _size; i += PAGE_SIZE) touch_read_write(base + i); } @@ -96,8 +103,8 @@ class Genode::Attached_ram_dataspace * * \throw Out_of_ram * \throw Out_of_caps - * \throw Region_map::Region_conflict - * \throw Region_map::Invalid_dataspace + * \throw Attached_dataspace::Region_conflict + * \throw Attached_dataspace::Invalid_dataspace */ Attached_ram_dataspace(Ram_allocator &ram, Region_map &rm, size_t size, Cache cache = CACHED) @@ -125,7 +132,7 @@ class Genode::Attached_ram_dataspace * untyped memory anyway. */ template - T *local_addr() const { return static_cast(_local_addr); } + T *local_addr() const { return reinterpret_cast(_at); } /** * Return size @@ -134,10 +141,10 @@ class Genode::Attached_ram_dataspace void swap(Attached_ram_dataspace &other) { - _swap(_size, other._size); - _swap(_ram, other._ram); - _swap(_ds, other._ds); - _swap(_local_addr, other._local_addr); + _swap(_size, other._size); + _swap(_ram, other._ram); + _swap(_ds, other._ds); + _swap(_at, other._at); } /** diff --git a/repos/base/include/base/blocking.h b/repos/base/include/base/blocking.h deleted file mode 100644 index 6c2c6335b2..0000000000 --- a/repos/base/include/base/blocking.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * \brief Support for blocking operations - * \author Norman Feske - * \date 2007-09-06 - */ - -/* - * Copyright (C) 2007-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _INCLUDE__BASE__BLOCKING_H_ -#define _INCLUDE__BASE__BLOCKING_H_ - -#include - -namespace Genode { class Blocking_canceled; } - -/** - * Blocking-canceled exception - * - * Two operations may block a thread, waiting at a lock or performing an RPC - * call. Both operations may be canceled when the thread is destructed. In this - * case, the thread unblocks and throws an exception, and therefore, is able to - * clean up the thread state before exiting. - */ -class Genode::Blocking_canceled : public Exception { }; - -#endif /* _INCLUDE__BASE__BLOCKING_H_ */ diff --git a/repos/base/include/base/capability.h b/repos/base/include/base/capability.h index 8f28375061..ef2992bd00 100644 --- a/repos/base/include/base/capability.h +++ b/repos/base/include/base/capability.h @@ -32,7 +32,7 @@ namespace Genode { /** * Capability that is not associated with a specific RPC interface */ - typedef Native_capability Untyped_capability; + using Untyped_capability = Native_capability; template class Capability; @@ -123,7 +123,7 @@ class Genode::Capability : public Untyped_capability template struct Arg { - typedef typename Meta::Type_at::Type Type; + using Type = typename Meta::Type_at::Type; }; template @@ -138,7 +138,7 @@ class Genode::Capability : public Untyped_capability public: - typedef RPC_INTERFACE Rpc_interface; + using Rpc_interface = RPC_INTERFACE; /** * Constructor diff --git a/repos/base/include/base/child.h b/repos/base/include/base/child.h index d38a3d75bd..7c70c369bd 100644 --- a/repos/base/include/base/child.h +++ b/repos/base/include/base/child.h @@ -26,6 +26,7 @@ #include #include #include +#include #include namespace Genode { @@ -44,9 +45,9 @@ namespace Genode { */ struct Genode::Child_policy { - typedef String<64> Name; - typedef String<64> Binary_name; - typedef String<64> Linker_name; + using Name = String<64>; + using Binary_name = String<64>; + using Linker_name = String<64>; virtual ~Child_policy() { } @@ -125,6 +126,11 @@ struct Genode::Child_policy virtual Pd_session &ref_pd() = 0; virtual Pd_session_capability ref_pd_cap() const = 0; + /** + * RAM allocator used as backing store for '_session_md_alloc' + */ + virtual Ram_allocator &session_md_ram() { return ref_pd(); } + /** * Respond to the release of resources by the child * @@ -156,14 +162,10 @@ struct Genode::Child_policy */ virtual void init(Pd_session &, Capability) { } - class Nonexistent_id_space : Exception { }; - /** * ID space for sessions provided by the child - * - * \throw Nonexistent_id_space */ - virtual Id_space &server_id_space() { throw Nonexistent_id_space(); } + virtual Id_space &server_id_space() = 0; /** * Notification hook invoked each time a session state is modified @@ -188,22 +190,47 @@ struct Genode::Child_policy */ virtual bool initiate_env_sessions() const { return true; } + struct With_address_space_fn : Interface + { + virtual void call(Region_map &) const = 0; + }; + + virtual void _with_address_space(Pd_session &pd, With_address_space_fn const &fn) + { + Region_map_client region_map(pd.address_space()); + fn.call(region_map); + } + /** - * Return region map for the child's address space + * Call functor 'fn' with the child's address-space region map as argument * - * \param pd the child's PD session capability - * - * By default, the function returns a 'nullptr'. In this case, the 'Child' - * interacts with the address space of the child's PD session via RPC calls - * to the 'Pd_session::address_space'. - * - * By overriding the default, those RPC calls can be omitted, which is - * useful if the child's PD session (including the PD's address space) is - * virtualized by the parent. If the virtual PD session is served by the - * same entrypoint as the child's parent interface, an RPC call to 'pd' - * would otherwise produce a deadlock. + * In the common case where the child's PD is provided by core, the address + * space is accessed via the 'Region_map' RPC interface. However, in cases + * where the child's PD session interface is locally implemented - as is + * the case for a debug monitor - the address space must be accessed by + * component-local method calls instead. */ - virtual Region_map *address_space(Pd_session &) { return nullptr; } + void with_address_space(Pd_session &pd, auto const &fn) + { + using FN = decltype(fn); + + struct Impl : With_address_space_fn + { + FN const &_fn; + Impl(FN const &fn) : _fn(fn) { }; + void call(Region_map &rm) const override { _fn(rm); } + }; + + _with_address_space(pd, Impl(fn)); + } + + /** + * Start initial thread of the child at instruction pointer 'ip' + */ + virtual void start_initial_thread(Capability thread, addr_t ip) + { + Cpu_thread_client(thread).start(ip, 0); + } /** * Return true if ELF loading should be inhibited @@ -242,10 +269,18 @@ class Genode::Child : protected Rpc_object, struct Initial_thread_base : Interface { + struct Start : Interface + { + virtual void start_initial_thread(Capability, addr_t ip) = 0; + }; + /** * Start execution at specified instruction pointer + * + * The 'Child_policy' allows for the overriding of the default + * RPC-based implementation of 'start_initial_thread'. */ - virtual void start(addr_t ip) = 0; + virtual void start(addr_t ip, Start &) = 0; /** * Return capability of the initial thread @@ -262,19 +297,20 @@ class Genode::Child : protected Rpc_object, public: - typedef Cpu_session::Name Name; + using Initial_thread_base::Start; + + using Name = Cpu_session::Name; /** * Constructor * - * \throw Cpu_session::Thread_creation_failed * \throw Out_of_ram * \throw Out_of_caps */ Initial_thread(Cpu_session &, Pd_session_capability, Name const &); ~Initial_thread(); - void start(addr_t) override; + void start(addr_t, Start &) override; Capability cap() const override { return _cap; } }; @@ -283,8 +319,7 @@ class Genode::Child : protected Rpc_object, Child_policy &_policy; /* print error message with the child's name prepended */ - template - void _error(ARGS &&... args) { error(_policy.name(), ": ", args...); } + void _error(auto &&... args) { error(_policy.name(), ": ", args...); } Region_map &_local_rm; @@ -307,7 +342,7 @@ class Genode::Child : protected Rpc_object, Id_space _id_space { }; /* allocator used for dynamically created session state objects */ - Sliced_heap _session_md_alloc { _policy.ref_pd(), _local_rm }; + Sliced_heap _session_md_alloc { _policy.session_md_ram(), _local_rm }; Session_state::Factory::Batch_size const _session_batch_size { _policy.session_alloc_batch_size() }; @@ -316,7 +351,7 @@ class Genode::Child : protected Rpc_object, Session_state::Factory _session_factory { _session_md_alloc, _session_batch_size }; - typedef Session_state::Args Args; + using Args = Session_state::Args; /* * Members that are initialized not before the child's environment is @@ -327,75 +362,41 @@ class Genode::Child : protected Rpc_object, Constructible _initial_thread { }; - struct Process + struct Initial_thread_start : Initial_thread::Start { - class Missing_dynamic_linker : Exception { }; - class Invalid_executable : Exception { }; + Child_policy &_policy; - enum Type { TYPE_LOADED, TYPE_FORKED }; - - struct Loaded_executable + void start_initial_thread(Capability cap, addr_t ip) override { - /** - * Initial instruction pointer of the new process, as defined - * in the header of the executable. - */ - addr_t entry { 0 }; + _policy.start_initial_thread(cap, ip); + } - /** - * Constructor parses the executable and sets up segment - * dataspaces - * - * \param local_rm local address space, needed to make the - * segment dataspaces temporarily visible in - * the local address space to initialize their - * content with the data from the 'elf_ds' - * - * \throw Region_map::Region_conflict - * \throw Region_map::Invalid_dataspace - * \throw Invalid_executable - * \throw Missing_dynamic_linker - * \throw Out_of_ram - * \throw Out_of_caps - */ - Loaded_executable(Type type, - Dataspace_capability ldso_ds, - Ram_allocator &ram, - Region_map &local_rm, - Region_map &remote_rm, - Parent_capability parent_cap); - } loaded_executable; + Initial_thread_start(Child_policy &policy) : _policy(policy) { } - /** - * Constructor - * - * \throw Missing_dynamic_linker - * \throw Invalid_executable - * \throw Region_map::Region_conflict - * \throw Region_map::Invalid_dataspace - * \throw Out_of_ram - * \throw Out_of_caps - * - * On construction of a protection domain, the initial thread is - * started immediately. - * - * The 'type' 'TYPE_FORKED' creates an empty process. In this case, - * all process initialization steps except for the creation of the - * initial thread must be done manually, i.e., as done for - * implementing fork. - */ - Process(Type type, - Dataspace_capability ldso_ds, - Pd_session &pd, - Initial_thread_base &initial_thread, - Region_map &local_rm, - Region_map &remote_rm, - Parent_capability parent); + } _initial_thread_start { _policy }; - ~Process(); - }; + struct Entry { addr_t ip; }; - Constructible _process { }; + enum class Load_error { INVALID, OUT_OF_RAM, OUT_OF_CAPS }; + using Load_result = Attempt; + + static Load_result _load_static_elf(Dataspace_capability elf_ds, + Ram_allocator &ram, + Region_map &local_rm, + Region_map &remote_rm, + Parent_capability parent_cap); + + enum class Start_result { UNKNOWN, OK, OUT_OF_RAM, OUT_OF_CAPS, INVALID }; + + static Start_result _start_process(Dataspace_capability ldso_ds, + Pd_session &pd, + Initial_thread_base &, + Initial_thread::Start &, + Region_map &local_rm, + Region_map &remote_rm, + Parent_capability parent); + + Start_result _start_result { }; /* * The child's environment sessions @@ -408,7 +409,7 @@ class Genode::Child : protected Rpc_object, Id_space::Id const _client_id; - typedef String<64> Label; + using Label = String<64>; Args const _args; @@ -488,13 +489,16 @@ class Genode::Child : protected Rpc_object, _child._try_construct_env_dependent_members(); } + using Transfer_ram_quota_result = Pd_session::Transfer_ram_quota_result; + using Transfer_cap_quota_result = Pd_session::Transfer_ram_quota_result; + /** * Service (Ram_transfer::Account) interface */ - void transfer(Pd_session_capability to, Ram_quota amount) override + Ram_transfer_result transfer(Pd_session_capability to, Ram_quota amount) override { Ram_transfer::Account &from = _service; - from.transfer(to, amount); + return from.transfer(to, amount); } /** @@ -509,10 +513,10 @@ class Genode::Child : protected Rpc_object, /** * Service (Cap_transfer::Account) interface */ - void transfer(Pd_session_capability to, Cap_quota amount) override + Cap_transfer_result transfer(Pd_session_capability to, Cap_quota amount) override { Cap_transfer::Account &from = _service; - from.transfer(to, amount); + return from.transfer(to, amount); } /** @@ -591,7 +595,7 @@ class Genode::Child : protected Rpc_object, "environment session denied (", _args.string(), ")"); } } - typedef typename CONNECTION::Session_type SESSION; + using SESSION = typename CONNECTION::Session_type; SESSION &session() { return _connection->session(); } SESSION const &session() const { return _connection->session(); } @@ -680,7 +684,7 @@ class Genode::Child : protected Rpc_object, * environment sessions could not be established, e.g., the ROM session * of the binary could not be obtained. */ - bool active() const { return _process.constructed(); } + bool active() const { return _start_result == Start_result::OK; } /** * Initialize the child's PD session @@ -732,8 +736,7 @@ class Genode::Child : protected Rpc_object, void close_all_sessions(); - template - void for_each_session(FN const &fn) const + void for_each_session(auto const &fn) const { _id_space.for_each(fn); } @@ -802,9 +805,9 @@ class Genode::Child : protected Rpc_object, void announce(Service_name const &) override; void session_sigh(Signal_context_capability) override; - Session_capability session(Client::Id, Service_name const &, - Session_args const &, Affinity const &) override; - Session_capability session_cap(Client::Id) override; + Session_result session(Client::Id, Service_name const &, + Session_args const &, Affinity const &) override; + Session_cap_result session_cap(Client::Id) override; Upgrade_result upgrade(Client::Id, Upgrade_args const &) override; Close_result close(Client::Id) override; void exit(int) override; diff --git a/repos/base/include/base/connection.h b/repos/base/include/base/connection.h index d242603afe..1798d84906 100644 --- a/repos/base/include/base/connection.h +++ b/repos/base/include/base/connection.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2008-2017 Genode Labs GmbH + * Copyright (C) 2008-2023 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -46,13 +46,6 @@ class Genode::Connection_base : Noncopyable, Interface _id_space_element(_parent_client, _env.id_space()) { } - /** - * Legacy constructor - * - * \noapi - */ - Connection_base(); - void upgrade(Session::Resources resources) { String<80> const args("ram_quota=", resources.ram_quota, ", " @@ -78,18 +71,17 @@ class Genode::Connection_base : Noncopyable, Interface * * \noapi */ - template - auto retry_with_upgrade(Ram_quota ram, Cap_quota caps, FUNC func) -> decltype(func()) + auto retry_with_upgrade(Ram_quota ram, Cap_quota caps, auto const &fn) -> decltype(fn()) { enum { UPGRADE_ATTEMPTS = ~0U }; return Genode::retry( - [&] () { + [&] { return Genode::retry( - [&] () { return func(); }, - [&] () { upgrade_caps(caps.value); }, + [&] { return fn(); }, + [&] { upgrade_caps(caps.value); }, UPGRADE_ATTEMPTS); }, - [&] () { upgrade_ram(ram.value); }, + [&] { upgrade_ram(ram.value); }, UPGRADE_ATTEMPTS); } }; @@ -101,92 +93,76 @@ class Genode::Connection_base : Noncopyable, Interface template class Genode::Connection : public Connection_base { + public: + + using Args = String; + using Session_type = SESSION_TYPE; + using Ram_quota = Genode::Ram_quota; + private: - /* - * Buffer for storing the session arguments passed to the - * 'session' method that is called before the 'Connection' is - * constructed. - */ + using Client_id = Parent::Client::Id; - enum { FORMAT_STRING_SIZE = Parent::Session_args::MAX_SIZE }; - - char _session_args[FORMAT_STRING_SIZE]; - - Affinity _affinity_arg { }; - - void _session(Parent &, - Affinity const &affinity, - const char *format_args, va_list list) + static Capability _request(Env &env, + Client_id const &id, + Session_label const &label, + Ram_quota const &ram_quota, + Affinity const &affinity, + Args const &args) { - String_console sc(_session_args, FORMAT_STRING_SIZE); - sc.vprintf(format_args, list); - va_end(list); + /* supplement session quotas and label as session arguments */ + Args const complete_args("label=\"", label, "\", " + "ram_quota=", ram_quota, ", " + "cap_quota=", unsigned(SESSION_TYPE::CAP_QUOTA), ", ", + args); - _affinity_arg = affinity; - } + if (complete_args.length() == Args::capacity()) + warning("truncated arguments of ", + SESSION_TYPE::service_name(), " session"); - Capability _request_cap() - { try { - return _env.session(_id_space_element.id(), - _session_args, _affinity_arg); } + return env.session(id, complete_args.string(), + affinity); + } catch (...) { error(SESSION_TYPE::service_name(), "-session creation failed " - "(", Cstring(_session_args), ")"); + "(", complete_args, ")"); throw; } } - Capability _cap = _request_cap(); + Capability _cap; public: - typedef SESSION_TYPE Session_type; - - /** - * Constructor - */ - Connection(Env &env, Capability) + Connection(Env &env, + Session_label const &label, + Ram_quota const &ram_quota, + Affinity const &affinity, + Args const &args) : - Connection_base(env), _cap(_request_cap()) + Connection_base(env), + _cap(_request(env, _id_space_element.id(), + label, ram_quota, affinity, args)) { } /** - * Destructor + * Constructor + * + * Shortcut for the common case where the affinity is not specified. */ + Connection(Env &env, Session_label const &label, + Ram_quota const &ram_quota, Args const &args) + : + Connection(env, label, ram_quota, Affinity(), args) + { } + ~Connection() { _env.close(_id_space_element.id()); } /** * Return session capability */ Capability cap() const { return _cap; } - - /** - * Issue session request to the parent - */ - Capability session(Parent &parent, const char *format_args, ...) - { - va_list list; - va_start(list, format_args); - - _session(parent, Affinity(), format_args, list); - return Capability(); - } - - /** - * Issue session request to the parent - */ - Capability session(Parent &parent, - Affinity const &affinity, - char const *format_args, ...) - { - va_list list; - va_start(list, format_args); - - _session(parent, affinity, format_args, list); - return Capability(); - } }; #endif /* _INCLUDE__BASE__CONNECTION_H_ */ diff --git a/repos/base/include/base/debug.h b/repos/base/include/base/debug.h deleted file mode 100644 index d17086c3c7..0000000000 --- a/repos/base/include/base/debug.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * \brief Debugging output function - * \author Emery Hemingway - * \date 2016-10-13 - */ - -/* - * Copyright (C) 2016-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _INCLUDE__BASE__DEBUG_H_ -#define _INCLUDE__BASE__DEBUG_H_ -#ifndef GENODE_RELEASE - -#include - -#define PDBG(...) \ - Genode::log("\033[33m", __PRETTY_FUNCTION__, "\033[0m ", ##__VA_ARGS__) - -#endif /* GENODE_RELEASE */ -#endif /* _INCLUDE__BASE__DEBUG_H_ */ diff --git a/repos/base/include/base/entrypoint.h b/repos/base/include/base/entrypoint.h index 579016e210..d1a217d3c9 100644 --- a/repos/base/include/base/entrypoint.h +++ b/repos/base/include/base/entrypoint.h @@ -35,11 +35,9 @@ class Genode::Entrypoint : Noncopyable /** * Functor for post I/O signal progress handling * - * This mechanism is for processing I/O events - * deferred during signal dispatch. This is the - * case when the application is blocked by I/O - * but should not be resumed during signal - * dispatch. + * This mechanism is for processing I/O events deferred during signal + * dispatch. This is the case when the application is blocked by I/O + * but should not be resumed during signal dispatch. */ struct Io_progress_handler : Interface { @@ -78,7 +76,7 @@ class Genode::Entrypoint : Noncopyable ep(ep) { start(); } - void entry() override { ep._process_incoming_signals(); } + void entry() override; }; Env &_env; @@ -98,10 +96,6 @@ class Genode::Entrypoint : Noncopyable void _handle_deferred_signals() { } Constructible > _deferred_signal_handler { }; - bool _suspended = false; - void (*_suspended_callback) () = nullptr; - void (*_resumed_callback) () = nullptr; - bool _signal_proxy_delivers_signal { false }; Genode::Mutex _block_for_signal_mutex { }; @@ -113,15 +107,6 @@ class Genode::Entrypoint : Noncopyable _io_progress_handler->handle_io_progress(); } - /* - * This signal handler is solely used to force an iteration of the - * signal-dispatch loop. It is triggered by 'schedule_suspend' to - * let the signal-dispatching thread execute the actual suspend- - * resume mechanism. - */ - void _handle_suspend() { _suspended = true; } - Constructible > _suspend_dispatcher { }; - void _dispatch_signal(Signal &sig); void _defer_signal(Signal &sig); void _process_deferred_signals(); @@ -217,16 +202,6 @@ class Genode::Entrypoint : Noncopyable */ Rpc_entrypoint &rpc_ep() { return *_rpc_ep; } - /** - * Trigger a suspend-resume cycle in the entrypoint - * - * The 'suspended' callback is called after the entrypoint entered the - * safe suspend state. - * The 'resumed' callback is called when the entrypoint is fully - * functional again. - */ - void schedule_suspend(void (*suspended)(), void (*resumed)()); - /** * Register hook functor to be called after I/O signals are dispatched */ diff --git a/repos/base/include/base/heap.h b/repos/base/include/base/heap.h index e406dc75e1..f67918e10a 100644 --- a/repos/base/include/base/heap.h +++ b/repos/base/include/base/heap.h @@ -148,8 +148,7 @@ class Genode::Heap : public Allocator /** * Call 'fn' with the start and size of each backing-store region */ - template - void for_each_region(FN const &fn) const + void for_each_region(auto const &fn) const { Mutex::Guard guard(_mutex); for (Dataspace const *ds = _ds_pool.first(); ds; ds = ds->next()) diff --git a/repos/base/include/base/id_space.h b/repos/base/include/base/id_space.h index 95b69c0ab9..193ea25823 100644 --- a/repos/base/include/base/id_space.h +++ b/repos/base/include/base/id_space.h @@ -18,6 +18,7 @@ #include #include #include +#include #include namespace Genode { template class Id_space; } @@ -62,8 +63,8 @@ class Genode::Id_space : public Noncopyable return e ? e->_lookup(id) : 0; } - template - void _for_each(FUNC const &fn) const + template + void _for_each(auto const &fn) const { if (Avl_node::child(Avl_node_base::LEFT)) Avl_node::child(Avl_node_base::LEFT)->template _for_each(fn); @@ -172,8 +173,8 @@ class Genode::Id_space : public Noncopyable * This function is called with the ID space locked. Hence, it is not * possible to modify the ID space from within 'fn'. */ - template - void for_each(FUNC const &fn) const + template + void for_each(auto const &fn) const { Mutex::Guard guard(_mutex); @@ -181,6 +182,31 @@ class Genode::Id_space : public Noncopyable _elements.first()->template _for_each(fn); } + /** + * Apply functor 'fn' to object with given ID, or call 'missing_fn' + * + * See 'for_each' for a description of the 'ARG' argument. + * If the ID is not known, 'missing_fn' is called instead of 'fn'. + * Both 'fn' and 'missing_fn' must have the same return type. + */ + template + auto apply(Id id, FN const &fn, auto const &missing_fn) + -> typename Trait::Functor::Return_type + { + T *obj_ptr = nullptr; + { + Mutex::Guard guard(_mutex); + + if (_elements.first()) + if (Element *e = _elements.first()->_lookup(id)) + obj_ptr = &e->_obj; + } + if (obj_ptr) + return fn(static_cast(*obj_ptr)); + else + return missing_fn(); + } + /** * Apply functor 'fn' to object with given ID * @@ -188,24 +214,12 @@ class Genode::Id_space : public Noncopyable * * \throw Unknown_id */ - template - auto apply(Id id, FUNC const &fn) - -> typename Trait::Functor::Return_type + template + auto apply(Id id, FN const &fn) + -> typename Trait::Functor::Return_type { - T *obj = nullptr; - { - Mutex::Guard guard(_mutex); - - if (!_elements.first()) - throw Unknown_id(); - - if (Element *e = _elements.first()->_lookup(id)) - obj = &e->_obj; - } - if (obj) - return fn(static_cast(*obj)); - else - throw Unknown_id(); + using Result = typename Trait::Functor::Return_type; + return apply(id, fn, [&] () -> Result { throw Unknown_id(); }); } /** @@ -221,8 +235,8 @@ class Genode::Id_space : public Noncopyable * \return true if 'fn' was applied, or * false if the ID space is empty. */ - template - bool apply_any(FUNC const &fn) + template + bool apply_any(auto const &fn) { T *obj = nullptr; { diff --git a/repos/base/include/base/ipc.h b/repos/base/include/base/ipc.h index 6838d2f703..84920fd36b 100644 --- a/repos/base/include/base/ipc.h +++ b/repos/base/include/base/ipc.h @@ -30,7 +30,6 @@ namespace Genode { * Invoke capability to call an RPC function * * \param rcv_caps number of capabilities expected as result - * \throw Blocking_canceled * * \noapi * diff --git a/repos/base/include/base/ipc_msgbuf.h b/repos/base/include/base/ipc_msgbuf.h index 6b636824f3..d68623e5ab 100644 --- a/repos/base/include/base/ipc_msgbuf.h +++ b/repos/base/include/base/ipc_msgbuf.h @@ -39,7 +39,7 @@ class Genode::Msgbuf_base : Noncopyable * Resolve ambiguity if the header is included from a libc-using * program. */ - typedef Genode::size_t size_t; + using size_t = Genode::size_t; /* * Capabilities to be transferred diff --git a/repos/base/include/base/local_connection.h b/repos/base/include/base/local_connection.h index 56c1d2e721..dbacb8bca9 100644 --- a/repos/base/include/base/local_connection.h +++ b/repos/base/include/base/local_connection.h @@ -31,7 +31,7 @@ struct Genode::Local_connection_base : Noncopyable { public: - typedef Session_state::Args Args; + using Args = Session_state::Args; protected: @@ -114,7 +114,7 @@ class Genode::Local_connection : Local_connection_base { private: - typedef typename CONNECTION::Session_type SESSION; + using SESSION = typename CONNECTION::Session_type; Constructible _client { }; diff --git a/repos/base/include/base/lock.h b/repos/base/include/base/lock.h index dedc334669..10b1ff8688 100644 --- a/repos/base/include/base/lock.h +++ b/repos/base/include/base/lock.h @@ -14,9 +14,6 @@ #ifndef _INCLUDE__BASE__LOCK_H_ #define _INCLUDE__BASE__LOCK_H_ -#include -#include - namespace Genode { class Lock; class Thread; diff --git a/repos/base/include/base/lock_guard.h b/repos/base/include/base/lock_guard.h deleted file mode 100644 index 364b0e1117..0000000000 --- a/repos/base/include/base/lock_guard.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * \brief Lock guard - * \author Norman Feske - * \date 2006-07-26 - */ - -/* - * Copyright (C) 2006-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _INCLUDE__BASE__LOCK_GUARD_H_ -#define _INCLUDE__BASE__LOCK_GUARD_H_ - -namespace Genode { template class Lock_guard; } - - -/** - * Lock guard template - * - * \param LT lock type - * - * A lock guard is instantiated as a local variable. When a lock guard is - * constructed, it acquires the lock that is specified as constructor argument. - * When the control flow leaves the scope of the lock-guard variable via a - * return statement or an exception, the lock guard's destructor gets called, - * freeing the lock. - */ -template -class Genode::Lock_guard -{ - private: - - LT &_lock; - - public: - - explicit Lock_guard(LT &lock) : _lock(lock) { _lock.lock(); } - - ~Lock_guard() { _lock.unlock(); } -}; - -#endif /* _INCLUDE__BASE__LOCK_GUARD_H_ */ diff --git a/repos/base/include/base/log.h b/repos/base/include/base/log.h index 1cd59eda17..fb02268d0a 100644 --- a/repos/base/include/base/log.h +++ b/repos/base/include/base/log.h @@ -58,8 +58,7 @@ class Genode::Log Log(Output &output) : _output(output) { } - template - void output(Type type, ARGS &&... args) + void output(Type type, auto &&... args) { /* * This function is being inlined. Hence, we try to keep it as @@ -82,8 +81,7 @@ class Genode::Log */ struct Log_fn { - template - Log_fn(ARGS && ... args) { log().output(LOG, args...); } + Log_fn(auto && ... args) { log().output(LOG, args...); } }; }; @@ -103,8 +101,7 @@ class Genode::Raw public: - template - static void output(ARGS &&... args) + static void output(auto &&... args) { _acquire(); Output::out_args(_output(), args...); @@ -124,16 +121,14 @@ class Genode::Trace_output /* cannot include log_session.h here because of recursion */ enum { LOG_SESSION_MAX_STRING_LEN = 232 }; - typedef Buffered_output - Buffered_trace_output; + using Buffered_trace_output = + Buffered_output; public: Trace_output() { } - template - void output(ARGS &&... args) + void output(auto &&... args) { Buffered_trace_output buffered_trace_output { Write_trace_fn() }; @@ -152,8 +147,7 @@ class Genode::Trace_output */ struct Fn { - template - Fn(ARGS && ... args) + Fn(auto && ... args) { trace_output().output(Trace::timestamp(), ": ", args...); } @@ -166,8 +160,7 @@ namespace Genode { /** * Write 'args' as a regular message to the log */ - template - void log(ARGS &&... args) { Log::Log_fn(args...); } + void log(auto &&... args) { Log::Log_fn(args...); } /** @@ -177,8 +170,7 @@ namespace Genode { * the description of the 'error' function regarding the convention of * formatting error/warning messages. */ - template - void warning(ARGS &&... args) { Log::log().output(Log::WARNING, args...); } + void warning(auto &&... args) { Log::log().output(Log::WARNING, args...); } /** @@ -189,8 +181,7 @@ namespace Genode { * message. By convention, the actual message should be brief, starting * with a lower-case character. */ - template - void error(ARGS &&... args) { Log::log().output(Log::ERROR, args...); } + void error(auto &&... args) { Log::log().output(Log::ERROR, args...); } /** @@ -198,8 +189,7 @@ namespace Genode { * * This function is intended for temporarily debugging purposes only. */ - template - void raw(ARGS &&... args) { Raw::output(args...); } + void raw(auto &&... args) { Raw::output(args...); } /** @@ -207,8 +197,7 @@ namespace Genode { * * The message is prefixed with a timestamp value */ - template - void trace(ARGS && ... args) { Trace_output::Fn(args...); } + void trace(auto && ... args) { Trace_output::Fn(args...); } } @@ -220,7 +209,7 @@ class Genode::Log_tsc_probe : Noncopyable { private: - typedef Trace::Timestamp Timestamp; + using Timestamp = Trace::Timestamp; struct Pretty_tsc { diff --git a/repos/base/include/base/object_pool.h b/repos/base/include/base/object_pool.h index 1a2eb36793..45a61014ad 100644 --- a/repos/base/include/base/object_pool.h +++ b/repos/base/include/base/object_pool.h @@ -120,11 +120,11 @@ class Genode::Object_pool : Interface, Noncopyable _tree.remove(obj); } - template - auto apply(unsigned long capid, FUNC func) - -> typename Trait::Functor::Return_type + template + auto apply(unsigned long capid, FN const &fn) + -> typename Trait::Functor::Return_type { - using Functor = Trait::Functor; + using Functor = Trait::Functor; using Object_pointer = typename Functor::template Argument<0>::Type; using Weak_ptr = Weak_ptr; using Locked_ptr = Locked_ptr; @@ -144,19 +144,18 @@ class Genode::Object_pool : Interface, Noncopyable Locked_ptr lock_ptr(ptr); Object_pointer op = lock_ptr.valid() ? dynamic_cast(&lock_ptr->obj) : nullptr; - return func(op); + return fn(op); } } - template - auto apply(Untyped_capability cap, FUNC func) - -> typename Trait::Functor::Return_type + template + auto apply(Untyped_capability cap, FN const &fn) + -> typename Trait::Functor::Return_type { - return apply(cap.local_name(), func); + return apply(cap.local_name(), fn); } - template - void remove_all(FUNC func) + void remove_all(auto const &fn) { using Weak_ptr = Weak_ptr; using Locked_ptr = Locked_ptr; @@ -178,7 +177,7 @@ class Genode::Object_pool : Interface, Noncopyable } } - func(obj); + fn(obj); } } }; diff --git a/repos/base/include/base/output.h b/repos/base/include/base/output.h index 44f8d9ef50..ee2c7237d7 100644 --- a/repos/base/include/base/output.h +++ b/repos/base/include/base/output.h @@ -43,15 +43,13 @@ struct Genode::Output : Interface /** * Helper for the sequential output of a variable list of arguments */ - template - static void out_args(Output &output, HEAD && head, TAIL &&... tail) + static void out_args(Output &output, auto && head, auto &&... tail) { print(output, head); out_args(output, tail...); } - template - static void out_args(Output &output, LAST && last) { print(output, last); } + static void out_args(Output &output, auto && last) { print(output, last); } }; @@ -82,8 +80,7 @@ namespace Genode { * This function template takes precedence over the one that takes a * constant object reference as argument. */ - template - static inline void print(Output &output, T *ptr) + static inline void print(Output &output, auto *ptr) { print(output, (void const *)ptr); } @@ -173,9 +170,8 @@ namespace Genode { * output. If set to 'PAD', the leading zeros will be * printed. */ - template - explicit Hex(T value, Prefix prefix = PREFIX, Pad pad = NO_PAD) - : _value(value), _digits(2*sizeof(T)), _prefix(prefix), _pad(pad) { } + explicit Hex(auto value, Prefix prefix = PREFIX, Pad pad = NO_PAD) + : _value(value), _digits(2*sizeof(value)), _prefix(prefix), _pad(pad) { } void print(Output &output) const; }; @@ -224,8 +220,7 @@ namespace Genode { * method is able to access object-internal state, which can thereby be * incorporated into the textual output. */ - template - static inline void print(Output &output, T const &obj) + static inline void print(Output &output, auto const &obj) { obj.print(output); } @@ -233,8 +228,7 @@ namespace Genode { /** * Print a variable number of arguments */ - template - static inline void print(Output &output, HEAD const &head, TAIL &&... tail) + static inline void print(Output &output, auto const &head, auto &&... tail) { Output::out_args(output, head, tail...); } diff --git a/repos/base/include/base/quota_guard.h b/repos/base/include/base/quota_guard.h index f12105e631..394bc6c7f1 100644 --- a/repos/base/include/base/quota_guard.h +++ b/repos/base/include/base/quota_guard.h @@ -16,6 +16,7 @@ #include #include +#include namespace Genode { @@ -87,7 +88,7 @@ class Genode::Quota_guard_untyped * \return true if quota limit could be reduced, or * false if the requested amount exceeds the available quota */ - bool try_downgrade(size_t const amount) + [[nodiscard]] bool try_downgrade(size_t const amount) { if (avail() < amount) return false; @@ -102,7 +103,7 @@ class Genode::Quota_guard_untyped * \return true on success, or * false if the amount exceeds the available quota */ - bool try_withdraw(size_t const amount) + [[nodiscard]] bool try_withdraw(size_t const amount) { if (amount > avail()) return false; @@ -184,6 +185,14 @@ class Genode::Quota_guard */ void upgrade(UNIT amount) { _guard.upgrade(amount.value); } + /** + * Try to withdraw quota by specified amount + */ + bool try_withdraw(UNIT amount) + { + return _guard.try_withdraw(amount.value); + } + /** * Try to decrease quota limit by specified amount */ @@ -249,10 +258,10 @@ class Genode::Quota_guard void acknowledge() { _ack = true; } }; - template - RET with_reservation(UNIT const amount, - FN const &fn, - ERROR_FN const &error_fn) + template + RET with_reservation(UNIT const amount, + auto const &fn, + auto const &error_fn) { if (!_guard.try_withdraw(amount.value)) return error_fn(); @@ -280,11 +289,11 @@ class Genode::Quota_guard namespace Genode { - typedef Quota_guard Ram_quota_guard; - typedef Quota_guard Cap_quota_guard; + using Ram_quota_guard = Quota_guard; + using Cap_quota_guard = Quota_guard; - typedef Ram_quota_guard::Limit_exceeded Out_of_ram; - typedef Cap_quota_guard::Limit_exceeded Out_of_caps; + using Out_of_ram = Ram_quota_guard::Limit_exceeded; + using Out_of_caps = Cap_quota_guard::Limit_exceeded; } #endif /* _INCLUDE__BASE__QUOTA_GUARD_H_ */ diff --git a/repos/base/include/base/quota_transfer.h b/repos/base/include/base/quota_transfer.h index 2832955948..50bac4d24a 100644 --- a/repos/base/include/base/quota_transfer.h +++ b/repos/base/include/base/quota_transfer.h @@ -19,10 +19,10 @@ namespace Genode { - template class Quota_transfer; + template class Quota_transfer; - typedef Quota_transfer Ram_transfer; - typedef Quota_transfer Cap_transfer; + using Ram_transfer = Quota_transfer; + using Cap_transfer = Quota_transfer; } @@ -38,15 +38,15 @@ namespace Genode { * exception), the destructor the transfer object reverts the transfer in * flight. */ -template +template class Genode::Quota_transfer { public: - class Quota_exceeded : Exception { }; - struct Account : Noncopyable, Interface { + using Transfer_result = RESULT; + /** * Return capability used for transfers to the account * @@ -61,13 +61,11 @@ class Genode::Quota_transfer /** * Transfer quota to the specified account - * - * \throw Out_of_ram - * \throw Out_of_caps - * \throw Invalid_session - * \throw Undefined_ref_account */ - virtual void transfer(Capability, UNIT) { } + virtual Transfer_result transfer(Capability, UNIT) + { + return Transfer_result::OK; + } /** * Try to transfer quota, ignoring possible exceptions @@ -76,7 +74,7 @@ class Genode::Quota_transfer */ void try_transfer(Capability to, UNIT amount) { - try { transfer(to, amount); } catch (...) { } + transfer(to, amount); } }; @@ -93,9 +91,12 @@ class Genode::Quota_transfer Capability cap(UNIT) const override { return _cap; } - void transfer(Capability to, UNIT amount) override + using Transfer_result = RESULT; + + Transfer_result transfer(Capability to, UNIT amount) override { - if (to.valid()) _session.transfer_quota(to, amount); + return to.valid() ? _session.transfer_quota(to, amount) + : Transfer_result::OK; } }; @@ -106,14 +107,20 @@ class Genode::Quota_transfer Account &_from; Account &_to; + static bool _exceeded(Ram_quota, RESULT r) { return (r == RESULT::OUT_OF_RAM); } + static bool _exceeded(Cap_quota, RESULT r) { return (r == RESULT::OUT_OF_CAPS); } + public: + class Quota_exceeded : Exception { }; + /** * Constructor * * \param amount amount of quota to transfer * \param from donor account * \param to receiving account + * \throw Quota_exceeded */ Quota_transfer(UNIT amount, Account &from, Account &to) : @@ -122,11 +129,8 @@ class Genode::Quota_transfer if (!_from.cap(UNIT()).valid() || !_to.cap(UNIT()).valid()) return; - try { _from.transfer(_to.cap(UNIT()), amount); } - catch (typename SESSION::Undefined_ref_account) { } - catch (typename SESSION::Invalid_session) { } - catch (... /* 'Out_of_ram' / 'Out_of_caps' */) { - throw Quota_exceeded(); } + if (_exceeded(UNIT{}, _from.transfer(_to.cap(UNIT()), amount))) + throw Quota_exceeded(); } /** diff --git a/repos/base/include/base/ram_allocator.h b/repos/base/include/base/ram_allocator.h index 46225e4592..a11d3f6a4d 100644 --- a/repos/base/include/base/ram_allocator.h +++ b/repos/base/include/base/ram_allocator.h @@ -24,7 +24,7 @@ namespace Genode { struct Ram_dataspace : Dataspace { }; - typedef Capability Ram_dataspace_capability; + using Ram_dataspace_capability = Capability; struct Ram_allocator; diff --git a/repos/base/include/base/registry.h b/repos/base/include/base/registry.h index 4fcd3cb8f2..0209feb51d 100644 --- a/repos/base/include/base/registry.h +++ b/repos/base/include/base/registry.h @@ -109,13 +109,14 @@ struct Genode::Registry : private Registry_base : Registry_base::Element(registry, &obj) { } }; - template - void for_each(FUNC const &fn) + void for_each(auto const &fn) { + using FN = decltype(fn); + struct Typed_functor : Registry_base::Untyped_functor { - FUNC const &_fn; - Typed_functor(FUNC const &fn) : _fn(fn) { } + FN const &_fn; + Typed_functor(FN const &fn) : _fn(fn) { } void call(void *obj_ptr) override { @@ -127,8 +128,7 @@ struct Genode::Registry : private Registry_base Registry_base::_for_each(untyped_functor); } - template - void for_each(FUNC const &fn) const + void for_each(auto const &fn) const { Mutex::Guard guard(_mutex); @@ -170,8 +170,7 @@ class Genode::Registered : public T */ static_assert(__has_virtual_destructor(T), "registered object must have virtual destructor"); - template - Registered(Registry > ®istry, ARGS &&... args) + Registered(Registry > ®istry, auto &&... args) : T(args...), _element(registry, *this) { } }; @@ -193,8 +192,7 @@ class Genode::Registered_no_delete : public T public: - template - Registered_no_delete(Registry > ®istry, ARGS &&... args) + Registered_no_delete(Registry > ®istry, auto &&... args) : T(args...), _element(registry, *this) { } }; diff --git a/repos/base/include/base/rpc.h b/repos/base/include/base/rpc.h index db31fbfc23..5462573bd9 100644 --- a/repos/base/include/base/rpc.h +++ b/repos/base/include/base/rpc.h @@ -37,10 +37,10 @@ */ #define GENODE_RPC_THROW(rpc_name, ret_type, func_name, exc_types, ...) \ struct rpc_name { \ - typedef ::Genode::Meta::Ref_args<__VA_ARGS__>::Type Client_args; \ - typedef ::Genode::Meta::Pod_args<__VA_ARGS__>::Type Server_args; \ - typedef ::Genode::Trait::Exc_list::Type Exceptions; \ - typedef ::Genode::Trait::Call_return::Type Ret_type; \ + using Client_args = ::Genode::Meta::Ref_args<__VA_ARGS__>::Type; \ + using Server_args = ::Genode::Meta::Pod_args<__VA_ARGS__>::Type; \ + using Exceptions = ::Genode::Trait::Exc_list::Type; \ + using Ret_type = ::Genode::Trait::Call_return::Type; \ \ template \ static RET serve(SERVER &server, Server_args &args) { \ @@ -66,7 +66,7 @@ * this type list. */ #define GENODE_RPC_INTERFACE(...) \ - typedef GENODE_TYPE_LIST(__VA_ARGS__) Rpc_functions + using Rpc_functions = GENODE_TYPE_LIST(__VA_ARGS__) /** * Macro for declaring a RPC interface derived from another RPC interface @@ -80,10 +80,9 @@ * the inherited RPC functions are preserved. */ #define GENODE_RPC_INTERFACE_INHERIT(base, ...) \ - typedef ::Genode::Meta::Append::Type \ - Rpc_functions; \ - typedef base Rpc_inherited_interface; + using Rpc_functions = ::Genode::Meta::Append::Type; \ + using Rpc_inherited_interface = base; namespace Genode { @@ -101,11 +100,11 @@ namespace Genode { template struct Rpc_direction; - template struct Rpc_direction { typedef Rpc_arg_in Type; }; - template struct Rpc_direction { typedef Rpc_arg_in Type; }; - template struct Rpc_direction { typedef Rpc_arg_in Type; }; - template struct Rpc_direction { typedef Rpc_arg_inout Type; }; - template struct Rpc_direction { typedef Rpc_arg_inout Type; }; + template struct Rpc_direction { using Type = Rpc_arg_in; }; + template struct Rpc_direction { using Type = Rpc_arg_in; }; + template struct Rpc_direction { using Type = Rpc_arg_in; }; + template struct Rpc_direction { using Type = Rpc_arg_inout; }; + template struct Rpc_direction { using Type = Rpc_arg_inout; }; /** * Representation of function return type @@ -115,8 +114,8 @@ namespace Genode { * regardless of the presence of a return type with the same meta * program. */ - template struct Call_return { typedef T Type; }; - template <> struct Call_return { typedef Meta::Empty Type; }; + template struct Call_return { using Type = T; }; + template <> struct Call_return { using Type = Meta::Empty; }; /** * Representation of the list of exception types @@ -124,8 +123,8 @@ namespace Genode { * This template maps the special case of a 'Type_list' with no arguments * to the 'Empty' type. */ - template struct Exc_list { typedef T Type; }; - template <> struct Exc_list > { typedef Meta::Empty Type; }; + template struct Exc_list { using Type = T; }; + template <> struct Exc_list > { using Type = Meta::Empty; }; } @@ -167,29 +166,27 @@ namespace Genode { { long value; - enum { - SUCCESS = 0, + static constexpr long SUCCESS = 0; - /** - * Server-side object does not exist - * - * This exception code is not meant to be reflected from the server - * to the client. On kernels with capability support, the condition - * can never occur. On kernels without capability protection, the - * code is merely used for diagnostic purposes at the server side. - */ - INVALID_OBJECT = -1, + /** + * Server-side object does not exist + * + * This exception code is not meant to be reflected from the server + * to the client. On kernels with capability support, the condition + * can never occur. On kernels without capability protection, the + * code is merely used for diagnostic purposes at the server side. + */ + static constexpr long INVALID_OBJECT = -1; - /** - * Special exception code used to respond to illegal opcodes - */ - INVALID_OPCODE = -2, + /** + * Special exception code used to respond to illegal opcodes + */ + static constexpr long INVALID_OPCODE = -2; - /** - * Opcode base used for passing exception information - */ - EXCEPTION_BASE = -1000 - }; + /** + * Opcode base used for passing exception information + */ + static constexpr long EXCEPTION_BASE = -1000; explicit Rpc_exception_code(int value) : value(value) { } }; @@ -204,7 +201,7 @@ namespace Genode { */ template struct Rpc_args_size { - typedef typename ARGS::Head This; + using This = typename ARGS::Head; enum { This_size = Rpc_transfer_size::Value }; enum { Value = (IN && Trait::Rpc_direction::Type::IN ? This_size : 0) + (OUT && Trait::Rpc_direction::Type::OUT ? This_size : 0) @@ -237,7 +234,7 @@ namespace Genode { */ template struct Rpc_msg_payload_size { - typedef typename RPC_FUNCTION::Server_args Args; + using Args = typename RPC_FUNCTION::Server_args; enum { Value = Rpc_args_size::Value }; }; @@ -268,14 +265,16 @@ namespace Genode { template struct Rpc_function_msg_size { - enum { Value = Rpc_msg_payload_size::Value - + sizeof(Rpc_opcode) }; }; + static constexpr unsigned + Value = Rpc_msg_payload_size::Value + + sizeof(Rpc_opcode); }; template struct Rpc_function_msg_size { - enum { Value = Rpc_msg_payload_size::Value - + Rpc_retval_size::Value - + sizeof(Rpc_exception_code) }; }; + static constexpr unsigned + Value = Rpc_msg_payload_size::Value + + Rpc_retval_size::Value + + sizeof(Rpc_exception_code); }; /** @@ -305,7 +304,7 @@ namespace Genode { */ template struct Rpc_interface_msg_size { - typedef typename RPC_IF::Rpc_functions Rpc_functions; + using Rpc_functions = typename RPC_IF::Rpc_functions; enum { Value = Rpc_function_list_msg_size::Value }; }; @@ -315,8 +314,8 @@ namespace Genode { template struct Rpc_interface_is_inherited { - typedef char yes[1]; - typedef char no[2]; + using yes = char[1]; + using no = char[2]; template static yes &test(typename IF::Rpc_inherited_interface *); diff --git a/repos/base/include/base/rpc_client.h b/repos/base/include/base/rpc_client.h index 491a28f3d0..ae4129aa47 100644 --- a/repos/base/include/base/rpc_client.h +++ b/repos/base/include/base/rpc_client.h @@ -49,16 +49,18 @@ namespace Genode { template struct Rpc_caps_out { - enum { Value = Cap_para_out::Value - + Rpc_caps_out::Value }; }; + static constexpr unsigned + Value = Cap_para_out::Value + + Rpc_caps_out::Value; }; template <> - struct Rpc_caps_out { enum { Value = 0 }; }; + struct Rpc_caps_out { static constexpr unsigned Value = 0; }; template struct Rpc_function_caps_out { - enum { Value = Rpc_caps_out::Value + - Cap_return ::Value}; }; + static constexpr unsigned + Value = Rpc_caps_out::Value + + Cap_return ::Value; }; /*************************************************** @@ -107,7 +109,7 @@ namespace Genode { * '_unmarshal_result' is selected depending on the RPC * direction. */ - typedef typename Trait::Rpc_direction::Type Rpc_dir; + using Rpc_dir = typename Trait::Rpc_direction::Type; _unmarshal_result(unmarshaller, args.get(), Meta::Overload_selector()); /* unmarshal remaining arguments */ @@ -135,7 +137,7 @@ namespace Genode { Msgbuf reply_buf; /* determine opcode of RPC function */ - typedef typename RPC_INTERFACE::Rpc_functions Rpc_functions; + using Rpc_functions = typename RPC_INTERFACE::Rpc_functions; Rpc_opcode opcode(static_cast(Meta::Index_of::Value)); /* marshal opcode and RPC input arguments */ @@ -192,7 +194,7 @@ class Genode::Rpc_client : public RPC_INTERFACE public: - typedef RPC_INTERFACE Rpc_interface; + using Rpc_interface = RPC_INTERFACE; Rpc_client(Capability const &cap) : _cap(cap) { } diff --git a/repos/base/include/base/rpc_server.h b/repos/base/include/base/rpc_server.h index 66998550eb..52c9203f00 100644 --- a/repos/base/include/base/rpc_server.h +++ b/repos/base/include/base/rpc_server.h @@ -60,7 +60,7 @@ class Genode::Rpc_dispatcher : public RPC_INTERFACE * Shortcut for the type list of RPC functions provided by this server * component */ - typedef typename RPC_INTERFACE::Rpc_functions Rpc_functions; + using Rpc_functions = typename RPC_INTERFACE::Rpc_functions; protected: @@ -69,7 +69,7 @@ class Genode::Rpc_dispatcher : public RPC_INTERFACE Meta::Overload_selector) { typename Trait::Rpc_direction::Type direction; - typedef typename ARG_LIST::Stored_head Arg; + using Arg = typename ARG_LIST::Stored_head; Arg arg = _read_arg(msg, direction); Meta::Overload_selector tail_selector; @@ -120,10 +120,11 @@ class Genode::Rpc_dispatcher : public RPC_INTERFACE _do_serve(typename RPC_FUNCTION::Server_args &args, Meta::Overload_selector) { - enum { EXCEPTION_CODE = Rpc_exception_code::EXCEPTION_BASE - - Meta::Length::Value }; + static constexpr unsigned + EXCEPTION_CODE = Rpc_exception_code::EXCEPTION_BASE + - Meta::Length::Value; try { - typedef typename EXC_TL::Tail Exc_tail; + using Exc_tail = typename EXC_TL::Tail; return _do_serve(args, Meta::Overload_selector()); } catch (typename EXC_TL::Head) { @@ -141,7 +142,7 @@ class Genode::Rpc_dispatcher : public RPC_INTERFACE _do_serve(typename RPC_FUNCTION::Server_args &args, Meta::Overload_selector) { - typedef typename RPC_FUNCTION::Ret_type Ret_type; + using Ret_type = typename RPC_FUNCTION::Ret_type; SERVER *me = static_cast(this); return RPC_FUNCTION::template serve(*me, args); } @@ -153,12 +154,12 @@ class Genode::Rpc_dispatcher : public RPC_INTERFACE { using namespace Meta; - typedef typename RPC_FUNCTIONS_TO_CHECK::Head This_rpc_function; + using This_rpc_function = typename RPC_FUNCTIONS_TO_CHECK::Head; if (opcode.value == Index_of::Value) { /* read arguments from incoming message */ - typedef typename This_rpc_function::Server_args Server_args; + using Server_args = typename This_rpc_function::Server_args; Meta::Overload_selector arg_selector; Server_args args = _read_args(in, arg_selector); @@ -172,10 +173,10 @@ class Genode::Rpc_dispatcher : public RPC_INTERFACE * select the overload. */ - typedef typename This_rpc_function::Ret_type Ret_type; + using Ret_type = typename This_rpc_function::Ret_type; Rpc_exception_code exc(Rpc_exception_code::SUCCESS); try { - typedef typename This_rpc_function::Exceptions Exceptions; + using Exceptions = typename This_rpc_function::Exceptions; Overload_selector overloader; Ret_type ret = _do_serve(args, overloader); @@ -197,7 +198,7 @@ class Genode::Rpc_dispatcher : public RPC_INTERFACE return exc; } - typedef typename RPC_FUNCTIONS_TO_CHECK::Tail Tail; + using Tail = typename RPC_FUNCTIONS_TO_CHECK::Tail; return _do_dispatch(opcode, in, out, Overload_selector()); } diff --git a/repos/base/include/base/service.h b/repos/base/include/base/service.h index 2eaf528c25..93275a6c51 100644 --- a/repos/base/include/base/service.h +++ b/repos/base/include/base/service.h @@ -39,7 +39,10 @@ class Genode::Service : public Ram_transfer::Account, { public: - typedef Session_state::Name Name; + using Name = Session_state::Name; + + using Ram_transfer_result = Ram_transfer::Account::Transfer_result; + using Cap_transfer_result = Cap_transfer::Account::Transfer_result; private: @@ -47,7 +50,7 @@ class Genode::Service : public Ram_transfer::Account, protected: - typedef Session_state::Factory Factory; + using Factory = Session_state::Factory; /** * Return factory to use for creating 'Session_state' objects @@ -77,8 +80,7 @@ class Genode::Service : public Ram_transfer::Account, * session state. All subsequent 'Session_state' arguments correspond * to the forwarded 'args'. */ - template - Session_state &create_session(Factory &client_factory, ARGS &&... args) + Session_state &create_session(Factory &client_factory, auto &&... args) { return _factory(client_factory).create(*this, args...); } @@ -112,7 +114,7 @@ class Genode::Local_service : public Service struct Factory : Interface { - typedef Session_state::Args Args; + using Args = Session_state::Args; /** * Create session @@ -134,7 +136,7 @@ class Genode::Local_service : public Service { private: - typedef Session_state::Args Args; + using Args = Session_state::Args; SESSION &_s; @@ -151,8 +153,7 @@ class Genode::Local_service : public Service Factory &_factory; - template - void _apply_to_rpc_obj(Session_state &session, FUNC const &fn) + void _apply_to_rpc_obj(Session_state &session, auto const &fn) { SESSION *rpc_obj = dynamic_cast(session.local_ptr); @@ -357,6 +358,8 @@ class Genode::Parent_service : public Try_parent_service void initiate_request(Session_state &session) override { + Session_state::Phase original_phase = session.phase; + for (unsigned i = 0; i < 10; i++) { try { @@ -367,11 +370,13 @@ class Genode::Parent_service : public Try_parent_service Ram_quota ram_quota { ram_quota_from_args(session.args().string()) }; Parent::Resource_args args(String<64>("ram_quota=", ram_quota)); _env.parent().resource_request(args); + session.phase = original_phase; } catch (Out_of_caps) { Cap_quota cap_quota { cap_quota_from_args(session.args().string()) }; Parent::Resource_args args(String<64>("cap_quota=", cap_quota)); _env.parent().resource_request(args); + session.phase = original_phase; } } @@ -471,9 +476,10 @@ class Genode::Child_service : public Async_service /** * Ram_transfer::Account interface */ - void transfer(Pd_session_capability to, Ram_quota amount) override + Ram_transfer_result transfer(Pd_session_capability to, Ram_quota amount) override { - if (to.valid()) _pd.transfer_quota(to, amount); + return to.valid() ? _pd.transfer_quota(to, amount) + : Ram_transfer_result::OK; } /** @@ -484,9 +490,10 @@ class Genode::Child_service : public Async_service /** * Cap_transfer::Account interface */ - void transfer(Pd_session_capability to, Cap_quota amount) override + Cap_transfer_result transfer(Pd_session_capability to, Cap_quota amount) override { - if (to.valid()) _pd.transfer_quota(to, amount); + return to.valid() ? _pd.transfer_quota(to, amount) + : Cap_transfer_result::OK; } /** diff --git a/repos/base/include/base/session_label.h b/repos/base/include/base/session_label.h index e5728ed7a7..e23b3b2928 100644 --- a/repos/base/include/base/session_label.h +++ b/repos/base/include/base/session_label.h @@ -15,7 +15,6 @@ #ifndef _INCLUDE__BASE__SESSION_LABEL_H_ #define _INCLUDE__BASE__SESSION_LABEL_H_ -#include #include #include @@ -40,8 +39,7 @@ struct Genode::Session_label : String<160> * copy constructors as candidate. */ template - Session_label(Genode::String const &other) - : Genode::String<160>(other) { } + Session_label(Genode::String const &other) : Genode::String<160>(other) { } Session_label last_element() const { diff --git a/repos/base/include/base/session_object.h b/repos/base/include/base/session_object.h index b9d47e7a3e..78f0e15181 100644 --- a/repos/base/include/base/session_object.h +++ b/repos/base/include/base/session_object.h @@ -27,10 +27,12 @@ class Genode::Session_object : private Ram_quota_guard, { public: - typedef Session::Label Label; - typedef Session::Diag Diag; - typedef Session::Resources Resources; + using Label = Session::Label; + using Diag = Session::Diag; + using Resources = Session::Resources; + using Ram_quota_guard::try_withdraw; + using Cap_quota_guard::try_withdraw; using Ram_quota_guard::withdraw; using Cap_quota_guard::withdraw; using Ram_quota_guard::replenish; @@ -101,8 +103,7 @@ class Genode::Session_object : private Ram_quota_guard, * The method produces output only if the session is in diagnostic * mode (defined via the 'diag' session argument). */ - template - void diag(ARGS &&... args) + void diag(auto &&... args) const { if (_diag.enabled) log(RPC_INTERFACE::service_name(), " (", _label, ") ", args...); @@ -111,8 +112,7 @@ class Genode::Session_object : private Ram_quota_guard, /** * Output label-prefixed error message */ - template - void error(ARGS &&... args) + void error(auto &&... args) const { Genode::error(RPC_INTERFACE::service_name(), " (", _label, ") ", args...); } @@ -120,8 +120,7 @@ class Genode::Session_object : private Ram_quota_guard, /** * Output label-prefixed error message */ - template - void warning(ARGS &&... args) + void warning(auto &&... args) const { Genode::warning(RPC_INTERFACE::service_name(), " (", _label, ") ", args...); } diff --git a/repos/base/include/base/session_state.h b/repos/base/include/base/session_state.h index f56af45e71..bc3289fb0c 100644 --- a/repos/base/include/base/session_state.h +++ b/repos/base/include/base/session_state.h @@ -37,8 +37,8 @@ class Genode::Session_state : public Parent::Client, public Parent::Server class Factory; - typedef String<32> Name; - typedef String<256> Args; + using Name = String<32>; + using Args = String<256>; struct Ready_callback : Interface { @@ -323,8 +323,7 @@ class Genode::Session_state::Factory : Noncopyable * * \throw Allocator::Out_of_memory */ - template - Session_state &create(ARGS &&... args) + Session_state &create(auto &&... args) { Session_state &session = *new (_slab) Session_state(args...); session.owner(*this); diff --git a/repos/base/include/base/shared_object.h b/repos/base/include/base/shared_object.h index f4dd1622fe..a8df46220a 100644 --- a/repos/base/include/base/shared_object.h +++ b/repos/base/include/base/shared_object.h @@ -128,7 +128,7 @@ class Genode::Dynamic_linker struct Object_info { /* name of shared library, or "binary" for the main program */ - typedef String<64> Name; + using Name = String<64>; Name name; Rom_dataspace_capability ds_cap; @@ -177,8 +177,8 @@ class Genode::Dynamic_linker */ static void keep(Env &, char const *name); - typedef Shared_object::Invalid_rom_module Invalid_rom_module; - typedef Shared_object::Invalid_symbol Invalid_symbol; + using Invalid_rom_module = Shared_object::Invalid_rom_module; + using Invalid_symbol = Shared_object::Invalid_symbol; /** * Replace executable binary diff --git a/repos/base/include/base/signal.h b/repos/base/include/base/signal.h index 73efca52f9..f91d195b75 100644 --- a/repos/base/include/base/signal.h +++ b/repos/base/include/base/signal.h @@ -21,6 +21,7 @@ #include #include #include +#include /* only needed for base-hw */ namespace Kernel { struct Signal_receiver; } @@ -29,6 +30,7 @@ namespace Genode { class Entrypoint; class Rpc_entrypoint; + class Pd_session; class Signal_source; class Signal_receiver; @@ -41,7 +43,7 @@ namespace Genode { template class Signal_handler; template class Io_signal_handler; - typedef Capability Signal_context_capability; + using Signal_context_capability = Capability; } @@ -299,20 +301,23 @@ class Genode::Signal_receiver : Noncopyable void remove(Signal_context const *re); - template - void for_each_locked(FUNC && functor) const + void for_each_locked(auto const &fn) const { Signal_context *context = _head; - if (!context) return; + if (!context) + return; do { Mutex::Guard mutex_guard(context->_mutex); - if (functor(*context)) return; + if (fn(*context)) + return; context = context->_next; } while (context != _head); } }; + Pd_session &_pd; + /** * Semaphore used to indicate that signal(s) are ready to be picked * up. This is needed for platforms other than 'base-hw' only. @@ -338,7 +343,7 @@ class Genode::Signal_receiver : Noncopyable * and 'dissolve'. Note that '_contexts_mutex' must be held when * calling this method. */ - void _unsynchronized_dissolve(Signal_context *context); + void _unsynchronized_dissolve(Signal_context &); /** * Hook to platform specific destructor parts @@ -348,25 +353,12 @@ class Genode::Signal_receiver : Noncopyable /** * Hooks to platform specific dissolve parts */ - void _platform_begin_dissolve(Signal_context * const c); - void _platform_finish_dissolve(Signal_context * const c); + void _platform_begin_dissolve (Signal_context &); + void _platform_finish_dissolve(Signal_context &); public: - /** - * Exception class - */ - class Context_already_in_use { }; - class Context_not_associated { }; - - /** - * Constructor - */ Signal_receiver(); - - /** - * Destructor - */ ~Signal_receiver(); /** @@ -374,19 +366,17 @@ class Genode::Signal_receiver : Noncopyable * * \param context context associated with signals delivered to the * receiver - * \throw 'Context_already_in_use' * \return new signal-context capability that can be * passed to a signal transmitter */ - Signal_context_capability manage(Signal_context *context); + Signal_context_capability manage(Signal_context &context); /** * Dissolve signal context from receiver * * \param context context to remove from receiver - * \throw 'Context_not_associated' */ - void dissolve(Signal_context *context); + void dissolve(Signal_context &context); /** * Block until a signal is received and return the signal @@ -428,7 +418,7 @@ class Genode::Signal_receiver : Noncopyable * source associated with the process. It must not be used for other * purposes. */ - static void dispatch_signals(Signal_source *); + static void dispatch_signals(Signal_source &); }; diff --git a/repos/base/include/base/slab.h b/repos/base/include/base/slab.h index 3e9d9d05aa..d6fe19d9a1 100644 --- a/repos/base/include/base/slab.h +++ b/repos/base/include/base/slab.h @@ -109,13 +109,8 @@ class Genode::Slab : public Allocator */ ~Slab(); - /** - * Return number of bytes consumed per slab entry - * - * The function takes the slab-internal meta-data needs and the actual - * slab entry into account. - */ - static size_t entry_costs(size_t slab_size, size_t block_size); + static constexpr size_t overhead_per_block() { return 4*sizeof(addr_t); } + static constexpr size_t overhead_per_entry() { return sizeof(addr_t) + 1; } /** * Return number of unused slab entries diff --git a/repos/base/include/base/synced_allocator.h b/repos/base/include/base/synced_allocator.h index 6298ae617b..084e060e03 100644 --- a/repos/base/include/base/synced_allocator.h +++ b/repos/base/include/base/synced_allocator.h @@ -44,8 +44,7 @@ class Genode::Synced_allocator : public Allocator using Guard = typename Synced_interface::Guard; - template - Synced_allocator(ARGS &&... args) + Synced_allocator(auto &&... args) : _alloc(args...), _synced_object(_mutex, &_alloc) { } Guard operator () () { return _synced_object(); } diff --git a/repos/base/include/base/thread.h b/repos/base/include/base/thread.h index 08f7531afb..af3c86d929 100644 --- a/repos/base/include/base/thread.h +++ b/repos/base/include/base/thread.h @@ -28,7 +28,6 @@ namespace Genode { class Thread; class Stack; class Env; - template class Thread_deprecated; } @@ -46,9 +45,9 @@ class Genode::Thread class Stack_too_large : public Exception { }; class Stack_alloc_failed : public Exception { }; - typedef Affinity::Location Location; - typedef Cpu_session::Name Name; - typedef Cpu_session::Weight Weight; + using Location = Affinity::Location; + using Name = Cpu_session::Name; + using Weight = Cpu_session::Weight; struct Stack_info { addr_t base; addr_t top; addr_t libc_tls_pointer_offset; }; @@ -96,11 +95,12 @@ class Genode::Thread protected: /** - * Capability for this thread (set by _start()) + * Capability for this thread or creation error (set by _start()) * * Used if thread creation involves core's CPU service. */ - Thread_capability _thread_cap { }; + Cpu_session::Create_thread_result _thread_cap = + Cpu_session::Create_thread_error::DENIED; /** * Pointer to cpu session used for this thread @@ -168,11 +168,6 @@ class Genode::Thread * * \noapi * - * FIXME: With type = Forked_main_thread the stack allocation - * gets skipped but we should at least set Stack::ds_cap in a - * way that it references the dataspace of the already attached - * stack. - * * \deprecated superseded by the 'Thread(Env &...' constructor */ Thread(size_t weight, const char *name, size_t stack_size, @@ -271,13 +266,15 @@ class Genode::Thread */ virtual void entry() = 0; + enum class Start_result { OK, DENIED }; + /** * Start execution of the thread * * This method is virtual to enable the customization of threads * used as server activation. */ - virtual void start(); + virtual Start_result start(); /** * Request name of thread @@ -316,7 +313,15 @@ class Genode::Thread /** * Request capability of thread */ - Thread_capability cap() const { return _thread_cap; } + Thread_capability cap() const + { + return _thread_cap.convert( + [&] (Thread_capability cap) { return cap; }, + [&] (auto) { + error("attempt to obtain cap of incomplete thread"); + return Thread_capability(); + }); + } /** * Return kernel-specific thread meta data @@ -421,8 +426,7 @@ class Genode::Thread /** * Log trace event as defined in base/trace/events.h */ - template - static void trace(EVENT const *event) { _logger()->log(event); } + static void trace(auto const *event) { _logger()->log(event); } /** * Thread affinity diff --git a/repos/base/include/base/thread_state.h b/repos/base/include/base/thread_state.h index 2c1da93bc1..88e5831f91 100644 --- a/repos/base/include/base/thread_state.h +++ b/repos/base/include/base/thread_state.h @@ -18,13 +18,12 @@ namespace Genode { struct Thread_state; } -struct Genode::Thread_state : Cpu_state -{ - bool unresolved_page_fault = false; - bool exception = false; - Thread_state() { }; - Thread_state(Cpu_state &c) : Cpu_state(c) { }; +struct Genode::Thread_state +{ + enum class State { VALID, UNAVAILABLE, PAGE_FAULT, EXCEPTION } state; + + Cpu_state cpu; }; #endif /* _INCLUDE__BASE__THREAD_STATE_H_ */ diff --git a/repos/base/include/base/trace/buffer.h b/repos/base/include/base/trace/buffer.h index 4ad84bb640..de5d2f3eae 100644 --- a/repos/base/include/base/trace/buffer.h +++ b/repos/base/include/base/trace/buffer.h @@ -160,8 +160,7 @@ class Genode::Trace::Simple_buffer _head_entry()->mark(_Entry::HEAD); } - template - char *_reserve(size_t len, WRAP_FUNC && wrap) + char *_reserve(size_t len, auto const &wrap_fn) { if (_head_offset + sizeof(_Entry) + len <= _size) return _head_entry()->data; @@ -170,11 +169,10 @@ class Genode::Trace::Simple_buffer if (_head_offset + sizeof(_Entry) <= _size) _head_entry()->mark(_Entry::PADDING); - return wrap(); + return wrap_fn(); } - template - void _commit(size_t len, WRAP_FUNC && wrap) + void _commit(size_t len, auto const &wrap_fn) { /* omit empty entries */ if (len == 0) @@ -185,12 +183,12 @@ class Genode::Trace::Simple_buffer * the new head */ size_t *old_head_len = &_head_entry()->len; - _num_entries++; + _num_entries = _num_entries + 1; /* advance head offset, wrap when next entry does not fit into buffer */ _head_offset += sizeof(_Entry) + len; if (_head_offset + sizeof(_Entry) > _size) - wrap(); + wrap_fn(); /* mark entry next to new entry as head */ else if (_head_offset + sizeof(_Entry) <= _size) diff --git a/repos/base/include/base/trace/logger.h b/repos/base/include/base/trace/logger.h index 73e93bb4b6..d725490702 100644 --- a/repos/base/include/base/trace/logger.h +++ b/repos/base/include/base/trace/logger.h @@ -77,9 +77,8 @@ struct Genode::Trace::Logger /** * Log event to trace buffer */ - template __attribute__((optimize("-fno-delete-null-pointer-checks"))) - void log(EVENT const *event) + void log(auto const *event) { if (!this || !_evaluate_control()) return; diff --git a/repos/base/include/base/trace/types.h b/repos/base/include/base/trace/types.h index 60f8673337..b68e66c750 100644 --- a/repos/base/include/base/trace/types.h +++ b/repos/base/include/base/trace/types.h @@ -23,19 +23,12 @@ namespace Genode { namespace Trace { - /********************* - ** Exception types ** - *********************/ + using Thread_name = String<32>; - struct Policy_too_large : Exception { }; - struct Nonexistent_subject : Exception { }; - struct Already_traced : Exception { }; - struct Source_is_dead : Exception { }; - struct Nonexistent_policy : Exception { }; - struct Traced_by_other_session : Exception { }; - struct Subject_not_traced : Exception { }; - - typedef String<32> Thread_name; + struct Num_subjects { unsigned value; }; + struct Policy_size { size_t num_bytes; }; + struct Buffer_size { size_t num_bytes; }; + struct Trace_ok { }; struct Policy_id; struct Subject_id; @@ -49,10 +42,7 @@ namespace Genode { namespace Trace { */ struct Genode::Trace::Policy_id { - unsigned id; - - Policy_id() : id(0) { } - Policy_id(unsigned id) : id(id) { } + unsigned id { }; bool operator == (Policy_id const &other) const { return id == other.id; } }; @@ -63,10 +53,7 @@ struct Genode::Trace::Policy_id */ struct Genode::Trace::Subject_id { - unsigned id; - - Subject_id() : id(0) { } - Subject_id(unsigned id) : id(id) { } + unsigned id { }; bool operator == (Subject_id const &other) const { return id == other.id; } }; diff --git a/repos/base/include/base/tslab.h b/repos/base/include/base/tslab.h index b47a207ef0..6e759109d7 100644 --- a/repos/base/include/base/tslab.h +++ b/repos/base/include/base/tslab.h @@ -16,12 +16,16 @@ #include -namespace Genode { template struct Tslab; } +namespace Genode { template struct Tslab; } -template +template struct Genode::Tslab : Slab { + /* check if reasonable amount of entries + overhead fits one block */ + static_assert(MIN_SLABS_PER_BLOCK*(sizeof(T)+overhead_per_entry()) + + overhead_per_block() <= BLOCK_SIZE); + Tslab(Allocator *backing_store, void *initial_sb = 0) : Slab(sizeof(T), BLOCK_SIZE, initial_sb, backing_store) { } diff --git a/repos/base/include/base/weak_ptr.h b/repos/base/include/base/weak_ptr.h index 297a1674f4..ee48b6db83 100644 --- a/repos/base/include/base/weak_ptr.h +++ b/repos/base/include/base/weak_ptr.h @@ -17,6 +17,7 @@ #include #include #include +#include #include namespace Genode { diff --git a/repos/base-hw/src/include/hw/page_flags.h b/repos/base/include/cpu/page_flags.h similarity index 91% rename from repos/base-hw/src/include/hw/page_flags.h rename to repos/base/include/cpu/page_flags.h index 0622577f90..741a3c8fe4 100644 --- a/repos/base-hw/src/include/hw/page_flags.h +++ b/repos/base/include/cpu/page_flags.h @@ -11,13 +11,13 @@ * under the terms of the GNU Affero General Public License version 3. */ -#ifndef _SRC__LIB__HW__PAGE_FLAGS_H_ -#define _SRC__LIB__HW__PAGE_FLAGS_H_ +#ifndef _INCLUDE__CPU__PAGE_FLAGS_H_ +#define _INCLUDE__CPU__PAGE_FLAGS_H_ #include #include -namespace Hw { +namespace Genode { enum Writeable { RO, RW }; enum Executeable { NO_EXEC, EXEC }; @@ -29,7 +29,7 @@ namespace Hw { } -struct Hw::Page_flags +struct Genode::Page_flags { Writeable writeable; Executeable executable; @@ -57,7 +57,7 @@ struct Hw::Page_flags }; -namespace Hw { +namespace Genode { static constexpr Page_flags PAGE_FLAGS_KERN_IO { RW, NO_EXEC, KERN, GLOBAL, DEVICE, Genode::UNCACHED }; @@ -71,4 +71,4 @@ namespace Hw { { RW, NO_EXEC, USER, NO_GLOBAL, RAM, Genode::CACHED }; } -#endif /* _SRC__LIB__HW__PAGE_FLAGS_H_ */ +#endif /* _INCLUDE__CPU__PAGE_FLAGS_H_ */ diff --git a/repos/base/include/cpu/page_table_allocator.h b/repos/base/include/cpu/page_table_allocator.h new file mode 100644 index 0000000000..28309a1d49 --- /dev/null +++ b/repos/base/include/cpu/page_table_allocator.h @@ -0,0 +1,155 @@ +/* + * \brief Page table allocator + * \author Stefan Kalkowski + * \author Johannes Schlatow + * \date 2015-06-10 + */ + +/* + * Copyright (C) 2015-2023 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _INCLUDE__CPU__PAGE_TABLE_ALLOCATOR_H_ +#define _INCLUDE__CPU__PAGE_TABLE_ALLOCATOR_H_ + +#include +#include + +namespace Genode { + template class Page_table_allocator; + struct Out_of_tables {}; +} + +template +class Genode::Page_table_allocator +{ + protected: + + using addr_t = Genode::addr_t; + using size_t = Genode::size_t; + + addr_t const _virt_addr; + addr_t const _phys_addr; + size_t const _size; + + template addr_t _offset(TABLE & table) { + return (addr_t)&table - _virt_addr; } + + void * _index(unsigned idx) { + return (void*)(_virt_addr + TABLE_SIZE*idx); } + + virtual unsigned _alloc() = 0; + virtual void _free(unsigned idx) = 0; + + public: + + template class Array; + + Page_table_allocator(addr_t virt_addr, addr_t phys_addr, size_t size) + : _virt_addr(virt_addr), _phys_addr(phys_addr), _size(size) { } + + virtual ~Page_table_allocator() { } + + template + void with_table(addr_t phys_addr, auto const &match_fn, auto const &no_match_fn) + { + static_assert((sizeof(TABLE) == TABLE_SIZE), "unexpected size"); + + if (phys_addr >= _phys_addr && phys_addr < _phys_addr + _size) + match_fn(*(TABLE*)(_virt_addr + (phys_addr - _phys_addr))); + else + no_match_fn(); + } + + template addr_t construct() + { + static_assert((sizeof(TABLE) == TABLE_SIZE), "unexpected size"); + TABLE & table = *Genode::construct_at(_index(_alloc())); + return _offset(table) + _phys_addr; + } + + template void destruct(addr_t phys_addr) + { + static_assert((sizeof(TABLE) == TABLE_SIZE), "unexpected size"); + + with_table
(phys_addr, + [&] (TABLE & table) { + table.~TABLE(); + _free((unsigned)(_offset(table) / sizeof(TABLE))); + }, + [&] { + Genode::error("Trying to destruct foreign table at ", Genode::Hex(phys_addr)); + }); + } + + size_t size() const { return _size; } +}; + + +template +template +class Genode::Page_table_allocator::Array +{ + public: + + class Allocator; + + private: + + struct Table { Genode::uint8_t data[TABLE_SIZE]; }; + + Table _tables[COUNT]; + Allocator _alloc; + + public: + + Array() : _alloc((Table*)&_tables, (addr_t)&_tables, COUNT * TABLE_SIZE) {} + + explicit Array(auto phys_addr) + : _alloc(_tables, phys_addr((void*)_tables), COUNT * TABLE_SIZE) { } + + Page_table_allocator & alloc() { return _alloc; } +}; + + +template +template +class Genode::Page_table_allocator::Array::Allocator +: + public Genode::Page_table_allocator +{ + private: + + using Bit_allocator = Genode::Bit_allocator; + using Array = Page_table_allocator::Array; + + Bit_allocator _free_tables { }; + + unsigned _alloc() override + { + try { + return (unsigned)_free_tables.alloc(); + } catch (typename Bit_allocator::Out_of_indices&) {} + throw Out_of_tables(); + } + + void _free(unsigned idx) override { _free_tables.free(idx); } + + public: + + Allocator(Table * tables, addr_t phys_addr, size_t size) + : Page_table_allocator((addr_t)tables, phys_addr, size) {} + + Allocator(addr_t phys_addr, addr_t virt_addr, size_t size) + : Page_table_allocator(virt_addr, phys_addr, size), + _free_tables(static_cast(&reinterpret_cast(virt_addr)->alloc())->_free_tables) + { + static_assert(!__is_polymorphic(Bit_allocator), + "base class needs to be non-virtual"); + } +}; + +#endif /* _INCLUDE__CPU__PAGE_TABLE_ALLOCATOR_H_ */ diff --git a/repos/base/include/cpu/string.h b/repos/base/include/cpu/string.h new file mode 100644 index 0000000000..898b0a9b57 --- /dev/null +++ b/repos/base/include/cpu/string.h @@ -0,0 +1,62 @@ +/* + * \brief CPU-specific memcpy + * \author Sebastian Sumpf + * \author Johanned Schlatow + * \date 2012-08-02 + */ + +/* + * Copyright (C) 2012-2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _INCLUDE__CPU__STRING_H_ +#define _INCLUDE__CPU__STRING_H_ + +namespace Genode { + + /** + * Copy memory block + * + * \param dst destination memory block + * \param src source memory block + * \param size number of bytes to copy + * + * \return number of bytes not copied + */ + inline size_t memcpy_cpu(void * dst, const void * src, size_t size) + { + using word_t = unsigned long; + + enum { + LEN = sizeof(word_t), + MASK = LEN-1 + }; + + unsigned char *d = (unsigned char *)dst, *s = (unsigned char *)src; + + /* check byte alignment */ + size_t d_align = (size_t)d & MASK; + size_t s_align = (size_t)s & MASK; + + /* only same alignments work */ + if (d_align != s_align) + return size; + + /* copy to word alignment */ + for (; (size > 0) && (s_align > 0) && (s_align < LEN); + s_align++, *d++ = *s++, size--); + + /* copy words */ + for (; size >= LEN; size -= LEN, + d += LEN, + s += LEN) + *(word_t*)d = *(word_t*)s; + + return size; + } +} + +#endif /* _INCLUDE__CPU__STRING_H_ */ diff --git a/repos/base/include/cpu_session/capability.h b/repos/base/include/cpu_session/capability.h index 15c9e303df..970ed82f0e 100644 --- a/repos/base/include/cpu_session/capability.h +++ b/repos/base/include/cpu_session/capability.h @@ -19,7 +19,7 @@ namespace Genode { class Cpu_session; - typedef Capability Cpu_session_capability; + using Cpu_session_capability = Capability; } #endif /* _INCLUDE__CPU_SESSION__CAPABILITY_H_ */ diff --git a/repos/base/include/cpu_session/client.h b/repos/base/include/cpu_session/client.h index e677d64ef5..48ed7ad007 100644 --- a/repos/base/include/cpu_session/client.h +++ b/repos/base/include/cpu_session/client.h @@ -25,7 +25,7 @@ struct Genode::Cpu_session_client : Rpc_client explicit Cpu_session_client(Cpu_session_capability session) : Rpc_client(session) { } - Thread_capability + Create_thread_result create_thread(Capability pd, Name const &name, Affinity::Location affinity, Weight weight, addr_t utcb = 0) override { return call(pd, name, affinity, weight, utcb); } diff --git a/repos/base/include/cpu_session/connection.h b/repos/base/include/cpu_session/connection.h index ac0368abfd..aedbb5d385 100644 --- a/repos/base/include/cpu_session/connection.h +++ b/repos/base/include/cpu_session/connection.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2008-2017 Genode Labs GmbH + * Copyright (C) 2008-2023 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -22,34 +22,45 @@ namespace Genode { struct Cpu_connection; } struct Genode::Cpu_connection : Connection, Cpu_session_client { - enum { RAM_QUOTA = 36*1024 }; - /** * Constructor * - * \param label initial session label * \param priority designated priority of all threads created * with this CPU session */ - Cpu_connection(Env &env, const char *label = "", long priority = DEFAULT_PRIORITY, + Cpu_connection(Env &env, + Label const &label = Label(), + long priority = DEFAULT_PRIORITY, Affinity const &affinity = Affinity()) : - Connection(env, - session(env.parent(), affinity, - "priority=0x%lx, ram_quota=%u, " - "cap_quota=%u, label=\"%s\"", - priority, RAM_QUOTA, CAP_QUOTA, label)), + Connection(env, label, Ram_quota { RAM_QUOTA }, affinity, + Args("priority=", Hex(priority))), Cpu_session_client(cap()) { } - Thread_capability create_thread(Capability pd, - Name const &name, - Affinity::Location affinity, - Weight weight, - addr_t utcb = 0) override + Create_thread_result create_thread(Capability pd, + Name const &name, + Affinity::Location affinity, + Weight weight, + addr_t utcb = 0) override { - return retry_with_upgrade(Ram_quota{8*1024}, Cap_quota{2}, [&] () { - return Cpu_session_client::create_thread(pd, name, affinity, weight, utcb); }); + Thread_capability result { }; + bool denied = false; + while (!result.valid()) { + using Error = Cpu_session::Create_thread_error; + Cpu_session_client::create_thread(pd, name, affinity, weight, utcb).with_result( + [&] (Thread_capability cap) { result = cap; }, + [&] (Error e) { + switch (e) { + case Error::OUT_OF_RAM: upgrade_ram(8*1024); break; + case Error::OUT_OF_CAPS: upgrade_caps(2); break; + case Error::DENIED: denied = true; break; + } + }); + if (denied) + return Error::DENIED; + } + return result; } }; diff --git a/repos/base/include/cpu_session/cpu_session.h b/repos/base/include/cpu_session/cpu_session.h index 67389f49e1..f47e6c1993 100644 --- a/repos/base/include/cpu_session/cpu_session.h +++ b/repos/base/include/cpu_session/cpu_session.h @@ -14,9 +14,9 @@ #ifndef _INCLUDE__CPU_SESSION__CPU_SESSION_H_ #define _INCLUDE__CPU_SESSION__CPU_SESSION_H_ +#include #include #include -#include #include #include #include @@ -27,7 +27,7 @@ namespace Genode { struct Cpu_session; struct Cpu_session_client; - typedef Capability Thread_capability; + using Thread_capability = Capability; } @@ -43,20 +43,16 @@ struct Genode::Cpu_session : Session * allocation, its session capability, the capability of the 'Native_cpu' * RPC interface, and a capability for the trace-control dataspace. */ - enum { CAP_QUOTA = 6 }; + static constexpr unsigned CAP_QUOTA = 6; + static constexpr size_t RAM_QUOTA = 36*1024; - typedef Cpu_session_client Client; + using Client = Cpu_session_client; /********************* ** Exception types ** *********************/ - class Thread_creation_failed : public Exception { }; - class Quota_exceeded : public Thread_creation_failed { }; - - - enum { THREAD_NAME_LEN = 32 }; enum { PRIORITY_LIMIT = 1 << 16 }; enum { QUOTA_LIMIT_LOG2 = 15 }; enum { QUOTA_LIMIT = 1 << QUOTA_LIMIT_LOG2 }; @@ -67,13 +63,13 @@ struct Genode::Cpu_session : Session */ struct Weight { - enum { DEFAULT_WEIGHT = 10 }; + static constexpr size_t DEFAULT_WEIGHT = 10; size_t value = DEFAULT_WEIGHT; Weight() { } explicit Weight(size_t value) : value(value) { } }; - typedef String Name; + using Name = String<32>; /** * Physical quota configuration @@ -82,6 +78,9 @@ struct Genode::Cpu_session : Session virtual ~Cpu_session() { } + enum class Create_thread_error { OUT_OF_RAM, OUT_OF_CAPS, DENIED }; + using Create_thread_result = Attempt; + /** * Create a new thread * @@ -92,15 +91,12 @@ struct Genode::Cpu_session : Session * \param weight CPU quota that shall be granted to the thread * \param utcb base of the UTCB that will be used by the thread * \return capability representing the new thread - * \throw Thread_creation_failed - * \throw Out_of_ram - * \throw Out_of_caps */ - virtual Thread_capability create_thread(Capability pd, - Name const &name, - Affinity::Location affinity, - Weight weight, - addr_t utcb = 0) = 0; + virtual Create_thread_result create_thread(Capability pd, + Name const &name, + Affinity::Location affinity, + Weight weight, + addr_t utcb = 0) = 0; /** * Kill an existing thread @@ -208,9 +204,8 @@ struct Genode::Cpu_session : Session /** * Scale down 'value' from the 'QUOTA_LIMIT' space to a space with 'limit' */ - template static size_t quota_lim_downscale(size_t const value, size_t const limit) { - return (size_t)(((T)value * limit) >> Cpu_session::QUOTA_LIMIT_LOG2); } + return (size_t)(((uint64_t)value * limit) >> Cpu_session::QUOTA_LIMIT_LOG2); } /***************************************** @@ -232,10 +227,9 @@ struct Genode::Cpu_session : Session ** RPC declaration ** *********************/ - GENODE_RPC_THROW(Rpc_create_thread, Thread_capability, create_thread, - GENODE_TYPE_LIST(Thread_creation_failed, Out_of_ram, Out_of_caps), - Capability, Name const &, Affinity::Location, - Weight, addr_t); + GENODE_RPC(Rpc_create_thread, Create_thread_result, create_thread, + Capability, Name const &, Affinity::Location, + Weight, addr_t); GENODE_RPC(Rpc_kill_thread, void, kill_thread, Thread_capability); GENODE_RPC(Rpc_exception_sigh, void, exception_sigh, Signal_context_capability); GENODE_RPC(Rpc_affinity_space, Affinity::Space, affinity_space); diff --git a/repos/base/include/cpu_thread/cpu_thread.h b/repos/base/include/cpu_thread/cpu_thread.h index f6a589d1c2..4f36b528af 100644 --- a/repos/base/include/cpu_thread/cpu_thread.h +++ b/repos/base/include/cpu_thread/cpu_thread.h @@ -15,7 +15,6 @@ #define _INCLUDE__CPU_THREAD__CPU_THREAD_H_ #include -#include #include #include #include @@ -26,8 +25,6 @@ namespace Genode { struct Cpu_thread; } struct Genode::Cpu_thread : Interface { - class State_access_failed : public Exception { }; - /** * Get dataspace of the thread's user-level thread-control block (UTCB) */ @@ -59,7 +56,6 @@ struct Genode::Cpu_thread : Interface * Get the current thread state * * \return state of the targeted thread - * \throw State_access_failed */ virtual Thread_state state() = 0; @@ -67,7 +63,6 @@ struct Genode::Cpu_thread : Interface * Override the current thread state * * \param state state that shall be applied - * \throw State_access_failed */ virtual void state(Thread_state const &state) = 0; @@ -136,11 +131,8 @@ struct Genode::Cpu_thread : Interface GENODE_RPC(Rpc_start, void, start, addr_t, addr_t); GENODE_RPC(Rpc_pause, void, pause); GENODE_RPC(Rpc_resume, void, resume); - GENODE_RPC_THROW(Rpc_get_state, Thread_state, state, - GENODE_TYPE_LIST(State_access_failed)); - GENODE_RPC_THROW(Rpc_set_state, void, state, - GENODE_TYPE_LIST(State_access_failed), - Thread_state const &); + GENODE_RPC(Rpc_get_state, Thread_state, state); + GENODE_RPC(Rpc_set_state, void, state, Thread_state const &); GENODE_RPC(Rpc_exception_sigh, void, exception_sigh, Signal_context_capability); GENODE_RPC(Rpc_single_step, void, single_step, bool); GENODE_RPC(Rpc_affinity, void, affinity, Affinity::Location); diff --git a/repos/base/include/dataspace/capability.h b/repos/base/include/dataspace/capability.h index 7aa33d495a..40b87dea77 100644 --- a/repos/base/include/dataspace/capability.h +++ b/repos/base/include/dataspace/capability.h @@ -17,6 +17,6 @@ #include #include -namespace Genode { typedef Capability Dataspace_capability; } +namespace Genode { using Dataspace_capability = Capability; } #endif /* _INCLUDE__DATASPACE__CAPABILITY_H_ */ diff --git a/repos/base/include/deprecated/env.h b/repos/base/include/deprecated/env.h deleted file mode 100644 index 4164e40c2c..0000000000 --- a/repos/base/include/deprecated/env.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * \brief Environment of a component - * \author Norman Feske - * \date 2006-07-01 - * - * \deprecated This interface will be removed once all components are - * adjusted to the new API of base/component.h - */ - -/* - * Copyright (C) 2006-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _INCLUDE__DEPRECATED__ENV_H_ -#define _INCLUDE__DEPRECATED__ENV_H_ - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Genode { - - struct Env_deprecated; - - /** - * Return the interface to the component's environment - * - * \noapi - * \deprecated - */ - extern Env_deprecated *env_deprecated(); - - /** - * Return the interface to the component's environment - * - * \deprecated - */ - static inline Env_deprecated *env() __attribute__((deprecated)); - static inline Env_deprecated *env() - { - return env_deprecated(); - } -} - - -/** - * Component runtime environment - * - * The environment of a Genode component is defined by its parent. The 'Env' - * class allows the component to interact with its environment. It is - * initialized at the startup of the component. - */ -struct Genode::Env_deprecated : Interface -{ - /** - * Communication channel to our parent - */ - virtual Parent *parent() = 0; - - /** - * CPU session of the component - * - * This session is used to create the threads of the component. - */ - virtual Cpu_session *cpu_session() = 0; - virtual Cpu_session_capability cpu_session_cap() = 0; - - /** - * Region-manager session of the component as created by the parent - * - * \deprecated This function exists for API compatibility only. - * The functionality of the former RM service is now - * provided by the 'Region_map' interface. - */ - virtual Region_map *rm_session() = 0; - - /** - * PD session of the component as created by the parent - */ - virtual Pd_session *pd_session() = 0; - virtual Pd_session_capability pd_session_cap() = 0; -}; - -#endif /* _INCLUDE__DEPRECATED__ENV_H_ */ diff --git a/repos/base/include/drivers/defs/arm_v7.h b/repos/base/include/drivers/defs/arm_v7.h deleted file mode 100644 index 9420d10f20..0000000000 --- a/repos/base/include/drivers/defs/arm_v7.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * \brief Definitions for Armv7 - * \author Stefan Kalkowski - * \date 2019-04-10 - */ - -/* - * Copyright (C) 2019 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _INCLUDE__DRIVERS__DEFS__ARM_V7_H_ -#define _INCLUDE__DRIVERS__DEFS__ARM_V7_H_ - -namespace Arm_v7 { - - enum Interrupts { - - /****************************** - ** Virtualization extension ** - ******************************/ - - VT_MAINTAINANCE_IRQ = 25, - VT_TIMER_IRQ = 27, - }; -}; - -#endif /* _INCLUDE__DRIVERS__DEFS__ARM_V7_H_ */ diff --git a/repos/base/include/drivers/defs/imx53.h b/repos/base/include/drivers/defs/imx53.h deleted file mode 100644 index 45595d79ef..0000000000 --- a/repos/base/include/drivers/defs/imx53.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * \brief MMIO and IRQ definitions common to i.MX53 SoC - * \author Stefan Kalkowski - * \date 2012-10-24 - */ - -/* - * Copyright (C) 2012-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _INCLUDE__DRIVERS__DEFS__IMX53_H_ -#define _INCLUDE__DRIVERS__DEFS__IMX53_H_ - -namespace Imx53 { - enum { - MMIO_BASE = 0x0, - MMIO_SIZE = 0x70000000, - - RAM_BANK_0_BASE = 0x70000000, - RAM_BANK_0_SIZE = 0x40000000, - RAM_BANK_1_BASE = 0xb0000000, - RAM_BANK_1_SIZE = 0x40000000, - - SDHC_IRQ = 1, - SDHC_MMIO_BASE = 0x50004000, - SDHC_MMIO_SIZE = 0x00004000, - - UART_1_IRQ = 31, - UART_1_MMIO_BASE = 0x53fbc000, - UART_1_MMIO_SIZE = 0x00004000, - - EPIT_1_IRQ = 40, - EPIT_1_MMIO_BASE = 0x53fac000, - EPIT_1_MMIO_SIZE = 0x00004000, - - EPIT_2_IRQ = 41, - EPIT_2_MMIO_BASE = 0x53fb0000, - EPIT_2_MMIO_SIZE = 0x00004000, - - GPIO1_MMIO_BASE = 0x53f84000, - GPIO1_MMIO_SIZE = 0x4000, - GPIO2_MMIO_BASE = 0x53f88000, - GPIO2_MMIO_SIZE = 0x4000, - GPIO3_MMIO_BASE = 0x53f8c000, - GPIO3_MMIO_SIZE = 0x4000, - GPIO4_MMIO_BASE = 0x53f90000, - GPIO4_MMIO_SIZE = 0x4000, - GPIO5_MMIO_BASE = 0x53fdc000, - GPIO5_MMIO_SIZE = 0x4000, - GPIO6_MMIO_BASE = 0x53fe0000, - GPIO6_MMIO_SIZE = 0x4000, - GPIO7_MMIO_BASE = 0x53fe4000, - GPIO7_MMIO_SIZE = 0x4000, - GPIO1_IRQL = 50, - GPIO1_IRQH = 51, - GPIO2_IRQL = 52, - GPIO2_IRQH = 53, - GPIO3_IRQL = 54, - GPIO3_IRQH = 55, - GPIO4_IRQL = 56, - GPIO4_IRQH = 57, - GPIO5_IRQL = 103, - GPIO5_IRQH = 104, - GPIO6_IRQL = 105, - GPIO6_IRQH = 106, - GPIO7_IRQL = 107, - GPIO7_IRQH = 108, - - IRQ_CONTROLLER_BASE = 0x0fffc000, - IRQ_CONTROLLER_SIZE = 0x00004000, - - AIPS_1_MMIO_BASE = 0x53f00000, - AIPS_2_MMIO_BASE = 0x63f00000, - - IOMUXC_BASE = 0x53fa8000, - IOMUXC_SIZE = 0x00004000, - - PWM2_BASE = 0x53fb8000, - PWM2_SIZE = 0x00004000, - - IPU_BASE = 0x18000000, - IPU_SIZE = 0x08000000, - - SRC_BASE = 0x53fd0000, - SRC_SIZE = 0x00004000, - - CCM_BASE = 0x53FD4000, - CCM_SIZE = 0x00004000, - - I2C_2_IRQ = 63, - I2C_2_BASE = 0x63fc4000, - I2C_2_SIZE = 0x00004000, - - I2C_3_IRQ = 64, - I2C_3_BASE = 0x53fec000, - I2C_3_SIZE = 0x00004000, - - IIM_BASE = 0x63f98000, - IIM_SIZE = 0x00004000, - - CSU_BASE = 0x63f9c000, - CSU_SIZE = 0x00001000, - - M4IF_BASE = 0x63fd8000, - M4IF_SIZE = 0x00001000, - }; -}; - -#endif /* _INCLUDE__DRIVERS__DEFS__IMX53_H_ */ diff --git a/repos/base/include/drivers/defs/imx53_qsb.h b/repos/base/include/drivers/defs/imx53_qsb.h deleted file mode 100644 index 6fc0c3c69b..0000000000 --- a/repos/base/include/drivers/defs/imx53_qsb.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * \brief MMIO and IRQ definitions of the i.MX53 Quickstart board - * \author Stefan Kalkowski - * \date 2012-10-24 - */ - -/* - * Copyright (C) 2012-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _INCLUDE__DRIVERS__DEFS__IMX53_QSB_H_ -#define _INCLUDE__DRIVERS__DEFS__IMX53_QSB_H_ - -/* Genode includes */ -#include - -namespace Imx53_qsb { - - using namespace Imx53; - - enum { - RAM0_BASE = RAM_BANK_0_BASE, - RAM0_SIZE = 0x20000000, - RAM1_BASE = RAM_BANK_1_BASE, - RAM1_SIZE = 0x20000000, - }; -}; - -#endif /* _INCLUDE__DRIVERS__DEFS__IMX53_QSB_H_ */ diff --git a/repos/base/include/drivers/defs/imx6.h b/repos/base/include/drivers/defs/imx6.h deleted file mode 100644 index 3d60934c72..0000000000 --- a/repos/base/include/drivers/defs/imx6.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * \brief MMIO and IRQ definitions common to i.MX6 SoC - * \author Nikolay Golikov - * \author Josef Soentgen - * \author Martin Stein - * \date 2017-06-20 - */ - -/* - * Copyright (C) 2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _INCLUDE__DRIVERS__DEFS__IMX6_H_ -#define _INCLUDE__DRIVERS__DEFS__IMX6_H_ - -namespace Imx6 { - enum { - /* device IO memory */ - MMIO_BASE = 0x00000000, - MMIO_SIZE = 0x10000000, - - UART_1_IRQ = 58, - UART_1_MMIO_BASE = 0x02020000, - UART_1_MMIO_SIZE = 0x00004000, - - UART_2_IRQ = 59, - UART_2_MMIO_BASE = 0x021e8000, - UART_2_MMIO_SIZE = 0x00004000, - - /* timer */ - EPIT_2_IRQ = 89, - EPIT_2_MMIO_BASE = 0x020d4000, - EPIT_2_MMIO_SIZE = 0x00004000, - - /* ARM IP Bus control */ - AIPS_1_MMIO_BASE = 0x0207c000, - AIPS_1_MMIO_SIZE = 0x00004000, - AIPS_2_MMIO_BASE = 0x0217c000, - AIPS_2_MMIO_SIZE = 0x00004000, - - /* CPU */ - CORTEX_A9_PRIVATE_MEM_BASE = 0x00a00000, - CORTEX_A9_PRIVATE_MEM_SIZE = 0x00002000, - - /* L2 cache controller */ - PL310_MMIO_BASE = 0x00a02000, - PL310_MMIO_SIZE = 0x00001000, - - /* System reset controller */ - SRC_MMIO_BASE = 0x20d8000, - - /* SD host controller */ - SDHC_1_IRQ = 54, - SDHC_1_MMIO_BASE = 0x02190000, - SDHC_1_MMIO_SIZE = 0x00004000, - SDHC_2_IRQ = 55, - SDHC_2_MMIO_BASE = 0x02194000, - SDHC_2_MMIO_SIZE = 0x00004000, - SDHC_3_IRQ = 56, - SDHC_3_MMIO_BASE = 0x02198000, - SDHC_3_MMIO_SIZE = 0x00004000, - SDHC_4_IRQ = 57, - SDHC_4_MMIO_BASE = 0x0219c000, - SDHC_4_MMIO_SIZE = 0x00004000, - - /* GPIO */ - GPIO1_MMIO_BASE = 0x0209c000, - GPIO1_MMIO_SIZE = 0x4000, - GPIO2_MMIO_BASE = 0x020a0000, - GPIO2_MMIO_SIZE = 0x4000, - GPIO3_MMIO_BASE = 0x020a4000, - GPIO3_MMIO_SIZE = 0x4000, - GPIO4_MMIO_BASE = 0x020a8000, - GPIO4_MMIO_SIZE = 0x4000, - GPIO5_MMIO_BASE = 0x020ac000, - GPIO5_MMIO_SIZE = 0x4000, - GPIO6_MMIO_BASE = 0x020b0000, - GPIO6_MMIO_SIZE = 0x4000, - GPIO7_MMIO_BASE = 0x020b4000, - GPIO7_MMIO_SIZE = 0x4000, - GPIO1_IRQL = 98, - GPIO1_IRQH = 99, - GPIO2_IRQL = 100, - GPIO2_IRQH = 101, - GPIO3_IRQL = 102, - GPIO3_IRQH = 103, - GPIO4_IRQL = 104, - GPIO4_IRQH = 105, - GPIO5_IRQL = 106, - GPIO5_IRQH = 107, - GPIO6_IRQL = 108, - GPIO6_IRQH = 109, - GPIO7_IRQL = 110, - GPIO7_IRQH = 111, - - }; -}; - -#endif /* _INCLUDE__DRIVERS__DEFS__IMX6_H_ */ diff --git a/repos/base/include/drivers/defs/imx6q_sabrelite.h b/repos/base/include/drivers/defs/imx6q_sabrelite.h deleted file mode 100644 index 9a2f96475d..0000000000 --- a/repos/base/include/drivers/defs/imx6q_sabrelite.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * \brief MMIO and IRQ definitions of the i.MX6Quad Sabrelite - * \author Stefan Kalkowski - * \date 2019-01-05 - */ - -/* - * Copyright (C) 2019 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _INCLUDE__DRIVERS__DEFS__IMX6Q_SABRELITE_H_ -#define _INCLUDE__DRIVERS__DEFS__IMX6Q_SABRELITE_H_ - -/* Genode includes */ -#include - -namespace Imx6q_sabrelite { - - using namespace Imx6; - - enum { - RAM_BASE = 0x10000000, - RAM_SIZE = 0x40000000, - }; -}; - -#endif /* _INCLUDE__DRIVERS__DEFS__IMX6Q_SABRELITE_H_ */ diff --git a/repos/base/include/drivers/defs/imx7d_sabre.h b/repos/base/include/drivers/defs/imx7d_sabre.h deleted file mode 100644 index 6a572bf3eb..0000000000 --- a/repos/base/include/drivers/defs/imx7d_sabre.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * \brief Definitions for the Imx7 dual sabre board - * \author Stefan Kalkowski - * \date 2018-10-07 - */ - -/* - * Copyright (C) 2018 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _INCLUDE__DRIVERS__DEFS__IMX7D_SABRE_H_ -#define _INCLUDE__DRIVERS__DEFS__IMX7D_SABRE_H_ - -#include - -namespace Imx7d_sabre { - - using namespace Arm_v7; - - enum { - RAM_0_BASE = 0x80000000UL, - RAM_0_SIZE = 0x40000000UL, - - IRQ_CONTROLLER_BASE = 0x31000000UL, - IRQ_CONTROLLER_SIZE = 0x8000, - - SRC_MMIO_BASE = 0x30390000UL, - - AIPS_1_MMIO_BASE = 0x301f0000UL, - AIPS_2_MMIO_BASE = 0x305f0000UL, - AIPS_3_MMIO_BASE = 0x309f0000UL, - - UART_1_MMIO_BASE = 0x30860000UL, - UART_1_MMIO_SIZE = 0x10000UL, - - TIMER_CLOCK = 1000000000UL, - }; -} - -#endif /* _INCLUDE__DRIVERS__DEFS__IMX7D_SABRE_H_ */ diff --git a/repos/base/include/drivers/defs/nit6_solox.h b/repos/base/include/drivers/defs/nit6_solox.h deleted file mode 100644 index 780123b4c7..0000000000 --- a/repos/base/include/drivers/defs/nit6_solox.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * \brief MMIO and IRQ definitions for Nit6 SOLOX board - * \author Stefan Kalkowski - * \date 2017-10-18 - */ - -/* - * Copyright (C) 2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _INCLUDE__DRIVERS__DEFS__NIT6_SOLOX_H_ -#define _INCLUDE__DRIVERS__DEFS__NIT6_SOLOX_H_ - -/* Genode includes */ -#include - -namespace Nit6_solox { - - using namespace Imx6; - - enum { - /* normal RAM */ - RAM_BASE = 0x80000000, - RAM_SIZE = 0x40000000, - }; -}; - -#endif /* _INCLUDE__DRIVERS__DEFS__NIT6_SOLOX_H_ */ diff --git a/repos/base/include/drivers/defs/pbxa9.h b/repos/base/include/drivers/defs/pbxa9.h index 6b5dd30609..0ca1e146e6 100644 --- a/repos/base/include/drivers/defs/pbxa9.h +++ b/repos/base/include/drivers/defs/pbxa9.h @@ -43,8 +43,8 @@ namespace Pbxa9 { SYSTEM_CONTROL_MMIO_BASE = 0x10000000, /* CPU */ - CORTEX_A9_PRIVATE_TIMER_CLK = 100000000, - CORTEX_A9_PRIVATE_TIMER_DIV = 100, + CORTEX_A9_GLOBAL_TIMER_CLK = 100000000, + CORTEX_A9_GLOBAL_TIMER_DIV = 100, CORTEX_A9_PRIVATE_MEM_BASE = 0x1f000000, CORTEX_A9_PRIVATE_MEM_SIZE = 0x2000, diff --git a/repos/base/include/drivers/defs/usb_armory.h b/repos/base/include/drivers/defs/usb_armory.h deleted file mode 100644 index 0b699c3368..0000000000 --- a/repos/base/include/drivers/defs/usb_armory.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * \brief MMIO and IRQ definitions for the USB Armory - * \author Stefan Kalkowski - * \date 2012-10-24 - */ - -/* - * Copyright (C) 2012-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _INCLUDE__DRIVERS__DEFS__USB_ARMORY_H_ -#define _INCLUDE__DRIVERS__DEFS__USB_ARMORY_H_ - -/* Genode includes */ -#include - -namespace Usb_armory { - - using namespace Imx53; - - enum { - RAM_BASE = RAM_BANK_0_BASE, - RAM_SIZE = 0x20000000, - }; -}; - -#endif /* _INCLUDE__DRIVERS__DEFS__USB_ARMORY_H_ */ diff --git a/repos/base/include/drivers/defs/wand_quad.h b/repos/base/include/drivers/defs/wand_quad.h deleted file mode 100644 index 76d091f027..0000000000 --- a/repos/base/include/drivers/defs/wand_quad.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * \brief MMIO and IRQ definitions of the Wandboard Quad - * \author Nikolay Golikov - * \author Josef Soentgen - * \author Martin Stein - * \date 2014-02-25 - */ - -/* - * Copyright (C) 2014-2016 Ksys Labs LLC - * Copyright (C) 2014-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _INCLUDE__DRIVERS__DEFS__WAND_QUAD_H_ -#define _INCLUDE__DRIVERS__DEFS__WAND_QUAD_H_ - -/* Genode includes */ -#include - -namespace Wand_quad { - - using namespace Imx6; - - enum { - /* normal RAM */ - RAM_BASE = 0x10000000, - RAM_SIZE = 0x80000000, - }; -}; - -#endif /* _INCLUDE__DRIVERS__DEFS__WAND_QUAD_H_ */ diff --git a/repos/base/include/drivers/platform/bcm2837_control.h b/repos/base/include/drivers/platform/bcm2837_control.h deleted file mode 100644 index d5f200621c..0000000000 --- a/repos/base/include/drivers/platform/bcm2837_control.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * \brief Driver for the platform specific functionality for bcm2837 - * \author Tomasz Gajewski - * \date 2019-12-28 - */ - -/* - * Copyright (C) 2011-2019 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _INCLUDE__DRIVERS__PLATFORM__BCM2837_CONTROL_H_ -#define _INCLUDE__DRIVERS__PLATFORM__BCM2837_CONTROL_H_ - -/* Genode includes */ -#include - - -namespace Genode { class Bcm2837_control; } - - -class Genode::Bcm2837_control : Mmio -{ - public: - - struct ControlRegister : public Register<0x0, 32> - { - struct CoreTimeClockSource : Bitfield<8,1> { }; - struct TimerIncrement : Bitfield<9,1> { }; - }; - - struct CoreTimerPrescaler : public Register<0x8, 32> - { - }; - - inline Bcm2837_control(addr_t const base); - - inline void initialize_timer_frequency(); -}; - - -Genode::Bcm2837_control::Bcm2837_control(addr_t const base) -: - Mmio(base) -{ } - - -void Genode::Bcm2837_control::initialize_timer_frequency() -{ - /* - * Set prescaler value to achieve divider value equal to 1. - * Value taken from chapter "3.1.1 Timer clock" from QA7_rev3.4.pdf - * document describing the BCM2836 chip. - */ - write(0x80000000); -} - - -#endif /* _INCLUDE__DRIVERS__PLATFORM__BCM2837_CONTROL_H_ */ diff --git a/repos/base/include/drivers/timer/util.h b/repos/base/include/drivers/timer/util.h index 190eac3778..d161d35a9f 100644 --- a/repos/base/include/drivers/timer/util.h +++ b/repos/base/include/drivers/timer/util.h @@ -28,7 +28,9 @@ namespace Genode { * to time with microseconds precision. Thus, we split the input in two and * translate both parts separately. This way, we can raise precision by * shifting the values to their optimal bit position. Afterwards, the - * results are shifted back and merged together again. + * results are shifted back and merged together again. Note, the remainder + * of the upper-half division is factored into the lower-half calculation + * (as upper-half value). * * Please ensure that the assertion * "ticks_per_ms >= TIMER_MIN_TICKS_PER_MS" is true when calling this @@ -45,10 +47,15 @@ namespace Genode { MSB_RSHIFT = 10, LSB_LSHIFT = HALF_WIDTH - MSB_RSHIFT, }; - RESULT_T const msb = ((((ticks & MSB_MASK) >> MSB_RSHIFT) - * 1000) / ticks_per_ms) << MSB_RSHIFT; - RESULT_T const lsb = ((((ticks & LSB_MASK) << LSB_LSHIFT) - * 1000) / ticks_per_ms) >> LSB_LSHIFT; + /* upper half */ + RESULT_T const msb0 = ((ticks & MSB_MASK) >> MSB_RSHIFT) * 1000; + RESULT_T const msb = (msb0 / ticks_per_ms) << MSB_RSHIFT; + RESULT_T const rem = (msb0 % ticks_per_ms) << MSB_RSHIFT; + /* lower half */ + RESULT_T const lsb0 = ((ticks & LSB_MASK) << LSB_LSHIFT) * 1000 + + (rem << LSB_LSHIFT); + RESULT_T const lsb = (lsb0 / ticks_per_ms) >> LSB_LSHIFT; + return msb + lsb; } } diff --git a/repos/base/include/drivers/uart/imx.h b/repos/base/include/drivers/uart/imx.h deleted file mode 100644 index bcb6f102ce..0000000000 --- a/repos/base/include/drivers/uart/imx.h +++ /dev/null @@ -1,267 +0,0 @@ -/* - * \brief Driver for Freescale's i.MX UART - * \author Norman Feske - * \author Martin Stein - * \date 2012-08-30 - */ - -/* - * Copyright (C) 2012-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _INCLUDE__DRIVERS__UART__IMX_H_ -#define _INCLUDE__DRIVERS__UART__IMX_H_ - -/* Genode includes */ -#include - -namespace Genode { class Imx_uart; } - - -/** - * Driver base for i.MX UART-module - */ -class Genode::Imx_uart: Mmio -{ - /** - * Control register 1 - */ - struct Cr1 : Register<0x80, 32> - { - struct Uart_en : Bitfield<0, 1> { }; /* enable UART */ - struct Doze : Bitfield<1, 1> { }; /* disable on doze */ - struct At_dma_en : Bitfield<2, 1> { }; /* aging DMA - * timer on */ - struct Tx_dma_en : Bitfield<3, 1> { }; /* TX ready DMA on */ - struct Snd_brk : Bitfield<4, 1> { }; /* send breaks */ - struct Rtsd_en : Bitfield<5, 1> { }; /* RTS delta IRQ on */ - struct Tx_mpty_en : Bitfield<6, 1> { }; /* TX empty IRQ on */ - struct Ir_en : Bitfield<7, 1> { }; /* enable infrared */ - struct Rx_dma_en : Bitfield<8, 1> { }; /* RX ready DMA on */ - struct R_rdy_en : Bitfield<9, 1> { }; /* RX ready IRQ on */ - - struct Icd : Bitfield<10, 2> /* idle IRQ condition */ - { - enum { IDLE_4_FRAMES = 0 }; - }; - - struct Id_en : Bitfield<12, 1> { }; /* enable idle IRQ */ - struct T_rdy_en : Bitfield<13, 1> { }; /* TX ready IRQ on */ - struct Adbr : Bitfield<14, 1> { }; /* enable baud-rate - * auto detect */ - struct Ad_en : Bitfield<15, 1> { }; /* enable ADBR IRQ */ - - /** - * Initialization value - */ - static access_t init_value() - { - return Uart_en::bits(1) | - Doze::bits(0) | - At_dma_en::bits(0) | - Tx_dma_en::bits(0) | - Snd_brk::bits(0) | - Rtsd_en::bits(0) | - Tx_mpty_en::bits(0) | - Ir_en::bits(0) | - Rx_dma_en::bits(0) | - R_rdy_en::bits(0) | - Id_en::bits(0) | - T_rdy_en::bits(0) | - Adbr::bits(0) | - Ad_en::bits(0); - } - - }; - - /** - * Control register 2 - */ - struct Cr2 : Register<0x84, 32> - { - struct S_rst : Bitfield<0, 1> /* SW reset bit */ - { - enum { NO_RESET = 1 }; - }; - - struct Rx_en : Bitfield<1, 1> { }; /* enable receiver */ - struct Tx_en : Bitfield<2, 1> { }; /* enable transmitter */ - struct At_en : Bitfield<3, 1> { }; /* enable aging timer */ - struct Rts_en : Bitfield<4, 1> { }; /* send request IRQ on */ - - struct Ws : Bitfield<5, 1> /* select word size */ - { - enum { _8_BITS = 1 }; - }; - - struct Stpb : Bitfield<6, 1> /* number of stop bits */ - { - enum { _1_BIT = 0 }; - }; - - struct Pr_en : Bitfield<8, 1> { }; /* enable parity */ - struct Esc_en : Bitfield<11, 1> { }; /* escape detection on */ - - struct Ctsc : Bitfield<13, 1> /* select CTS control */ - { - enum { BY_RECEIVER = 1 }; - }; - - struct Irts : Bitfield<14, 1> { }; /* ignore RTS pin */ - struct Esci : Bitfield<15, 1> { }; /* enable escape IRQ */ - - /** - * Initialization value - */ - static access_t init_value() - { - return S_rst::bits(S_rst::NO_RESET) | - Rx_en::bits(0) | - Tx_en::bits(1) | - At_en::bits(0) | - Rts_en::bits(0) | - Ws::bits(Ws::_8_BITS) | - Stpb::bits(Stpb::_1_BIT) | - Pr_en::bits(0) | - Esc_en::bits(0) | - Ctsc::bits(Ctsc::BY_RECEIVER) | - Irts::bits(1) | - Esci::bits(0); - } - }; - - /** - * Control register 3 - */ - struct Cr3 : Register<0x88, 32> - { - struct Rxdmux_sel : Bitfield<2, 1> { }; /* use muxed RXD */ - struct Aci_en : Bitfield<0, 1> { }; /* autobaud count IRQ on */ - struct Dtrd_en : Bitfield<3, 1> { }; /* data terminal ready - * delta IRQ on */ - struct Awak_en : Bitfield<4, 1> { }; /* wake IRQ on */ - struct Air_int_en : Bitfield<5, 1> { }; /* IR wake IRQ on */ - struct Rx_ds_en : Bitfield<6, 1> { }; /* RX status IRQ on */ - struct Ad_nimp : Bitfield<7, 1> { }; /* autobaud detect off */ - struct Ri_en : Bitfield<8, 1> { }; /* ring indicator IRQ on */ - struct Dcd_en : Bitfield<9, 1> { }; /* data carrier detect - * IRQ on */ - struct Dsr : Bitfield<10,1> { }; /* DSR/DTR output */ - struct Frame_en : Bitfield<11,1> { }; /* frame error IRQ on */ - struct Parity_en : Bitfield<12,1> { }; /* parity error IRQ on */ - struct Dtr_en : Bitfield<13,1> { }; /* data terminal ready - * IRQ on */ - struct Dpec_ctrl : Bitfield<14,2> { }; /* DTR/DSR IRQ edge - * control */ - - /** - * Initialization value - */ - static access_t init_value() - { - return Aci_en::bits(0) | - Rxdmux_sel::bits(0) | - Dtrd_en::bits(0) | - Awak_en::bits(0) | - Air_int_en::bits(0) | - Rx_ds_en::bits(0) | - Ad_nimp::bits(1) | - Ri_en::bits(0) | - Dcd_en::bits(0) | - Dsr::bits(0) | - Frame_en::bits(0) | - Parity_en::bits(0) | - Dtr_en::bits(0) | - Dpec_ctrl::bits(0); - } - }; - - /** - * Control register 4 - */ - struct Cr4 : Register<0x8c, 32> - { - struct Dr_en : Bitfield<0, 1> { }; /* RX data ready IRQ on */ - struct Or_en : Bitfield<1, 1> { }; /* RX overrun IRQ on */ - struct Bk_en : Bitfield<2, 1> { }; /* BREAK IRQ on */ - struct Tc_en : Bitfield<3, 1> { }; /* TX complete IRQ on */ - struct Lp_dis : Bitfield<4, 1> { }; /* low power off */ - struct IR_sc : Bitfield<5, 1> { }; /* use UART ref clock - * for vote logic */ - struct Id_dma_en : Bitfield<6, 1> { }; /* idle DMA IRQ on */ - struct Wake_en : Bitfield<7, 1> { }; /* WAKE IRQ on */ - struct IR_en : Bitfield<8, 1> { }; /* serial IR IRQ on */ - struct Cts_level : Bitfield<10,6> { }; /* CTS trigger level*/ - - /** - * Initialization value - */ - static access_t init_value() - { - return Dr_en::bits(0) | - Or_en::bits(0) | - Bk_en::bits(0) | - Tc_en::bits(0) | - Lp_dis::bits(0) | - IR_sc::bits(0) | - Id_dma_en::bits(0) | - Wake_en::bits(0) | - IR_en::bits(0) | - Cts_level::bits(0); - } - }; - - /** - * Status register 2 - */ - struct Sr2 : Register<0x98, 32> - { - struct Txdc : Bitfield<3, 1> { }; /* transmission complete */ - }; - - /** - * Transmitter register - */ - struct Txd : Register<0x40, 32> - { - struct Tx_data : Bitfield<0, 8> { }; /* transmit data */ - }; - - /** - * Transmit character 'c' without care about its type - */ - void _put_char(char c) - { - while (!read()) ; - write(c); - } - - public: - - /** - * Constructor - * - * \param base device MMIO base - */ - Imx_uart(addr_t base, uint32_t, uint32_t) : Mmio(base) - { - write(Cr1::init_value()); - write(Cr2::init_value()); - write(Cr3::init_value()); - write(Cr4::init_value()); - } - - /** - * Print character 'c' through the UART - */ - void put_char(char c) - { - /* transmit character */ - _put_char(c); - } -}; - -#endif /* _INCLUDE__DRIVERS__UART__IMX_H_ */ diff --git a/repos/base/include/drivers/uart/pl011.h b/repos/base/include/drivers/uart/pl011.h index 0fe1201852..22f3c2c599 100644 --- a/repos/base/include/drivers/uart/pl011.h +++ b/repos/base/include/drivers/uart/pl011.h @@ -17,13 +17,13 @@ /* Genode includes */ #include -namespace Genode { class Pl011_uart; } +namespace Genode { class Pl011_uart; } /** * Driver base for the PrimeCell UART PL011 Revision r1p3 */ -class Genode::Pl011_uart : Mmio +class Genode::Pl011_uart : Mmio<0x3a> { protected: @@ -126,11 +126,13 @@ class Genode::Pl011_uart : Mmio * Send ASCII char 'c' over the UART interface */ inline void put_char(char const c); + + void init() { } }; Genode::Pl011_uart::Pl011_uart(addr_t const base, uint32_t const clock, - uint32_t const baud_rate) : Mmio(base) + uint32_t const baud_rate) : Mmio({(char *)base, Mmio::SIZE}) { write(Uartcr::Uarten::bits(1) | Uartcr::Txe::bits(1) | diff --git a/repos/base/include/drivers/uart/x86_pc.h b/repos/base/include/drivers/uart/x86_pc.h index 2d6719c423..67e9cfa8fe 100644 --- a/repos/base/include/drivers/uart/x86_pc.h +++ b/repos/base/include/drivers/uart/x86_pc.h @@ -17,6 +17,7 @@ /* Genode includes */ #include +#include namespace Genode { class X86_uart; } @@ -24,7 +25,8 @@ class Genode::X86_uart { private: - uint16_t _port; + uint16_t const _port; + unsigned const _baud_rate; enum { COMPORT_DATA_OFFSET = 0, @@ -59,32 +61,36 @@ class Genode::X86_uart X86_uart(uint16_t const port, unsigned /* clock */, unsigned const baud_rate) : - _port(port) + _port(port), _baud_rate(baud_rate) { + init(); + } + void init() + { /** * Initialize serial port * * Based on 'init_serial' of L4ka::Pistachio's 'kdb/platform/pc99/io.cc' */ - if (!port) + if (!_port) return; uint16_t const - IER = (uint16_t)(port + 1), - EIR = (uint16_t)(port + 2), - LCR = (uint16_t)(port + 3), - MCR = (uint16_t)(port + 4), - LSR = (uint16_t)(port + 5), - MSR = (uint16_t)(port + 6), - DLLO = (uint16_t)(port + 0), - DLHI = (uint16_t)(port + 1); + IER = (uint16_t)(_port + 1), + EIR = (uint16_t)(_port + 2), + LCR = (uint16_t)(_port + 3), + MCR = (uint16_t)(_port + 4), + LSR = (uint16_t)(_port + 5), + MSR = (uint16_t)(_port + 6), + DLLO = (uint16_t)(_port + 0), + DLHI = (uint16_t)(_port + 1); _outb(LCR, 0x80); /* select bank 1 */ - for (volatile int i = 10000000; i--; ); - _outb(DLLO, (uint8_t)((115200/baud_rate) >> 0)); - _outb(DLHI, (uint8_t)((115200/baud_rate) >> 8)); + for (int i = 10000000; i; --i) memory_barrier(); + _outb(DLLO, (uint8_t)((115200/_baud_rate) >> 0)); + _outb(DLHI, (uint8_t)((115200/_baud_rate) >> 8)); _outb(LCR, 0x03); /* set 8,N,1 */ _outb(IER, 0x00); /* disable interrupts */ _outb(EIR, 0x07); /* enable FIFOs */ diff --git a/repos/base/include/io_mem_session/capability.h b/repos/base/include/io_mem_session/capability.h index 42ebcdd316..abe800a88f 100644 --- a/repos/base/include/io_mem_session/capability.h +++ b/repos/base/include/io_mem_session/capability.h @@ -17,6 +17,6 @@ #include #include -namespace Genode { typedef Capability Io_mem_session_capability; } +namespace Genode { using Io_mem_session_capability = Capability; } #endif /* _INCLUDE__IO_MEM_SESSION__CAPABILITY_H_ */ diff --git a/repos/base/include/io_mem_session/connection.h b/repos/base/include/io_mem_session/connection.h index e8deb1969b..18ae658d90 100644 --- a/repos/base/include/io_mem_session/connection.h +++ b/repos/base/include/io_mem_session/connection.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2008-2017 Genode Labs GmbH + * Copyright (C) 2008-2023 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -31,12 +31,10 @@ struct Genode::Io_mem_connection : Connection, Io_mem_session_cl */ Io_mem_connection(Env &env, addr_t base, size_t size, bool write_combined = false) : - Connection(env, - session(env.parent(), - "cap_quota=%u, ram_quota=%u, " - "base=0x%p, size=0x%lx, wc=%s", - CAP_QUOTA, RAM_QUOTA, base, size, - write_combined ? "yes" : "no")), + Connection(env, Label(), Ram_quota { RAM_QUOTA }, + Args("base=", Hex(base), ", " + "size=", Hex(size), ", " + "wc=", write_combined ? "yes" : "no")), Io_mem_session_client(cap()) { } }; diff --git a/repos/base/include/io_mem_session/io_mem_session.h b/repos/base/include/io_mem_session/io_mem_session.h index 90d774e939..0cfabfad2a 100644 --- a/repos/base/include/io_mem_session/io_mem_session.h +++ b/repos/base/include/io_mem_session/io_mem_session.h @@ -22,7 +22,7 @@ namespace Genode { struct Io_mem_dataspace; struct Io_mem_session; - typedef Capability Io_mem_dataspace_capability; + using Io_mem_dataspace_capability = Capability; } @@ -41,7 +41,8 @@ struct Genode::Io_mem_session : Session * session-object allocation, its session capability, and a dataspace * capability for the handed-out memory-mapped I/O dataspace. */ - enum { CAP_QUOTA = 3, RAM_QUOTA = 6 * 1024 }; + static constexpr unsigned CAP_QUOTA = 3; + static constexpr size_t RAM_QUOTA = 6*1024; virtual ~Io_mem_session() { } diff --git a/repos/base/include/io_port_session/capability.h b/repos/base/include/io_port_session/capability.h index 8c22b2c0c3..6e853da227 100644 --- a/repos/base/include/io_port_session/capability.h +++ b/repos/base/include/io_port_session/capability.h @@ -17,6 +17,6 @@ #include #include -namespace Genode { typedef Capability Io_port_session_capability; } +namespace Genode { using Io_port_session_capability = Capability; } #endif /* _INCLUDE__IO_PORT_SESSION__CAPABILITY_H_ */ diff --git a/repos/base/include/io_port_session/connection.h b/repos/base/include/io_port_session/connection.h index c7384b4b23..783875c72f 100644 --- a/repos/base/include/io_port_session/connection.h +++ b/repos/base/include/io_port_session/connection.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2008-2017 Genode Labs GmbH + * Copyright (C) 2008-2023 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -23,17 +23,6 @@ namespace Genode { struct Io_port_connection; } struct Genode::Io_port_connection : Connection, Io_port_session_client { - /** - * Issue session request - * - * \noapi - */ - Capability _session(Parent &parent, unsigned base, unsigned size) - { - return session(parent, "ram_quota=%u, cap_quota=%u, io_port_base=%u, io_port_size=%u", - RAM_QUOTA, CAP_QUOTA, base, size); - } - /** * Constructor * @@ -42,11 +31,9 @@ struct Genode::Io_port_connection : Connection, */ Io_port_connection(Env &env, unsigned base, unsigned size) : - Connection(env, - session(env.parent(), - "ram_quota=%u, cap_quota=%u, " - "io_port_base=%u, io_port_size=%u", - RAM_QUOTA, CAP_QUOTA, base, size)), + Connection(env, Label(), Ram_quota { RAM_QUOTA }, + Args("io_port_base=", base, ", " + "io_port_size=", size)), Io_port_session_client(cap()) { } }; diff --git a/repos/base/include/io_port_session/io_port_session.h b/repos/base/include/io_port_session/io_port_session.h index 24d7cfcd9d..7bae0f605f 100644 --- a/repos/base/include/io_port_session/io_port_session.h +++ b/repos/base/include/io_port_session/io_port_session.h @@ -38,10 +38,12 @@ struct Genode::Io_port_session : Session */ static const char *service_name() { return "IO_PORT"; } - enum { RAM_QUOTA = 6 * 1024, CAP_QUOTA = 2 }; + static constexpr unsigned CAP_QUOTA = 2; + static constexpr size_t RAM_QUOTA = 6*1024; virtual ~Io_port_session() { } + /****************************** ** Read value from I/O port ** ******************************/ diff --git a/repos/base/include/irq_session/capability.h b/repos/base/include/irq_session/capability.h index ddcec12801..a266c75cf8 100644 --- a/repos/base/include/irq_session/capability.h +++ b/repos/base/include/irq_session/capability.h @@ -17,6 +17,6 @@ #include #include -namespace Genode { typedef Capability Irq_session_capability; } +namespace Genode { using Irq_session_capability = Capability; } #endif /* _INCLUDE__IRQ_SESSION__CAPABILITY_H_ */ diff --git a/repos/base/include/irq_session/connection.h b/repos/base/include/irq_session/connection.h index f4b8f85ced..5ad4784e5a 100644 --- a/repos/base/include/irq_session/connection.h +++ b/repos/base/include/irq_session/connection.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2008-2017 Genode Labs GmbH + * Copyright (C) 2008-2023 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -19,47 +19,45 @@ namespace Genode { struct Irq_connection; } + struct Genode::Irq_connection : Connection, Irq_session_client { /** * Constructor * - * \param irq physical interrupt number + * \param label physical interrupt number * \param trigger interrupt trigger (e.g., level/edge) * \param polarity interrupt trigger polarity (e.g., low/high) */ - Irq_connection(Env &env, - unsigned irq, - Irq_session::Trigger trigger = Irq_session::TRIGGER_UNCHANGED, - Irq_session::Polarity polarity = Irq_session::POLARITY_UNCHANGED, - Genode::addr_t device_config_phys = 0) + Irq_connection(Env &env, + Label const &label, + Trigger trigger = Irq_session::TRIGGER_UNCHANGED, + Polarity polarity = Irq_session::POLARITY_UNCHANGED) : - Connection(env, session(env.parent(), - "ram_quota=%u, cap_quota=%u, " - "irq_number=%u, irq_trigger=%u, " - "irq_polarity=%u, device_config_phys=0x%lx", - RAM_QUOTA, CAP_QUOTA, - irq, trigger, polarity, device_config_phys)), + Connection(env, label, Ram_quota { RAM_QUOTA }, + Args("irq_number=", label, ", " + "irq_trigger=", unsigned(trigger), ", " + "irq_polarity=", unsigned(polarity), ", " + "irq_type=", unsigned(TYPE_LEGACY))), Irq_session_client(cap()) { } /** - * Constructor for label-based configuration (used by pin driver) + * Constructor * - * \param label session label + * \param label (virtual) interrupt number + * \param device_config_phys config-space physical address + * \param type interrupt type (e.g., msi/msi-x) */ - Irq_connection(Env &env, - char const *label) + Irq_connection(Env &env, + Label const &label, + addr_t device_config_phys, + Type type = Irq_session::TYPE_MSI) : - Connection(env, session(env.parent(), - "ram_quota=%u, cap_quota=%u, " - "irq_number=%u, irq_trigger=%u, " - "irq_polarity=%u, device_config_phys=0x%lx, " - "label=\"%s\"", - RAM_QUOTA, CAP_QUOTA, 0, - Irq_session::TRIGGER_UNCHANGED, - Irq_session::POLARITY_UNCHANGED, - 0, label)), + Connection(env, label, Ram_quota { RAM_QUOTA }, + Args("irq_number=", label, ", " + "device_config_phys=", Hex(device_config_phys), ", " + "irq_type=", unsigned(type))), Irq_session_client(cap()) { } }; diff --git a/repos/base/include/irq_session/irq_session.h b/repos/base/include/irq_session/irq_session.h index cb6807bc49..782547d076 100644 --- a/repos/base/include/irq_session/irq_session.h +++ b/repos/base/include/irq_session/irq_session.h @@ -48,6 +48,11 @@ struct Genode::Irq_session : Session */ enum Polarity { POLARITY_UNCHANGED = 0, POLARITY_HIGH, POLARITY_LOW }; + /** + * Interrupt type + */ + enum Type { TYPE_LEGACY = 0, TYPE_MSI, TYPE_MSIX }; + /** * Destructor */ @@ -78,7 +83,8 @@ struct Genode::Irq_session : Session */ static const char * service_name() { return "IRQ"; } - enum { CAP_QUOTA = 3, RAM_QUOTA = 6 * 1024 }; + static constexpr unsigned CAP_QUOTA = 3; + static constexpr size_t RAM_QUOTA = 6*1024; /********************* diff --git a/repos/base/include/log_session/capability.h b/repos/base/include/log_session/capability.h index c1949271ca..ace17b65d1 100644 --- a/repos/base/include/log_session/capability.h +++ b/repos/base/include/log_session/capability.h @@ -17,6 +17,6 @@ #include #include -namespace Genode { typedef Capability Log_session_capability; } +namespace Genode { using Log_session_capability = Capability; } #endif /* _INCLUDE__LOG_SESSION__CAPABILITY_H_ */ diff --git a/repos/base/include/log_session/connection.h b/repos/base/include/log_session/connection.h index 330e92ddb0..1ed3ef2f53 100644 --- a/repos/base/include/log_session/connection.h +++ b/repos/base/include/log_session/connection.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2008-2017 Genode Labs GmbH + * Copyright (C) 2008-2023 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -16,23 +16,15 @@ #include #include -#include namespace Genode { struct Log_connection; } struct Genode::Log_connection : Connection, Log_session_client { - enum { RAM_QUOTA = 8*1024UL }; - - /** - * Constructor - */ - Log_connection(Env &env, Session_label label = Session_label()) + Log_connection(Env &env, Session_label const &label = Session_label()) : - Connection(env, session(env.parent(), - "ram_quota=%ld, cap_quota=%ld, label=\"%s\"", - RAM_QUOTA, CAP_QUOTA, label.string())), + Connection(env, label, Ram_quota { RAM_QUOTA }, Args()), Log_session_client(cap()) { } }; diff --git a/repos/base/include/log_session/log_session.h b/repos/base/include/log_session/log_session.h index 5c7969824a..fcf3492ef4 100644 --- a/repos/base/include/log_session/log_session.h +++ b/repos/base/include/log_session/log_session.h @@ -37,16 +37,17 @@ struct Genode::Log_session : Session * A LOG connection consumes a dataspace capability for the session-object * allocation and its session capability. */ - enum { CAP_QUOTA = 2 }; + static constexpr unsigned CAP_QUOTA = 2; + static constexpr size_t RAM_QUOTA = 8*1024; - typedef Log_session_client Client; + using Client = Log_session_client; virtual ~Log_session() { } /* the lowest platform-specific maximum IPC payload size (OKL4) */ enum { MAX_STRING_LEN = 232 }; - typedef Rpc_in_buffer String; + using String = Rpc_in_buffer; /** * Output null-terminated string diff --git a/repos/base/include/parent/capability.h b/repos/base/include/parent/capability.h index 21928f5782..6aab744b66 100644 --- a/repos/base/include/parent/capability.h +++ b/repos/base/include/parent/capability.h @@ -17,6 +17,6 @@ #include #include -namespace Genode { typedef Capability Parent_capability; } +namespace Genode { using Parent_capability = Capability; } #endif /* _INCLUDE__PARENT__CAPABILITY_H_ */ diff --git a/repos/base/include/parent/client.h b/repos/base/include/parent/client.h index 5a6fc949c3..e160c4b938 100644 --- a/repos/base/include/parent/client.h +++ b/repos/base/include/parent/client.h @@ -33,13 +33,13 @@ struct Genode::Parent_client : Rpc_client void session_sigh(Signal_context_capability sigh) override { call(sigh); } - Session_capability session(Client::Id id, - Service_name const &service, - Session_args const &args, - Affinity const &affinity) override { + Session_result session(Client::Id id, + Service_name const &service, + Session_args const &args, + Affinity const &affinity) override { return call(id, service, args, affinity); } - Session_capability session_cap(Client::Id id) override { + Session_cap_result session_cap(Client::Id id) override { return call(id); } Upgrade_result upgrade(Client::Id to_session, Upgrade_args const &args) override { diff --git a/repos/base/include/parent/parent.h b/repos/base/include/parent/parent.h index 7379342e5b..99f783c54c 100644 --- a/repos/base/include/parent/parent.h +++ b/repos/base/include/parent/parent.h @@ -14,7 +14,7 @@ #ifndef _INCLUDE__PARENT__PARENT_H_ #define _INCLUDE__PARENT__PARENT_H_ -#include +#include #include #include #include @@ -53,12 +53,12 @@ class Genode::Parent public: - typedef Rpc_in_buffer<64> Service_name; - typedef Rpc_in_buffer<160> Session_args; - typedef Rpc_in_buffer<160> Upgrade_args; + using Service_name = Rpc_in_buffer<64>; + using Session_args = Rpc_in_buffer<160>; + using Upgrade_args = Rpc_in_buffer<160>; - struct Client : Interface { typedef Id_space::Id Id; }; - struct Server : Interface { typedef Id_space::Id Id; }; + struct Client : Interface { using Id = Id_space::Id; }; + struct Server : Interface { using Id = Id_space::Id; }; /** * Predefined session IDs corresponding to the environment sessions @@ -84,7 +84,7 @@ class Genode::Parent * Use 'String' instead of 'Rpc_in_buffer' because 'Resource_args' * is used as both in and out parameter. */ - typedef String<160> Resource_args; + using Resource_args = String<160>; virtual ~Parent() { } @@ -125,7 +125,7 @@ class Genode::Parent template void announce(Capability const &service_root) { - typedef typename ROOT_INTERFACE::Session_type Session; + using Session = typename ROOT_INTERFACE::Session_type; announce(Session::service_name(), service_root); /* @@ -143,6 +143,16 @@ class Genode::Parent */ virtual void session_sigh(Signal_context_capability) = 0; + enum class Session_error { + OUT_OF_RAM, /* session RAM quota exceeds our resources */ + OUT_OF_CAPS, /* session CAP quota exceeds our resources */ + INSUFFICIENT_RAM_QUOTA, /* RAM donation does not suffice */ + INSUFFICIENT_CAP_QUOTA, /* CAP donation does not suffice */ + DENIED, /* parent or server denies request */ + }; + + using Session_result = Attempt, Session_error>; + /** * Create session to a service * @@ -151,39 +161,35 @@ class Genode::Parent * \param args session constructor arguments * \param affinity preferred CPU affinity for the session * - * \throw Service_denied parent denies session request - * \throw Insufficient_cap_quota donated cap quota does not suffice - * \throw Insufficient_ram_quota donated RAM quota does not suffice - * \throw Out_of_caps session CAP quota exceeds our resources - * \throw Out_of_ram session RAM quota exceeds our resources - * * \return session capability if the new session is immediately - * available, or an invalid capability + * available, or an invalid capability, or an error of + * type 'Session_error'. * * If the returned capability is invalid, the request is pending at the * server. The parent delivers a signal to the handler as registered * via 'session_sigh' once the server responded to the request. Now the * session capability can be picked up by calling 'session_cap'. */ - virtual Session_capability session(Client::Id id, - Service_name const &service_name, - Session_args const &args, - Affinity const &affinity = Affinity()) = 0; + virtual Session_result session(Client::Id id, + Service_name const &service_name, + Session_args const &args, + Affinity const &affinity = Affinity()) = 0; + + enum class Session_cap_error { INSUFFICIENT_RAM_QUOTA, + INSUFFICIENT_CAP_QUOTA, DENIED, }; + + using Session_cap_result = Attempt, Session_cap_error>; /** * Request session capability * - * \throw Service_denied - * \throw Insufficient_cap_quota - * \throw Insufficient_ram_quota - * * See 'session' for more documentation. * - * In the exception case, the parent implicitly closes the session. + * In the error case, the parent implicitly closes the session. */ - virtual Session_capability session_cap(Client::Id id) = 0; + virtual Session_cap_result session_cap(Client::Id id) = 0; - enum Upgrade_result { UPGRADE_DONE, UPGRADE_PENDING }; + enum class Upgrade_result { OK, PENDING, OUT_OF_RAM, OUT_OF_CAPS }; /** * Transfer our quota to the server that provides the specified session @@ -191,16 +197,13 @@ class Genode::Parent * \param id ID of recipient session * \param args description of the amount of quota to transfer * - * \throw Out_of_caps - * \throw Out_of_ram - * * The 'args' argument has the same principle format as the 'args' * argument of the 'session' operation. */ virtual Upgrade_result upgrade(Client::Id to_session, Upgrade_args const &args) = 0; - enum [[nodiscard]] Close_result { CLOSE_DONE, CLOSE_PENDING }; + enum class [[nodiscard]] Close_result { DONE, PENDING }; /** * Close session @@ -308,19 +311,11 @@ class Genode::Parent GENODE_RPC(Rpc_announce, void, announce, Service_name const &); GENODE_RPC(Rpc_session_sigh, void, session_sigh, Signal_context_capability); - GENODE_RPC_THROW(Rpc_session, Session_capability, session, - GENODE_TYPE_LIST(Service_denied, Out_of_caps, - Out_of_ram, Insufficient_cap_quota, - Insufficient_ram_quota), - Client::Id, Service_name const &, Session_args const &, - Affinity const &); - GENODE_RPC_THROW(Rpc_session_cap, Session_capability, session_cap, - GENODE_TYPE_LIST(Service_denied, Insufficient_cap_quota, - Insufficient_ram_quota), - Client::Id); - GENODE_RPC_THROW(Rpc_upgrade, Upgrade_result, upgrade, - GENODE_TYPE_LIST(Out_of_ram, Out_of_caps), - Client::Id, Upgrade_args const &); + GENODE_RPC(Rpc_session, Session_result, session, + Client::Id, Service_name const &, Session_args const &, + Affinity const &); + GENODE_RPC(Rpc_session_cap, Session_cap_result, session_cap, Client::Id); + GENODE_RPC(Rpc_upgrade, Upgrade_result, upgrade, Client::Id, Upgrade_args const &); GENODE_RPC(Rpc_close, Close_result, close, Client::Id); GENODE_RPC(Rpc_session_response, void, session_response, Server::Id, Session_response); @@ -353,11 +348,11 @@ Genode::Parent::_announce_base(Genode::Capability const &service Genode::Meta::Bool_to_type *) { /* shortcut for inherited session type */ - typedef typename ROOT_INTERFACE::Session_type::Rpc_inherited_interface - Session_type_inherited; + using Session_type_inherited = + typename ROOT_INTERFACE::Session_type::Rpc_inherited_interface; /* shortcut for root interface type matching the inherited session type */ - typedef Typed_root Root_inherited; + using Root_inherited = Typed_root; /* convert root capability to match the inherited session type */ Capability root = service_root; diff --git a/repos/base/include/pd_session/capability.h b/repos/base/include/pd_session/capability.h index 59b3a89eb5..a0789d047f 100644 --- a/repos/base/include/pd_session/capability.h +++ b/repos/base/include/pd_session/capability.h @@ -17,6 +17,6 @@ #include #include -namespace Genode { typedef Capability Pd_session_capability; } +namespace Genode { using Pd_session_capability = Capability; } #endif /* _INCLUDE__PD_SESSION__CAPABILITY_H_ */ diff --git a/repos/base/include/pd_session/client.h b/repos/base/include/pd_session/client.h index e578f192cd..5c8007d10a 100644 --- a/repos/base/include/pd_session/client.h +++ b/repos/base/include/pd_session/client.h @@ -31,16 +31,16 @@ struct Genode::Pd_session_client : Rpc_client bool assign_pci(addr_t pci_config_memory_address, uint16_t bdf) override { return call(pci_config_memory_address, bdf); } - void map(addr_t virt, addr_t size) override { call(virt, size); } + Map_result map(Virt_range range) override { return call(range); } - Signal_source_capability alloc_signal_source() override { - return call(); } + Signal_source_result signal_source() override { + return call(); } - void free_signal_source(Signal_source_capability cap) override { + void free_signal_source(Capability cap) override { call(cap); } - Signal_context_capability alloc_context(Signal_source_capability source, - unsigned long imprint) override { + Alloc_context_result alloc_context(Capability source, + Imprint imprint) override { return call(source, imprint); } void free_context(Signal_context_capability cap) override { @@ -49,7 +49,7 @@ struct Genode::Pd_session_client : Rpc_client void submit(Signal_context_capability receiver, unsigned cnt = 1) override { call(receiver, cnt); } - Native_capability alloc_rpc_cap(Native_capability ep) override { + Alloc_rpc_cap_result alloc_rpc_cap(Native_capability ep) override { return call(ep); } void free_rpc_cap(Native_capability cap) override { @@ -64,11 +64,14 @@ struct Genode::Pd_session_client : Rpc_client Capability linker_area() override { return call(); } - void ref_account(Capability pd) override { - call(pd); } + Ref_account_result ref_account(Capability pd) override { + return call(pd); } - void transfer_quota(Capability pd, Cap_quota amount) override { - call(pd, amount); } + Transfer_cap_quota_result transfer_quota(Capability pd, + Cap_quota amount) override + { + return call(pd, amount); + } Cap_quota cap_quota() const override { return call(); } Cap_quota used_caps() const override { return call(); } @@ -85,16 +88,19 @@ struct Genode::Pd_session_client : Rpc_client return ds.valid() ? Dataspace_client(ds).size() : 0; } - void transfer_quota(Pd_session_capability pd_session, Ram_quota amount) override { - call(pd_session, amount); } + Transfer_ram_quota_result transfer_quota(Pd_session_capability pd_session, + Ram_quota amount) override + { + return call(pd_session, amount); + } Ram_quota ram_quota() const override { return call(); } Ram_quota used_ram() const override { return call(); } Capability native_pd() override { return call(); } - Managing_system_state managing_system(Managing_system_state const & state) override { - return call(state); } + Capability system_control_cap(Affinity::Location const location) override { + return call(location); } addr_t dma_addr(Ram_dataspace_capability ds) override { return call(ds); } diff --git a/repos/base/include/pd_session/connection.h b/repos/base/include/pd_session/connection.h index 49a8911a4a..94bcf38968 100644 --- a/repos/base/include/pd_session/connection.h +++ b/repos/base/include/pd_session/connection.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2008-2017 Genode Labs GmbH + * Copyright (C) 2008-2023 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -22,19 +22,12 @@ namespace Genode { struct Pd_connection; } struct Genode::Pd_connection : Connection, Pd_session_client { - enum { RAM_QUOTA = 24*1024*sizeof(long)}; enum Virt_space { UNCONSTRAIN = 0, CONSTRAIN = 1 }; - /** - * Constructor - * - * \param label session label - */ - Pd_connection(Env &env, char const *label = "", Virt_space space = CONSTRAIN) + Pd_connection(Env &env, Label const &label = Label(), Virt_space space = CONSTRAIN) : - Connection(env, session(env.parent(), - "ram_quota=%u, cap_quota=%u, label=\"%s\", virt_space=%u", - RAM_QUOTA, CAP_QUOTA, label, space)), + Connection(env, label, Ram_quota { RAM_QUOTA }, + Args("virt_space=", unsigned(space))), Pd_session_client(cap()) { } @@ -45,11 +38,9 @@ struct Genode::Pd_connection : Connection, Pd_session_client */ Pd_connection(Env &env, Device_pd) : - Connection(env, session(env.parent(), - "ram_quota=%u, cap_quota=%u, " - "label=\"device PD\", virt_space=%u, " - "managing_system=yes", - RAM_QUOTA, CAP_QUOTA, UNCONSTRAIN)), + Connection(env, "device PD", Ram_quota { RAM_QUOTA }, + Args("virt_space=", unsigned(UNCONSTRAIN), ", " + "managing_system=yes")), Pd_session_client(cap()) { } }; diff --git a/repos/base/include/pd_session/pd_session.h b/repos/base/include/pd_session/pd_session.h index 9f6c7871c4..c487129690 100644 --- a/repos/base/include/pd_session/pd_session.h +++ b/repos/base/include/pd_session/pd_session.h @@ -16,7 +16,7 @@ #define _INCLUDE__PD_SESSION__PD_SESSION_H_ #include -#include +#include #include #include #include @@ -46,9 +46,10 @@ struct Genode::Pd_session : Session, Ram_allocator * Furthermore, we account for the dataspace capabilities allocated during * the component bootstrapping. */ - enum { CAP_QUOTA = 6 + 7 }; + static constexpr unsigned CAP_QUOTA = 6 + 7; + static constexpr size_t RAM_QUOTA = 24*1024*sizeof(long); - typedef Pd_session_client Client; + using Client = Pd_session_client; virtual ~Pd_session() { } @@ -69,66 +70,56 @@ struct Genode::Pd_session : Session, Ram_allocator */ virtual bool assign_pci(addr_t pci_config_memory_address, uint16_t bdf) = 0; + struct Virt_range { addr_t start; size_t num_bytes; }; + + enum class Map_result { OK, OUT_OF_RAM, OUT_OF_CAPS }; + /** - * Trigger eager insertion of page frames to page table within - * specified virtual range. + * Trigger eager population of page table within specified virtual range * * If the used kernel don't support this feature, the operation will * silently ignore the request. - * - * \param virt virtual address within the address space to start - * \param size the virtual size of the region - * - * \throw Out_of_ram - * \throw Out_of_caps */ - virtual void map(addr_t virt, addr_t size) = 0; + virtual Map_result map(Virt_range) = 0; + /******************************** ** Support for the signal API ** ********************************/ - typedef Capability Signal_source_capability; - - class Invalid_session : public Exception { }; - class Undefined_ref_account : public Exception { }; - class Invalid_signal_source : public Exception { }; + enum class Signal_source_error { OUT_OF_RAM, OUT_OF_CAPS }; + using Signal_source_result = Attempt, Signal_source_error>; /** - * Create a new signal source - * - * \return a cap that acts as reference to the created source + * Return signal source for the PD * * The signal source provides an interface to wait for incoming signals. - * - * \throw Out_of_ram - * \throw Out_of_caps */ - virtual Signal_source_capability alloc_signal_source() = 0; + virtual Signal_source_result signal_source() = 0; /** * Free a signal source * * \param cap capability of the signal source to destroy */ - virtual void free_signal_source(Signal_source_capability cap) = 0; + virtual void free_signal_source(Capability cap) = 0; + + enum class Alloc_context_error { OUT_OF_RAM, OUT_OF_CAPS, INVALID_SIGNAL_SOURCE }; + using Alloc_context_result = Attempt, Alloc_context_error>; + + struct Imprint { addr_t value; }; /** * Allocate signal context * * \param source signal source that shall provide the new context * - * * \param imprint opaque value that gets delivered with signals * originating from the allocated signal-context capability * \return new signal-context capability - * - * \throw Out_of_ram - * \throw Out_of_caps - * \throw Invalid_signal_source */ - virtual Capability - alloc_context(Signal_source_capability source, unsigned long imprint) = 0; + virtual Alloc_context_result alloc_context(Capability source, + Imprint imprint) = 0; /** * Free signal-context @@ -158,17 +149,17 @@ struct Genode::Pd_session : Session, Ram_allocator ** Support for the RPC framework ** ***********************************/ + enum class Alloc_rpc_cap_error { OUT_OF_RAM, OUT_OF_CAPS }; + using Alloc_rpc_cap_result = Attempt; + /** * Allocate new RPC-object capability * * \param ep entry point that will use this capability * - * \throw Out_of_ram if meta-data backing store is exhausted - * \throw Out_of_caps if 'cap_quota' is exceeded - * * \return new RPC capability */ - virtual Native_capability alloc_rpc_cap(Native_capability ep) = 0; + virtual Alloc_rpc_cap_result alloc_rpc_cap(Native_capability ep) = 0; /** * Free RPC-object capability @@ -204,12 +195,14 @@ struct Genode::Pd_session : Session, Ram_allocator ** Accounting for capability allocations ** *******************************************/ + enum class Ref_account_result { OK, INVALID_SESSION }; + /** * Define reference account for the PD session - * - * \throw Invalid_session */ - virtual void ref_account(Capability) = 0; + virtual Ref_account_result ref_account(Capability) = 0; + + enum class Transfer_cap_quota_result { OK, OUT_OF_CAPS, INVALID_SESSION, NO_REF_ACCOUNT }; /** * Transfer capability quota to another PD session @@ -217,14 +210,11 @@ struct Genode::Pd_session : Session, Ram_allocator * \param to receiver of quota donation * \param amount amount of quota to donate * - * \throw Out_of_caps - * \throw Invalid_session - * \throw Undefined_ref_account - * * Quota can only be transfered if the specified PD session is either the * reference account for this session or vice versa. */ - virtual void transfer_quota(Capability to, Cap_quota amount) = 0; + virtual Transfer_cap_quota_result transfer_quota(Capability to, + Cap_quota amount) = 0; /** * Return current capability-quota limit @@ -254,20 +244,19 @@ struct Genode::Pd_session : Session, Ram_allocator * which comprises the actual allocation and deallocation operations. */ + enum class Transfer_ram_quota_result { OK, OUT_OF_RAM, INVALID_SESSION, NO_REF_ACCOUNT }; + /** * Transfer quota to another RAM session * * \param to receiver of quota donation * \param amount amount of quota to donate * - * \throw Out_of_ram - * \throw Invalid_session - * \throw Undefined_ref_account - * * Quota can only be transfered if the specified PD session is either the * reference account for this session or vice versa. */ - virtual void transfer_quota(Capability to, Ram_quota amount) = 0; + virtual Transfer_ram_quota_result transfer_quota(Capability to, + Ram_quota amount) = 0; /** * Return current quota limit @@ -304,12 +293,26 @@ struct Genode::Pd_session : Session, Ram_allocator ** Access to system management interface ** *******************************************/ + struct System_control : Interface + { + using System_control_state = Cpu_state; + + virtual System_control_state system_control(System_control_state const &) = 0; + + GENODE_RPC(Rpc_system_control, System_control_state, system_control, + System_control_state const &); + + GENODE_RPC_INTERFACE(Rpc_system_control); + }; + + using Managing_system_state = Cpu_state; /** - * Call privileged system management functionality of kernel or firmware + * Call privileged system control functionality of kernel or firmware */ - virtual Managing_system_state managing_system(Managing_system_state const &) = 0; + + virtual Capability system_control_cap(Affinity::Location const) = 0; /******************************************* @@ -349,62 +352,45 @@ struct Genode::Pd_session : Session, Ram_allocator GENODE_RPC(Rpc_assign_parent, void, assign_parent, Capability); GENODE_RPC(Rpc_assign_pci, bool, assign_pci, addr_t, uint16_t); - GENODE_RPC_THROW(Rpc_map, void, map, - GENODE_TYPE_LIST(Out_of_ram, Out_of_caps), - addr_t, addr_t); - - GENODE_RPC_THROW(Rpc_alloc_signal_source, Signal_source_capability, - alloc_signal_source, - GENODE_TYPE_LIST(Out_of_ram, Out_of_caps)); - GENODE_RPC(Rpc_free_signal_source, void, free_signal_source, Signal_source_capability); - GENODE_RPC_THROW(Rpc_alloc_context, Capability, alloc_context, - GENODE_TYPE_LIST(Out_of_ram, Out_of_caps, Invalid_signal_source), - Signal_source_capability, unsigned long); - GENODE_RPC(Rpc_free_context, void, free_context, - Capability); + GENODE_RPC(Rpc_map, Map_result, map, Virt_range); + GENODE_RPC(Rpc_signal_source, Signal_source_result, signal_source); + GENODE_RPC(Rpc_free_signal_source, void, free_signal_source, Capability); + GENODE_RPC(Rpc_alloc_context, Alloc_context_result, alloc_context, + Capability, Imprint); + GENODE_RPC(Rpc_free_context, void, free_context, Capability); GENODE_RPC(Rpc_submit, void, submit, Capability, unsigned); - - GENODE_RPC_THROW(Rpc_alloc_rpc_cap, Native_capability, alloc_rpc_cap, - GENODE_TYPE_LIST(Out_of_ram, Out_of_caps), Native_capability); + GENODE_RPC(Rpc_alloc_rpc_cap, Alloc_rpc_cap_result, alloc_rpc_cap, Native_capability); GENODE_RPC(Rpc_free_rpc_cap, void, free_rpc_cap, Native_capability); - GENODE_RPC(Rpc_address_space, Capability, address_space); GENODE_RPC(Rpc_stack_area, Capability, stack_area); GENODE_RPC(Rpc_linker_area, Capability, linker_area); - - GENODE_RPC_THROW(Rpc_ref_account, void, ref_account, - GENODE_TYPE_LIST(Invalid_session), Capability); - GENODE_RPC_THROW(Rpc_transfer_cap_quota, void, transfer_quota, - GENODE_TYPE_LIST(Out_of_caps, Invalid_session, Undefined_ref_account), - Capability, Cap_quota); + GENODE_RPC(Rpc_ref_account, Ref_account_result, ref_account, Capability); + GENODE_RPC(Rpc_transfer_cap_quota, Transfer_cap_quota_result, transfer_quota, + Capability, Cap_quota); GENODE_RPC(Rpc_cap_quota, Cap_quota, cap_quota); GENODE_RPC(Rpc_used_caps, Cap_quota, used_caps); - GENODE_RPC(Rpc_try_alloc, Alloc_result, try_alloc, size_t, Cache); GENODE_RPC(Rpc_free, void, free, Ram_dataspace_capability); - GENODE_RPC_THROW(Rpc_transfer_ram_quota, void, transfer_quota, - GENODE_TYPE_LIST(Out_of_ram, Invalid_session, Undefined_ref_account), - Capability, Ram_quota); + GENODE_RPC(Rpc_transfer_ram_quota, Transfer_ram_quota_result, transfer_quota, + Capability, Ram_quota); GENODE_RPC(Rpc_ram_quota, Ram_quota, ram_quota); GENODE_RPC(Rpc_used_ram, Ram_quota, used_ram); - GENODE_RPC(Rpc_native_pd, Capability, native_pd); - - GENODE_RPC(Rpc_managing_system, Managing_system_state, managing_system, - Managing_system_state const &); + GENODE_RPC(Rpc_system_control_cap, Capability, + system_control_cap, Affinity::Location); GENODE_RPC(Rpc_dma_addr, addr_t, dma_addr, Ram_dataspace_capability); GENODE_RPC(Rpc_attach_dma, Attach_dma_result, attach_dma, Dataspace_capability, addr_t); GENODE_RPC_INTERFACE(Rpc_assign_parent, Rpc_assign_pci, Rpc_map, - Rpc_alloc_signal_source, Rpc_free_signal_source, + Rpc_signal_source, Rpc_free_signal_source, Rpc_alloc_context, Rpc_free_context, Rpc_submit, Rpc_alloc_rpc_cap, Rpc_free_rpc_cap, Rpc_address_space, Rpc_stack_area, Rpc_linker_area, Rpc_ref_account, Rpc_transfer_cap_quota, Rpc_cap_quota, Rpc_used_caps, Rpc_try_alloc, Rpc_free, Rpc_transfer_ram_quota, Rpc_ram_quota, Rpc_used_ram, - Rpc_native_pd, Rpc_managing_system, + Rpc_native_pd, Rpc_system_control_cap, Rpc_dma_addr, Rpc_attach_dma); }; diff --git a/repos/base/include/region_map/client.h b/repos/base/include/region_map/client.h index 46fda09831..c484f517b2 100644 --- a/repos/base/include/region_map/client.h +++ b/repos/base/include/region_map/client.h @@ -41,16 +41,11 @@ class Genode::Region_map_client : public Rpc_client explicit Region_map_client(Capability); - Local_addr attach(Dataspace_capability ds, size_t size = 0, - off_t offset = 0, bool use_local_addr = false, - Local_addr local_addr = (void *)0, - bool executable = false, - bool writeable = true) override; - - void detach(Local_addr) override; - void fault_handler(Signal_context_capability) override; - State state() override; - Dataspace_capability dataspace() override; + Attach_result attach(Dataspace_capability, Attr const &) override; + void detach(addr_t) override; + void fault_handler(Signal_context_capability) override; + Fault fault() override; + Dataspace_capability dataspace() override; }; #endif /* _INCLUDE__REGION_MAP__CLIENT_H_ */ diff --git a/repos/base/include/region_map/region_map.h b/repos/base/include/region_map/region_map.h index 201c902dcf..2d8b3c95f7 100644 --- a/repos/base/include/region_map/region_map.h +++ b/repos/base/include/region_map/region_map.h @@ -14,6 +14,7 @@ #ifndef _INCLUDE__REGION_MAP__REGION_MAP_H_ #define _INCLUDE__REGION_MAP__REGION_MAP_H_ +#include #include #include #include @@ -26,7 +27,7 @@ namespace Genode { struct Region_map; } struct Genode::Region_map : Interface { /** - * State of region map + * Fault state of region map * * If a thread accesses a location outside the regions attached to its * address space, a fault occurs and gets signalled to the registered fault @@ -34,109 +35,46 @@ struct Genode::Region_map : Interface * fault address and fault type to resolve the fault. This information is * represented by this structure. */ - struct State + struct Fault { - enum Fault_type { READY, READ_FAULT, WRITE_FAULT, EXEC_FAULT }; + enum class Type { NONE, READ, WRITE, EXEC }; - /** - * Type of occurred fault - */ - Fault_type type = READY; - - /** - * Fault address - */ - addr_t addr = 0; - - /** - * Default constructor - */ - State() { } - - /** - * Constructor - */ - State(Fault_type fault_type, addr_t fault_addr) - : type(fault_type), addr(fault_addr) { } + Type type; /* type of occurred fault */ + addr_t addr; /* fault address unless fault is 'NONE' */ }; + struct Range { addr_t start; size_t num_bytes; }; /** - * Helper for tranferring the bit representation of a pointer as RPC - * argument. + * Attributes for 'attach' */ - class Local_addr + struct Attr { - private: - - void *_ptr = nullptr; - - public: - - template - Local_addr(T ptr) : _ptr((void *)ptr) { } - - Local_addr() { } - - template - operator T () { return (T)_ptr; } + size_t size; /* size of the mapping, or 0 for the whole dataspace */ + addr_t offset; /* page-aligned offset in dataspace */ + bool use_at; + addr_t at; /* designated start of region if 'use_at' is true */ + bool executable; + bool writeable; }; + enum class Attach_error { OUT_OF_RAM, OUT_OF_CAPS, REGION_CONFLICT, INVALID_DATASPACE }; - /********************* - ** Exception types ** - *********************/ - - class Invalid_dataspace : public Exception { }; - class Region_conflict : public Exception { }; - + using Attach_result = Attempt; /** * Map dataspace into region map * - * \param ds capability of dataspace to map - * \param size size of the locally mapped region - * default (0) is the whole dataspace - * \param offset start at offset in dataspace (page-aligned) - * \param use_local_addr if set to true, attach the dataspace at - * the specified 'local_addr' - * \param local_addr local destination address - * \param executable if the mapping should be executable - * \param writeable if the mapping should be writeable - * - * \throw Invalid_dataspace - * \throw Region_conflict - * \throw Out_of_ram RAM quota of meta-data backing store is exhausted - * \throw Out_of_caps cap quota of meta-data backing store is exhausted - * - * \return address of mapped dataspace within region map - * + * \param ds capability of dataspace to map + * \param attr mapping attributes + * \return address range of mapping within region map */ - virtual Local_addr attach(Dataspace_capability ds, - size_t size = 0, off_t offset = 0, - bool use_local_addr = false, - Local_addr local_addr = (void *)0, - bool executable = false, - bool writeable = true) = 0; - - /** - * Shortcut for attaching a dataspace at a predefined local address - */ - Local_addr attach_at(Dataspace_capability ds, addr_t local_addr, - size_t size = 0, off_t offset = 0) { - return attach(ds, size, offset, true, local_addr); } - - /** - * Shortcut for attaching a dataspace executable at a predefined local address - */ - Local_addr attach_executable(Dataspace_capability ds, addr_t local_addr, - size_t size = 0, off_t offset = 0) { - return attach(ds, size, offset, true, local_addr, true); } + virtual Attach_result attach(Dataspace_capability ds, Attr const &attr) = 0; /** * Remove region from local address space */ - virtual void detach(Local_addr local_addr) = 0; + virtual void detach(addr_t) = 0; /** * Register signal handler for region-manager faults @@ -149,9 +87,9 @@ struct Genode::Region_map : Interface virtual void fault_handler(Signal_context_capability handler) = 0; /** - * Request current state of region map + * Request current fault state of region map */ - virtual State state() = 0; + virtual Fault fault() = 0; /** * Return dataspace representation of region map @@ -163,17 +101,13 @@ struct Genode::Region_map : Interface ** RPC declaration ** *********************/ - GENODE_RPC_THROW(Rpc_attach, Local_addr, attach, - GENODE_TYPE_LIST(Invalid_dataspace, Region_conflict, - Out_of_ram, Out_of_caps), - Dataspace_capability, size_t, off_t, bool, Local_addr, - bool, bool); - GENODE_RPC(Rpc_detach, void, detach, Local_addr); + GENODE_RPC(Rpc_attach, Attach_result, attach, Dataspace_capability, Attr const &); + GENODE_RPC(Rpc_detach, void, detach, addr_t); GENODE_RPC(Rpc_fault_handler, void, fault_handler, Signal_context_capability); - GENODE_RPC(Rpc_state, State, state); + GENODE_RPC(Rpc_fault, Fault, fault); GENODE_RPC(Rpc_dataspace, Dataspace_capability, dataspace); - GENODE_RPC_INTERFACE(Rpc_attach, Rpc_detach, Rpc_fault_handler, Rpc_state, + GENODE_RPC_INTERFACE(Rpc_attach, Rpc_detach, Rpc_fault_handler, Rpc_fault, Rpc_dataspace); }; diff --git a/repos/base/include/rm_session/capability.h b/repos/base/include/rm_session/capability.h index 0a11286426..d2bfa9c257 100644 --- a/repos/base/include/rm_session/capability.h +++ b/repos/base/include/rm_session/capability.h @@ -17,6 +17,6 @@ #include #include -namespace Genode { typedef Capability Rm_session_capability; } +namespace Genode { using Rm_session_capability = Capability; } #endif /* _INCLUDE__RM_SESSION__CAPABILITY_H_ */ diff --git a/repos/base/include/rm_session/client.h b/repos/base/include/rm_session/client.h index 47434e5afa..14a84dd558 100644 --- a/repos/base/include/rm_session/client.h +++ b/repos/base/include/rm_session/client.h @@ -24,7 +24,7 @@ struct Genode::Rm_session_client : Rpc_client { explicit Rm_session_client(Rm_session_capability); - Capability create(size_t) override; + Create_result create(size_t) override; void destroy(Capability) override; }; diff --git a/repos/base/include/rm_session/connection.h b/repos/base/include/rm_session/connection.h index 0b6b7cf92c..365eff278a 100644 --- a/repos/base/include/rm_session/connection.h +++ b/repos/base/include/rm_session/connection.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2008-2018 Genode Labs GmbH + * Copyright (C) 2008-2023 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -21,38 +21,35 @@ namespace Genode { struct Rm_connection; } -struct Genode::Rm_connection : Connection, Rm_session_client +struct Genode::Rm_connection : Connection { - enum { RAM_QUOTA = 64*1024 }; + Rm_session_client _client { cap() }; - /** - * Constructor - */ Rm_connection(Env &env) : - Connection(env, session(env.parent(), "ram_quota=%u, cap_quota=%u", - RAM_QUOTA, CAP_QUOTA)), - Rm_session_client(cap()) + Connection(env, {}, Ram_quota { 64*1024 }, Args()) { } /** - * Wrapper over 'create' that handles resource requests - * from the server. + * Wrapper of 'create' that handles session-quota upgrades on demand */ - Capability create(size_t size) override + Capability create(size_t size) { - enum { UPGRADE_ATTEMPTS = 16U }; - - return Genode::retry( - [&] () { - return Genode::retry( - [&] () { return Rm_session_client::create(size); }, - [&] () { upgrade_caps(2); }, - UPGRADE_ATTEMPTS); - }, - [&] () { upgrade_ram(8*1024); }, - UPGRADE_ATTEMPTS); + Capability result { }; + using Error = Rm_session::Create_error; + while (!result.valid()) + _client.create(size).with_result( + [&] (Capability cap) { result = cap; }, + [&] (Error e) { + switch (e) { + case Error::OUT_OF_RAM: upgrade_ram(8*1024); break; + case Error::OUT_OF_CAPS: upgrade_caps(2); break; + } + }); + return result; } + + void destroy(Capability cap) { _client.destroy(cap); } }; #endif /* _INCLUDE__RM_SESSION__CONNECTION_H_ */ diff --git a/repos/base/include/rm_session/rm_session.h b/repos/base/include/rm_session/rm_session.h index 58174e7993..f119455ee3 100644 --- a/repos/base/include/rm_session/rm_session.h +++ b/repos/base/include/rm_session/rm_session.h @@ -33,15 +33,16 @@ struct Genode::Rm_session : Session */ enum { CAP_QUOTA = 2 }; + enum class Create_error { OUT_OF_RAM, OUT_OF_CAPS }; + using Create_result = Attempt, Create_error>; + /** * Create region map * * \param size upper bound of region map * \return region-map capability - * \throw Out_of_ram - * \throw Out_of_caps */ - virtual Capability create(size_t size) = 0; + virtual Create_result create(size_t size) = 0; /** * Destroy region map @@ -53,8 +54,7 @@ struct Genode::Rm_session : Session ** RPC declaration ** *********************/ - GENODE_RPC_THROW(Rpc_create, Capability, create, - GENODE_TYPE_LIST(Out_of_ram, Out_of_caps), size_t); + GENODE_RPC(Rpc_create, Create_result, create, size_t); GENODE_RPC(Rpc_destroy, void, destroy, Capability); GENODE_RPC_INTERFACE(Rpc_create, Rpc_destroy); diff --git a/repos/base/include/rom_session/capability.h b/repos/base/include/rom_session/capability.h index 2a9b1c04f3..f35b00d6de 100644 --- a/repos/base/include/rom_session/capability.h +++ b/repos/base/include/rom_session/capability.h @@ -17,6 +17,6 @@ #include #include -namespace Genode { typedef Capability Rom_session_capability; } +namespace Genode { using Rom_session_capability = Capability; } #endif /* _INCLUDE__ROM_SESSION__CAPABILITY_H_ */ diff --git a/repos/base/include/rom_session/connection.h b/repos/base/include/rom_session/connection.h index ce1b9badf4..fd33e0ac71 100644 --- a/repos/base/include/rom_session/connection.h +++ b/repos/base/include/rom_session/connection.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2008-2017 Genode Labs GmbH + * Copyright (C) 2008-2023 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -16,35 +16,28 @@ #include #include -#include namespace Genode { class Rom_connection; } -struct Genode::Rom_connection : Connection, - Rom_session_client +struct Genode::Rom_connection : Connection, Rom_session_client { - class Rom_connection_failed : public Service_denied { }; - - enum { RAM_QUOTA = 6*1024UL }; + struct Rom_connection_failed : Service_denied { }; /** * Constructor * - * \param label request label and name of ROM module + * \param label name of requested ROM module * * \throw Rom_connection_failed */ - Rom_connection(Env &env, const char *label) + Rom_connection(Env &env, Session_label const &label) try : - Connection(env, - session(env.parent(), - "ram_quota=%ld, cap_quota=%ld, label=\"%s\"", - RAM_QUOTA, CAP_QUOTA, label)), + Connection(env, label, Ram_quota { RAM_QUOTA }, Args()), Rom_session_client(cap()) { } catch (...) { - error("Could not open ROM session for \"", label, "\""); + error("could not open ROM session for \"", label, "\""); throw Rom_connection_failed(); } }; diff --git a/repos/base/include/rom_session/rom_session.h b/repos/base/include/rom_session/rom_session.h index 9a81086acc..90eb2c56b6 100644 --- a/repos/base/include/rom_session/rom_session.h +++ b/repos/base/include/rom_session/rom_session.h @@ -27,7 +27,7 @@ namespace Genode { struct Rom_session; struct Rom_session_client; - typedef Capability Rom_dataspace_capability; + using Rom_dataspace_capability = Capability; } @@ -46,9 +46,10 @@ struct Genode::Rom_session : Session * allocation, a dataspace capability for the ROM dataspace, and its * session capability. */ - enum { CAP_QUOTA = 3 }; + static constexpr unsigned CAP_QUOTA = 3; + static constexpr size_t RAM_QUOTA = 6*1024; - typedef Rom_session_client Client; + using Client = Rom_session_client; virtual ~Rom_session() { } diff --git a/repos/base/include/root/capability.h b/repos/base/include/root/capability.h index 42bbb199dc..195dc7c406 100644 --- a/repos/base/include/root/capability.h +++ b/repos/base/include/root/capability.h @@ -17,6 +17,6 @@ #include #include -namespace Genode { typedef Capability Root_capability; } +namespace Genode { using Root_capability = Capability; } #endif /* _INCLUDE__ROOT__CAPABILITY_H_ */ diff --git a/repos/base/include/root/root.h b/repos/base/include/root/root.h index c7e3a0c908..47b5e04867 100644 --- a/repos/base/include/root/root.h +++ b/repos/base/include/root/root.h @@ -29,8 +29,8 @@ namespace Genode { struct Genode::Root { - typedef Rpc_in_buffer<160> Session_args; - typedef Rpc_in_buffer<160> Upgrade_args; + using Session_args = Rpc_in_buffer<160>; + using Upgrade_args = Rpc_in_buffer<160>; virtual ~Root() { } @@ -84,7 +84,7 @@ struct Genode::Root template struct Genode::Typed_root : Root { - typedef SESSION_TYPE Session_type; + using Session_type = SESSION_TYPE; }; #endif /* _INCLUDE__ROOT__ROOT_H_ */ diff --git a/repos/base/include/session/capability.h b/repos/base/include/session/capability.h index a69d734c31..055ab9d5fa 100644 --- a/repos/base/include/session/capability.h +++ b/repos/base/include/session/capability.h @@ -17,6 +17,6 @@ #include #include -namespace Genode { typedef Capability Session_capability; } +namespace Genode { using Session_capability = Capability; } #endif /* _INCLUDE__SESSION__CAPABILITY_H_ */ diff --git a/repos/base/include/session/session.h b/repos/base/include/session/session.h index 2ef1b6104a..7a4eec48fa 100644 --- a/repos/base/include/session/session.h +++ b/repos/base/include/session/session.h @@ -51,7 +51,7 @@ struct Genode::Session struct Diag { bool enabled; }; - typedef Session_label Label; + using Label = Session_label; /* * Each session interface must implement the class function 'service_name' diff --git a/repos/base/include/spec/arm_64/cpu/cpu_state.h b/repos/base/include/spec/arm_64/cpu/cpu_state.h index b6b9d5b749..8318ce1b0e 100644 --- a/repos/base/include/spec/arm_64/cpu/cpu_state.h +++ b/repos/base/include/spec/arm_64/cpu/cpu_state.h @@ -16,15 +16,28 @@ /* Genode includes */ #include +#include namespace Genode { struct Cpu_state; } struct Genode::Cpu_state { - addr_t r[31] { 0 }; /* general purpose register 0...30 */ - addr_t sp { 0 }; /* stack pointer */ - addr_t ip { 0 }; /* instruction pointer */ + struct Esr : Genode::Register<64> + { + struct Ec : Bitfield<26, 6> + { + enum Exception { + SOFTWARE_STEP = 0b110010, + BREAKPOINT = 0b111100, + }; + }; + }; + + addr_t r[31] { 0 }; /* general purpose register 0...30 */ + addr_t sp { 0 }; /* stack pointer */ + addr_t ip { 0 }; /* instruction pointer */ + addr_t esr_el1 { 0 }; /* exception syndrome */ }; #endif /* _INCLUDE__SPEC__ARM_64__CPU__CPU_STATE_H_ */ diff --git a/repos/base/include/spec/arm_64/cpu/string.h b/repos/base/include/spec/arm_64/cpu/string.h deleted file mode 100644 index 2c5050e41f..0000000000 --- a/repos/base/include/spec/arm_64/cpu/string.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * \brief CPU-specific memcpy - * \author Stefan Kalkowski - * \date 2012-08-02 - */ - -/* - * Copyright (C) 2019 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _INCLUDE__SPEC__ARM_64__CPU__STRING_H_ -#define _INCLUDE__SPEC__ARM_64__CPU__STRING_H_ - -namespace Genode { - - /** - * Copy memory block - * - * \param dst destination memory block - * \param src source memory block - * \param size number of bytes to copy - * - * \return number of bytes not copied - */ - inline size_t memcpy_cpu(void *, const void *, size_t size) { return size; } -} - -#endif /* _INCLUDE__SPEC__ARM_64__CPU__STRING_H_ */ diff --git a/repos/base/include/spec/arm_64/trace/timestamp.h b/repos/base/include/spec/arm_64/trace/timestamp.h index 077effd4dd..f07c07a173 100644 --- a/repos/base/include/spec/arm_64/trace/timestamp.h +++ b/repos/base/include/spec/arm_64/trace/timestamp.h @@ -19,7 +19,7 @@ namespace Genode { namespace Trace { - typedef uint64_t Timestamp; + using Timestamp = uint64_t; inline Timestamp timestamp() { diff --git a/repos/base/include/spec/arm_v6/trace/timestamp.h b/repos/base/include/spec/arm_v6/trace/timestamp.h index 4b49e9c277..308eb74541 100644 --- a/repos/base/include/spec/arm_v6/trace/timestamp.h +++ b/repos/base/include/spec/arm_v6/trace/timestamp.h @@ -20,7 +20,7 @@ namespace Genode { namespace Trace { - typedef uint32_t Timestamp; + using Timestamp = uint32_t; inline Timestamp timestamp() { diff --git a/repos/base/include/spec/arm_v7/trace/timestamp.h b/repos/base/include/spec/arm_v7/trace/timestamp.h index df4e53e038..e53976fc99 100644 --- a/repos/base/include/spec/arm_v7/trace/timestamp.h +++ b/repos/base/include/spec/arm_v7/trace/timestamp.h @@ -20,7 +20,7 @@ namespace Genode { namespace Trace { - typedef uint32_t Timestamp; + using Timestamp = uint32_t; inline Timestamp timestamp() { diff --git a/repos/base/include/spec/riscv/cpu/string.h b/repos/base/include/spec/riscv/cpu/string.h deleted file mode 100644 index 9aa9e79ee0..0000000000 --- a/repos/base/include/spec/riscv/cpu/string.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * \brief CPU-specific memcpy - * \author Sebastian Sumpf - * \date 2015-06-01 - */ - -/* - * Copyright (C) 2015-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _INCLUDE__RISCV__CPU__STRING_H_ -#define _INCLUDE__RISCV__CPU__STRING_H_ - -namespace Genode { - - /** - * Copy memory block - * - * \param dst destination memory block - * \param src source memory block - * \param size number of bytes to copy - * - * \return number of bytes not copied - */ - inline size_t memcpy_cpu(void *, const void *, size_t size) { - return size; } -} - -#endif /* _INCLUDE__RISCV__CPU__STRING_H_ */ diff --git a/repos/base/include/spec/riscv/trace/timestamp.h b/repos/base/include/spec/riscv/trace/timestamp.h index 7da737d8f4..ac045b0704 100644 --- a/repos/base/include/spec/riscv/trace/timestamp.h +++ b/repos/base/include/spec/riscv/trace/timestamp.h @@ -20,7 +20,7 @@ namespace Genode { namespace Trace { - typedef uint32_t Timestamp; + using Timestamp = uint32_t; inline Timestamp timestamp() { diff --git a/repos/base/include/spec/x86/bios_data_area.h b/repos/base/include/spec/x86/bios_data_area.h index b4b36739c8..8d67fd72c9 100644 --- a/repos/base/include/spec/x86/bios_data_area.h +++ b/repos/base/include/spec/x86/bios_data_area.h @@ -22,21 +22,21 @@ namespace Genode { class Bios_data_area; } -class Genode::Bios_data_area : Mmio +class Genode::Bios_data_area : Mmio<0x12> { friend Unmanaged_singleton_constructor; private: - struct Serial_base_com1 : Register<0x400, 16> { }; - struct Equipment : Register<0x410, 16> + struct Serial_base_com1 : Register<0x0, 16> { }; + struct Equipment : Register<0x10, 16> { struct Serial_count : Bitfield<9, 3> { }; }; static addr_t _mmio_base_virt(); - Bios_data_area() : Mmio(_mmio_base_virt()) { } + Bios_data_area() : Mmio({(char *)(_mmio_base_virt() + 0x400), Mmio::SIZE}) { } public: diff --git a/repos/base/include/spec/x86/cpu/string.h b/repos/base/include/spec/x86/cpu/string.h deleted file mode 100644 index fdb3e50dec..0000000000 --- a/repos/base/include/spec/x86/cpu/string.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * \brief CPU-specific memcpy - * \author Sebastian Sumpf - * \date 2012-08-02 - */ - -/* - * Copyright (C) 2012-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _INCLUDE__SPEC__X86__CPU__STRING_H_ -#define _INCLUDE__SPEC__X86__CPU__STRING_H_ - -namespace Genode { - - /** - * Copy memory block - * - * \param dst destination memory block - * \param src source memory block - * \param size number of bytes to copy - * - * \return number of bytes not copied - */ - inline size_t memcpy_cpu(void * dst, const void * src, size_t size) - { - typedef unsigned long word_t; - - enum { - LEN = sizeof(word_t), - MASK = LEN-1 - }; - - unsigned char *d = (unsigned char *)dst, *s = (unsigned char *)src; - - /* check byte alignment */ - size_t d_align = (size_t)d & MASK; - size_t s_align = (size_t)s & MASK; - - /* only same alignments work */ - if (d_align != s_align) - return size; - - /* copy to word alignment */ - for (; (size > 0) && (s_align > 0) && (s_align < LEN); - s_align++, *d++ = *s++, size--); - - /* copy words */ - for (; size >= LEN; size -= LEN, - d += LEN, - s += LEN) - *(word_t*)d = *(word_t*)s; - - return size; - } -} - -#endif /* _INCLUDE__SPEC__X86__CPU__STRING_H_ */ diff --git a/repos/base/include/spec/x86/cpu/vcpu_state.h b/repos/base/include/spec/x86/cpu/vcpu_state.h index 2c6ac5b0f5..6141e566b1 100644 --- a/repos/base/include/spec/x86/cpu/vcpu_state.h +++ b/repos/base/include/spec/x86/cpu/vcpu_state.h @@ -2,11 +2,12 @@ * \brief Virtual CPU context for x86 * \author Alexander Boettcher * \author Christian Helmuth + * \author Benjamin Lamowski * \date 2018-10-09 */ /* - * Copyright (C) 2018-2021 Genode Labs GmbH + * Copyright (C) 2018-2023 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -47,6 +48,8 @@ class Genode::Vcpu_state public: + Vcpu_state() = default; + template class Register : Noncopyable { @@ -79,6 +82,26 @@ class Genode::Vcpu_state _charged = true; _value = value; } + + /* + * Charge without changing value + * + * \noapi + */ + void set_charged() { _charged = true; } + + /* + * Update value if not yet charged + * + * \noapi + */ + void update(T const &value) + { + if (!_charged) { + _value = value; + _charged = true; + } + } }; struct Range @@ -94,85 +117,88 @@ class Genode::Vcpu_state addr_t base; }; - Register ax; - Register cx; - Register dx; - Register bx; + Register ax { }; + Register cx { }; + Register dx { }; + Register bx { }; - Register bp; - Register si; - Register di; + Register bp { }; + Register si { }; + Register di { }; - Register sp; - Register ip; - Register ip_len; - Register flags; + Register sp { }; + Register ip { }; + Register ip_len { }; + Register flags { }; - Register es; - Register ds; - Register fs; - Register gs; - Register cs; - Register ss; - Register tr; - Register ldtr; + Register es { }; + Register ds { }; + Register fs { }; + Register gs { }; + Register cs { }; + Register ss { }; + Register tr { }; + Register ldtr { }; - Register gdtr; - Register idtr; + Register gdtr { }; + Register idtr { }; - Register cr0; - Register cr2; - Register cr3; - Register cr4; + Register cr0 { }; + Register cr2 { }; + Register cr3 { }; + Register cr4 { }; - Register dr7; + Register dr7 { }; - Register sysenter_ip; - Register sysenter_sp; - Register sysenter_cs; + Register sysenter_ip { }; + Register sysenter_sp { }; + Register sysenter_cs { }; - Register qual_primary; - Register qual_secondary; + Register qual_primary { }; + Register qual_secondary { }; - Register ctrl_primary; - Register ctrl_secondary; + Register ctrl_primary { }; + Register ctrl_secondary { }; - Register inj_info; - Register inj_error; + Register inj_info { }; + Register inj_error { }; - Register intr_state; - Register actv_state; + Register intr_state { }; + Register actv_state { }; - Register tsc; - Register tsc_offset; - Register tsc_aux; + Register tsc { }; + Register tsc_offset { }; + Register tsc_aux { }; - Register efer; + Register efer { }; - Register pdpte_0; - Register pdpte_1; - Register pdpte_2; - Register pdpte_3; + Register pdpte_0 { }; + Register pdpte_1 { }; + Register pdpte_2 { }; + Register pdpte_3 { }; - Register r8; - Register r9; - Register r10; - Register r11; - Register r12; - Register r13; - Register r14; - Register r15; + Register r8 { }; + Register r9 { }; + Register r10 { }; + Register r11 { }; + Register r12 { }; + Register r13 { }; + Register r14 { }; + Register r15 { }; - Register star; - Register lstar; - Register cstar; - Register fmask; - Register kernel_gs_base; + Register star { }; + Register lstar { }; + Register cstar { }; + Register fmask { }; + Register kernel_gs_base { }; - Register tpr; - Register tpr_threshold; + Register tpr { }; + Register tpr_threshold { }; - unsigned exit_reason; + Register xcr0 { }; + Register xss { }; + + unsigned exit_reason { }; class Fpu : Noncopyable { @@ -202,21 +228,16 @@ class Genode::Vcpu_state bool charged() const { return _charged; } - template - void with_state(FN const &fn) const - { - fn(_state); - } + void with_state(auto const &fn) const { fn(_state); } - template - void charge(FN const &fn) + void charge(auto const &fn) { _charged = true; fn(_state); } }; - Fpu fpu __attribute__((aligned(16))); + Fpu fpu __attribute__((aligned(16))) { }; /* * Registers transfered by hypervisor from guest on VM exit are charged. diff --git a/repos/base/include/spec/x86_32/cpu/cpu_state.h b/repos/base/include/spec/x86_32/cpu/cpu_state.h index 2b88fd613f..e1c6417eb3 100644 --- a/repos/base/include/spec/x86_32/cpu/cpu_state.h +++ b/repos/base/include/spec/x86_32/cpu/cpu_state.h @@ -36,6 +36,11 @@ struct Genode::Cpu_state addr_t fs = 0; addr_t eflags = 0; addr_t trapno = 0; + + enum { + ACPI_SUSPEND_REQUEST = 0x100, /* convention for system_control() */ + MSR_ACCESS = 0x101, /* convention for system_control() */ + }; }; #endif /* _INCLUDE__SPEC__X86_32__CPU__CPU_STATE_H_ */ diff --git a/repos/base/include/spec/x86_32/trace/timestamp.h b/repos/base/include/spec/x86_32/trace/timestamp.h index 9a73140dad..2a397cd3e5 100644 --- a/repos/base/include/spec/x86_32/trace/timestamp.h +++ b/repos/base/include/spec/x86_32/trace/timestamp.h @@ -20,7 +20,7 @@ namespace Genode { namespace Trace { - typedef uint64_t Timestamp; + using Timestamp = uint64_t; inline Timestamp timestamp() { diff --git a/repos/base/include/spec/x86_64/cpu/clflush.h b/repos/base/include/spec/x86_64/cpu/clflush.h new file mode 100644 index 0000000000..7d816f2269 --- /dev/null +++ b/repos/base/include/spec/x86_64/cpu/clflush.h @@ -0,0 +1,24 @@ +/* + * \brief Helper for flushing cache lines + * \author Johannes Schlatow + * \date 2023-09-20 + */ + +/* + * Copyright (C) 2023 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _INCLUDE__SPEC__X86_64__CLFLUSH_H_ +#define _INCLUDE__SPEC__X86_64__CLFLUSH_H_ + +namespace Genode { + inline void clflush(volatile void *addr) + { + asm volatile("clflush %0" : "+m" (*(volatile char *)addr)); + } +} + +#endif /* _INCLUDE__SPEC__X86_64__CLFLUSH_H_ */ diff --git a/repos/base/include/spec/x86_64/cpu/cpu_state.h b/repos/base/include/spec/x86_64/cpu/cpu_state.h index 7ab0324be9..99ca5c8901 100644 --- a/repos/base/include/spec/x86_64/cpu/cpu_state.h +++ b/repos/base/include/spec/x86_64/cpu/cpu_state.h @@ -4,13 +4,14 @@ * \author Christian Prochaska * \author Reto Buerki * \author Stefan Kalkowski + * \author Benjamin Lamowski * \date 2011-04-15 * * This file contains the x86_64-specific part of the CPU state. */ /* - * Copyright (C) 2011-2017 Genode Labs GmbH + * Copyright (C) 2011-2024 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -26,9 +27,14 @@ namespace Genode { struct Cpu_state; } struct Genode::Cpu_state { enum Cpu_exception { + DIVIDE_ERROR = 0x00, + DEBUG = 0x01, + BREAKPOINT = 0x03, UNDEFINED_INSTRUCTION = 0x06, NO_MATH_COPROC = 0x07, + GENERAL_PROTECTION = 0x0d, PAGE_FAULT = 0x0e, + ALIGNMENT_CHECK = 0x11, SUPERVISOR_CALL = 0x80, INTERRUPTS_START = 0x20, RESET = 0xfe, @@ -57,6 +63,11 @@ struct Genode::Cpu_state addr_t eflags = 0; addr_t sp = 0; addr_t ss = 0; + + enum { + ACPI_SUSPEND_REQUEST = 0x100, /* convention for system_control() */ + MSR_ACCESS = 0x101, /* convention for system_control() */ + }; }; #endif /* _INCLUDE__SPEC__X86_64__CPU__CPU_STATE_H_ */ diff --git a/repos/base/include/spec/x86_64/page_table/page_table_base.h b/repos/base/include/spec/x86_64/page_table/page_table_base.h new file mode 100644 index 0000000000..88ac0a9e5b --- /dev/null +++ b/repos/base/include/spec/x86_64/page_table/page_table_base.h @@ -0,0 +1,640 @@ +/* + * \brief x86_64 page table definitions + * \author Adrian-Ken Rueegsegger + * \author Johannes Schlatow + * \author Benjamin Lamowski + * \date 2015-02-06 + */ + +/* + * Copyright (C) 2015-2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _INCLUDE__SPEC__X86_64__PAGE_TABLE__PAGE_TABLE_BASE_H_ +#define _INCLUDE__SPEC__X86_64__PAGE_TABLE__PAGE_TABLE_BASE_H_ + +#include +#include +#include +#include + +namespace Genode { + + /** + * (Generic) 4-level translation structures. + */ + + enum { + SIZE_LOG2_4KB = 12, + SIZE_LOG2_2MB = 21, + SIZE_LOG2_1GB = 30, + SIZE_LOG2_512GB = 39, + SIZE_LOG2_256TB = 48, + }; + + /** + * Final page table template + * + * The last-level page table solely maps page frames. + */ + template + class Final_table; + + /** + * Page directory template. + * + * Page directories can refer to paging structures of the next level + * or directly map page frames by using large page mappings. + */ + template + class Page_directory; + + /** + * The 4th-level table refers to paging structures of the next level. + */ + template + class Pml4_table; +} + + +template +class Genode::Final_table +{ + public: + + using Descriptor = DESCRIPTOR; + + private: + + static constexpr size_t PAGE_SIZE_LOG2 = DESCRIPTOR::PAGE_SIZE_LOG2; + static constexpr size_t MAX_ENTRIES = 512; + static constexpr size_t PAGE_SIZE = 1UL << PAGE_SIZE_LOG2; + static constexpr size_t PAGE_MASK = ~((1UL << PAGE_SIZE_LOG2) - 1); + + class Misaligned {}; + class Invalid_range {}; + class Double_insertion {}; + + typename DESCRIPTOR::access_t _entries[MAX_ENTRIES]; + + struct Insert_func + { + Page_flags const & flags; + bool flush; + + Insert_func(Page_flags const & flags, bool flush) + : flags(flags), flush(flush) { } + + void operator () (addr_t const vo, addr_t const pa, + size_t const size, + DESCRIPTOR::access_t &desc) const + { + if ((vo & ~PAGE_MASK) || (pa & ~PAGE_MASK) || + size < PAGE_SIZE) + { + throw Invalid_range(); + } + typename DESCRIPTOR::access_t table_entry = + DESCRIPTOR::create(flags, pa); + + if (DESCRIPTOR::present(desc) && + DESCRIPTOR::clear_mmu_flags(desc) != table_entry) + { + throw Double_insertion(); + } + desc = table_entry; + + if (flush) + clflush(&desc); + } + }; + + struct Remove_func + { + bool flush; + + Remove_func(bool flush) : flush(flush) { } + + void operator () (addr_t /* vo */, addr_t /* pa */, size_t /* size */, + DESCRIPTOR::access_t &desc) const + { + desc = 0; + + if (flush) + clflush(&desc); + } + }; + + void _range_op(addr_t vo, addr_t pa, size_t size, auto const &fn) + { + for (size_t i = vo >> PAGE_SIZE_LOG2; size > 0; + i = vo >> PAGE_SIZE_LOG2) { + addr_t end = (vo + PAGE_SIZE) & PAGE_MASK; + size_t sz = Genode::min(size, end-vo); + + fn(vo, pa, sz, _entries[i]); + + /* check whether we wrap */ + if (end < vo) return; + + size = size - sz; + vo += sz; + pa += sz; + } + } + + public: + + static constexpr size_t MIN_PAGE_SIZE_LOG2 = SIZE_LOG2_4KB; + static constexpr size_t ALIGNM_LOG2 = SIZE_LOG2_4KB; + + /** + * A page table consists of 512 entries that each maps a 4KB page + * frame. For further details refer to Intel SDM Vol. 3A, table 4-19. + */ + Final_table() + { + if (!aligned((addr_t)this, ALIGNM_LOG2)) throw Misaligned(); + Genode::memset(&_entries, 0, sizeof(_entries)); + } + + /** + * Returns True if table does not contain any page mappings. + */ + bool empty() + { + for (unsigned i = 0; i < MAX_ENTRIES; i++) + if (DESCRIPTOR::present(_entries[i])) + return false; + return true; + } + + void for_each_entry(auto const &fn) + { + for (unsigned long i = 0; i < MAX_ENTRIES; i++) { + if (Descriptor::present(_entries[i])) + fn(i, _entries[i]); + } + } + + /** + * Insert translations into this table + * + * \param vo offset of the virtual region represented + * by the translation within the virtual + * region represented by this table + * \param pa base of the physical backing store + * \param size size of the translated region + * \param flags mapping flags + * \param alloc second level translation table allocator + * \param flush flush cache lines of table entries + * \param supported_sizes supported page sizes + */ + template + void insert_translation(addr_t vo, addr_t pa, size_t size, + Page_flags const & flags, ALLOCATOR &, + bool flush = false, uint32_t supported_sizes = (1U << 30 | 1U << 21 | 1U << 12)) + { + (void)supported_sizes; + this->_range_op(vo, pa, size, Insert_func(flags, flush)); + } + + /** + * Remove translations that overlap with a given virtual region + * + * \param vo region offset within the tables virtual region + * \param size region size + * \param alloc second level translation table allocator + */ + template + void remove_translation(addr_t vo, size_t size, ALLOCATOR &, bool flush = false) + { + this->_range_op(vo, 0, size, Remove_func(flush)); + } + +} __attribute__((aligned(1 << ALIGNM_LOG2))); + + +template +class Genode::Page_directory +{ + public: + + using Descriptor = DESCRIPTOR; + using Entry = ENTRY; + + private: + + static constexpr size_t PAGE_SIZE_LOG2 = Descriptor::PAGE_SIZE_LOG2; + static constexpr size_t MAX_ENTRIES = 512; + static constexpr size_t PAGE_SIZE = 1UL << PAGE_SIZE_LOG2; + static constexpr size_t PAGE_MASK = ~((1UL << PAGE_SIZE_LOG2) - 1); + + class Misaligned {}; + class Invalid_range {}; + class Double_insertion {}; + + typename Descriptor::access_t _entries[MAX_ENTRIES]; + + template + struct Insert_func + { + Page_flags const & flags; + ALLOCATOR & alloc; + bool flush; + uint32_t supported_sizes; + + Insert_func(Page_flags const & flags, ALLOCATOR & alloc, bool flush, + uint32_t supported_sizes) + : flags(flags), alloc(alloc), flush(flush), + supported_sizes(supported_sizes) + { } + + void operator () (addr_t const vo, addr_t const pa, + size_t const size, + typename Descriptor::access_t &desc) const + { + using Td = Descriptor::Table; + using access_t = typename Descriptor::access_t; + + /* can we insert a large page mapping? */ + if ((supported_sizes & PAGE_SIZE) && + !((vo & ~PAGE_MASK) || (pa & ~PAGE_MASK) || size < PAGE_SIZE)) + { + access_t table_entry = Descriptor::Page::create(flags, pa); + + if (Descriptor::present(desc) && + Descriptor::clear_mmu_flags(desc) != table_entry) { + throw Double_insertion(); } + + desc = table_entry; + if (flush) + clflush(&desc); + return; + } + + /* we need to use a next level table */ + if (!Descriptor::present(desc)) { + + /* create and link next level table */ + addr_t table_phys = alloc.template construct(); + desc = (access_t) Td::create(table_phys); + + if (flush) + clflush(&desc); + + } else if (Descriptor::maps_page(desc)) { + throw Double_insertion(); + } + + /* insert translation */ + alloc.template with_table(Td::Pa::masked(desc), + [&] (ENTRY & table) { + table.insert_translation(vo - (vo & PAGE_MASK), pa, size, + flags, alloc, flush, supported_sizes); + }, + [&] { + error("Unable to get mapped table address for ", + Genode::Hex(Td::Pa::masked(desc))); + }); + } + }; + + template + struct Remove_func + { + ALLOCATOR & alloc; + bool flush; + + Remove_func(ALLOCATOR & alloc, bool flush) + : alloc(alloc), flush(flush) { } + + void operator () (addr_t const vo, addr_t /* pa */, + size_t const size, + typename Descriptor::access_t &desc) const + { + if (Descriptor::present(desc)) { + if (Descriptor::maps_page(desc)) { + desc = 0; + } else { + using Td = Descriptor::Table; + + /* use allocator to retrieve virt address of table */ + addr_t table_phys = Td::Pa::masked(desc); + + alloc.template with_table(table_phys, + [&] (ENTRY & table) { + addr_t const table_vo = vo - (vo & PAGE_MASK); + table.remove_translation(table_vo, size, alloc, flush); + if (table.empty()) { + alloc.template destruct(table_phys); + desc = 0; + } + }, + [&] { + error("Unable to get mapped table address for ", + Genode::Hex(table_phys)); + }); + } + + if (desc == 0 && flush) + clflush(&desc); + } + } + }; + + void _range_op(addr_t vo, addr_t pa, size_t size, auto const &fn) + { + for (size_t i = vo >> PAGE_SIZE_LOG2; size > 0; + i = vo >> PAGE_SIZE_LOG2) + { + addr_t end = (vo + PAGE_SIZE) & PAGE_MASK; + size_t sz = Genode::min(size, end-vo); + + fn(vo, pa, sz, _entries[i]); + + /* check whether we wrap */ + if (end < vo) return; + + size = size - sz; + vo += sz; + pa += sz; + } + } + + public: + + static constexpr size_t MIN_PAGE_SIZE_LOG2 = SIZE_LOG2_4KB; + static constexpr size_t ALIGNM_LOG2 = SIZE_LOG2_4KB; + + Page_directory() + { + if (!aligned((addr_t)this, ALIGNM_LOG2)) throw Misaligned(); + Genode::memset(&_entries, 0, sizeof(_entries)); + } + + /** + * Returns True if table does not contain any page mappings. + * + * \return false if an entry is present, True otherwise + */ + bool empty() + { + for (unsigned i = 0; i < MAX_ENTRIES; i++) + if (Descriptor::present(_entries[i])) + return false; + return true; + } + + void for_each_entry(auto const &fn) + { + for (unsigned long i = 0; i < MAX_ENTRIES; i++) + if (Descriptor::present(_entries[i])) + fn(i, _entries[i]); + } + + /** + * Insert translations into this table + * + * \param vo offset of the virtual region represented + * by the translation within the virtual + * region represented by this table + * \param pa base of the physical backing store + * \param size size of the translated region + * \param flags mapping flags + * \param alloc second level translation table allocator + * \param flush flush cache lines of table entries + * \param supported_sizes supported page sizes + */ + template + void insert_translation(addr_t vo, addr_t pa, size_t size, + Page_flags const & flags, ALLOCATOR & alloc, + bool flush = false, + uint32_t supported_sizes = (1U << 30 | 1U << 21 | 1U << 12)) + { + _range_op(vo, pa, size, + Insert_func(flags, alloc, flush, supported_sizes)); + } + + /** + * Remove translations that overlap with a given virtual region + * + * \param vo region offset within the tables virtual region + * \param size region size + * \param alloc second level translation table allocator + */ + template + void remove_translation(addr_t vo, size_t size, ALLOCATOR & alloc, + bool flush) { + _range_op(vo, 0, size, Remove_func(alloc, flush)); } +}; + + +template +class Genode::Pml4_table +{ + public: + + using Descriptor = DESCRIPTOR; + using Entry = ENTRY; + + private: + + static constexpr size_t PAGE_SIZE_LOG2 = Descriptor::PAGE_SIZE_LOG2; + static constexpr size_t SIZE_LOG2 = Descriptor::SIZE_LOG2; + static constexpr size_t SIZE_MASK = (1UL << SIZE_LOG2) - 1; + static constexpr size_t MAX_ENTRIES = 512; + static constexpr size_t PAGE_SIZE = 1UL << PAGE_SIZE_LOG2; + static constexpr size_t PAGE_MASK = ~((1UL << PAGE_SIZE_LOG2) - 1); + + class Misaligned {}; + class Invalid_range {}; + + typename Descriptor::access_t _entries[MAX_ENTRIES]; + + template + struct Insert_func + { + Page_flags const & flags; + ALLOCATOR & alloc; + bool flush; + uint32_t supported_sizes; + + Insert_func(Page_flags const & flags, + ALLOCATOR & alloc, bool flush, uint32_t supported_sizes) + : flags(flags), alloc(alloc), flush(flush), + supported_sizes(supported_sizes) { } + + void operator () (addr_t const vo, addr_t const pa, + size_t const size, + Descriptor::access_t &desc) const + { + /* we need to use a next level table */ + if (!Descriptor::present(desc)) { + /* create and link next level table */ + addr_t table_phys = alloc.template construct(); + desc = Descriptor::create(table_phys); + + if (flush) + clflush(&desc); + } + + /* insert translation */ + addr_t table_phys = Descriptor::Pa::masked(desc); + alloc.template with_table(table_phys, + [&] (ENTRY & table) { + addr_t const table_vo = vo - (vo & PAGE_MASK); + table.insert_translation(table_vo, pa, size, flags, alloc, + flush, supported_sizes); + }, + [&] { + error("Unable to get mapped table address for ", + Genode::Hex(table_phys)); + }); + } + }; + + template + struct Remove_func + { + ALLOCATOR & alloc; + bool flush; + + Remove_func(ALLOCATOR & alloc, bool flush) + : alloc(alloc), flush(flush) { } + + void operator () (addr_t const vo, addr_t /* pa */, + size_t const size, + Descriptor::access_t &desc) const + { + if (Descriptor::present(desc)) { + /* use allocator to retrieve virt address of table */ + addr_t table_phys = Descriptor::Pa::masked(desc); + alloc.template with_table(table_phys, + [&] (ENTRY & table) { + addr_t const table_vo = vo - (vo & PAGE_MASK); + table.remove_translation(table_vo, size, alloc, flush); + if (table.empty()) { + alloc.template destruct(table_phys); + desc = 0; + + if (flush) + clflush(&desc); + } + }, + [&] { + error("Unable to get mapped table address for ", + Genode::Hex(table_phys)); + }); + } + } + }; + + void _range_op(addr_t vo, addr_t pa, size_t size, auto const &fn) + { + for (size_t i = (vo & SIZE_MASK) >> PAGE_SIZE_LOG2; size > 0; + i = (vo & SIZE_MASK) >> PAGE_SIZE_LOG2) { + addr_t end = (vo + PAGE_SIZE) & PAGE_MASK; + size_t sz = Genode::min(size, end-vo); + + fn(vo, pa, sz, _entries[i]); + + /* check whether we wrap */ + if (end < vo) return; + + size = size - sz; + vo += sz; + pa += sz; + } + } + + protected: + + /** + * Return how many entries of an alignment fit into region + */ + static constexpr size_t _count(size_t region, size_t alignment) + { + return Genode::align_addr(region, (int)alignment) + / (1UL << alignment); + } + + public: + + static constexpr size_t MIN_PAGE_SIZE_LOG2 = SIZE_LOG2_4KB; + static constexpr size_t ALIGNM_LOG2 = SIZE_LOG2_4KB; + + Pml4_table() + { + if (!aligned((addr_t)this, ALIGNM_LOG2)) throw Misaligned(); + Genode::memset(&_entries, 0, sizeof(_entries)); + } + + explicit Pml4_table(Pml4_table & kernel_table) : Pml4_table() + { + static size_t first = (0xffffffc000000000 & SIZE_MASK) >> PAGE_SIZE_LOG2; + for (size_t i = first; i < MAX_ENTRIES; i++) + _entries[i] = kernel_table._entries[i]; + } + + /** + * Returns True if table does not contain any page mappings. + * + * \return false if an entry is present, True otherwise + */ + bool empty() + { + for (unsigned i = 0; i < MAX_ENTRIES; i++) + if (Descriptor::present(_entries[i])) + return false; + return true; + } + + void for_each_entry(auto const &fn) + { + for (unsigned long i = 0; i < MAX_ENTRIES; i++) { + if (Descriptor::present(_entries[i])) + fn(i, _entries[i]); + } + } + + /** + * Insert translations into this table + * + * \param vo offset of the virtual region represented + * by the translation within the virtual + * region represented by this table + * \param pa base of the physical backing store + * \param size size of the translated region + * \param flags mapping flags + * \param alloc second level translation table allocator + * \param flush flush cache lines of table entries + * \param supported_sizes supported page sizes + */ + template + void insert_translation(addr_t vo, addr_t pa, size_t size, + Page_flags const & flags, ALLOCATOR & alloc, + bool flush = false, uint32_t supported_sizes = (1U << 30 | 1U << 21 | 1U << 12)) { + _range_op(vo, pa, size, + Insert_func(flags, alloc, flush, supported_sizes)); } + + /** + * Remove translations that overlap with a given virtual region + * + * \param vo region offset within the tables virtual region + * \param size region size + * \param alloc second level translation table allocator + */ + template + void remove_translation(addr_t vo, size_t size, ALLOCATOR & alloc, + bool flush = false) + { + _range_op(vo, 0, size, Remove_func(alloc, flush)); + } + +} __attribute__((aligned(1 << ALIGNM_LOG2))); + +#endif /* _INCLUDE__SPEC__X86_64__PAGE_TABLE__PAGE_TABLE_BASE_H_ */ diff --git a/repos/base/include/spec/x86_64/trace/timestamp.h b/repos/base/include/spec/x86_64/trace/timestamp.h index a432dabb87..643cecf7a5 100644 --- a/repos/base/include/spec/x86_64/trace/timestamp.h +++ b/repos/base/include/spec/x86_64/trace/timestamp.h @@ -20,7 +20,7 @@ namespace Genode { namespace Trace { - typedef uint64_t Timestamp; + using Timestamp = uint64_t; inline Timestamp timestamp() __attribute((always_inline)); inline Timestamp timestamp() diff --git a/repos/base/include/timer_session/capability.h b/repos/base/include/timer_session/capability.h index 257d4b99d4..96e6cd06e6 100644 --- a/repos/base/include/timer_session/capability.h +++ b/repos/base/include/timer_session/capability.h @@ -17,6 +17,6 @@ #include #include -namespace Timer { typedef Genode::Capability Session_capability; } +namespace Timer { using Session_capability = Genode::Capability; } #endif /* _INCLUDE__TIMER_SESSION__CAPABILITY_H_ */ diff --git a/repos/base/include/timer_session/connection.h b/repos/base/include/timer_session/connection.h index 4f24dea770..858fc9853c 100644 --- a/repos/base/include/timer_session/connection.h +++ b/repos/base/include/timer_session/connection.h @@ -186,7 +186,7 @@ class Timer::Connection : public Genode::Connection, Genode::Signal_context _default_sigh_ctx { }; Genode::Signal_context_capability - _default_sigh_cap = _sig_rec.manage(&_default_sigh_ctx); + _default_sigh_cap = _sig_rec.manage(_default_sigh_ctx); Genode::Signal_context_capability _custom_sigh_cap { }; @@ -199,7 +199,7 @@ class Timer::Connection : public Genode::Connection, ** Members for interaction with Timeout framework ** ****************************************************/ - enum { MIN_TIMEOUT_US = 5000 }; + enum { MIN_TIMEOUT_US = 1000 }; enum { REAL_TIME_UPDATE_PERIOD_US = 500000 }; enum { MAX_INTERPOLATION_QUALITY = 3 }; enum { MAX_REMOTE_TIME_LATENCY_US = 500 }; @@ -256,16 +256,17 @@ class Timer::Connection : public Genode::Connection, * \param label optional label used in session routing */ Connection(Genode::Env &env, - Genode::Entrypoint & ep, - char const *label = ""); + Genode::Entrypoint &ep, + Label const &label = Label()); /** * Convenience constructor wrapper using the environment's entrypoint as * timeout handler execution context */ - Connection(Genode::Env &env, char const *label = ""); + Connection(Genode::Env &env, Label const &label = Label()) + : Connection(env, env.ep(), label) { } - ~Connection() { _sig_rec.dissolve(&_default_sigh_ctx); } + ~Connection() { _sig_rec.dissolve(_default_sigh_ctx); } /* * Intercept 'sigh' to keep track of customized signal handlers diff --git a/repos/base/include/timer_session/timer_session.h b/repos/base/include/timer_session/timer_session.h index f552a39ac9..1400bed8be 100644 --- a/repos/base/include/timer_session/timer_session.h +++ b/repos/base/include/timer_session/timer_session.h @@ -29,7 +29,7 @@ namespace Timer { struct Timer::Session : Genode::Session { - typedef Genode::Signal_context_capability Signal_context_capability; + using Signal_context_capability = Genode::Signal_context_capability; /** * \noapi diff --git a/repos/base/include/trace_session/client.h b/repos/base/include/trace_session/client.h deleted file mode 100644 index 406bfbd93e..0000000000 --- a/repos/base/include/trace_session/client.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * \brief Client-side TRACE session interface - * \author Norman Feske - * \date 2013-08-12 - */ - -/* - * Copyright (C) 2013-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _INCLUDE__TRACE_SESSION__CLIENT_H_ -#define _INCLUDE__TRACE_SESSION__CLIENT_H_ - -#include -#include -#include - -namespace Genode { namespace Trace { struct Session_client; } } - - -struct Genode::Trace::Session_client : Genode::Rpc_client -{ - private: - - /** - * Shared-memory buffer used for carrying the payload of the - * 'subjects()' RPC function. - */ - class Argument_buffer - { - private: - - /* - * Noncopyable - */ - Argument_buffer(Argument_buffer const &); - Argument_buffer &operator = (Argument_buffer const &); - - public: - - Region_map &rm; - char *base; - size_t size; - - Argument_buffer(Region_map &rm, Dataspace_capability ds) - : - rm(rm), - base(rm.attach(ds)), - size(ds.call()) - { } - - ~Argument_buffer() - { - rm.detach(base); - } - }; - - Argument_buffer _argument_buffer; - - public: - - /** - * Constructor - */ - explicit Session_client(Region_map &rm, Capability session) - : - Rpc_client(session), - _argument_buffer(rm, call()) - { } - - /** - * Retrieve subject directory - * - * \throw Out_of_ram - * \throw Out_of_caps - */ - virtual size_t subjects(Subject_id *dst, size_t dst_len) - { - size_t const num_subjects = min(call(), dst_len); - - memcpy(dst, _argument_buffer.base, num_subjects*sizeof(Subject_id)); - - return num_subjects; - } - - struct For_each_subject_info_result { size_t count; size_t limit; }; - - template - For_each_subject_info_result for_each_subject_info(FN const &fn) - { - size_t const num_subjects = call(); - size_t const max_subjects = _argument_buffer.size / (sizeof(Subject_info) + sizeof(Subject_id)); - - Subject_info * const infos = reinterpret_cast(_argument_buffer.base); - Subject_id * const ids = reinterpret_cast(infos + max_subjects); - - for (unsigned i = 0; i < num_subjects; i++) { - fn(ids[i], infos[i]); - } - - return { .count = num_subjects, .limit = max_subjects }; - } - - Policy_id alloc_policy(size_t size) override { - return call(size); } - - Dataspace_capability policy(Policy_id policy_id) override { - return call(policy_id); } - - void unload_policy(Policy_id policy_id) override { - call(policy_id); } - - void trace(Subject_id s, Policy_id p, size_t buffer_size) override { - call(s, p, buffer_size); } - - void pause(Subject_id subject) override { - call(subject); } - - void resume(Subject_id subject) override { - call(subject); } - - Dataspace_capability buffer(Subject_id subject) override { - return call(subject); } - - void free(Subject_id subject) override { - call(subject); } -}; - -#endif /* _INCLUDE__TRACE_SESSION__CLIENT_H_ */ diff --git a/repos/base/include/trace_session/connection.h b/repos/base/include/trace_session/connection.h index 260d3eff79..6f5c07fce5 100644 --- a/repos/base/include/trace_session/connection.h +++ b/repos/base/include/trace_session/connection.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2013-2017 Genode Labs GmbH + * Copyright (C) 2013-2023 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -15,19 +15,36 @@ #define _INCLUDE__TRACE_SESSION__CONNECTION_H_ #include -#include +#include +#include #include +#include namespace Genode { namespace Trace { struct Connection; } } struct Genode::Trace::Connection : Genode::Connection, - Genode::Trace::Session_client + Genode::Rpc_client { - template - auto _retry(FUNC func) -> decltype(func()) + /** + * Shared-memory buffer used for carrying the payload of subject infos + */ + Attached_dataspace _argument_buffer; + + size_t const _max_arg_size; + + template + auto _retry(auto const &fn) -> decltype(fn()) { - return retry_with_upgrade(Ram_quota{8*1024}, Cap_quota{2}, func); + for (;;) { + bool retry = false; + auto const result = fn(); + if (result == ERROR::OUT_OF_CAPS) { upgrade_caps(2); retry = true; } + if (result == ERROR::OUT_OF_RAM) { upgrade_ram(8*1024); retry = true; } + + if (!retry) + return result; + } } /** @@ -35,39 +52,146 @@ struct Genode::Trace::Connection : Genode::Connection, * * \param ram_quota RAM donated for tracing purposes * \param arg_buffer_size session argument-buffer size - * \param parent_levels number of parent levels to trace */ - Connection(Env &env, size_t ram_quota, size_t arg_buffer_size, unsigned parent_levels) + Connection(Env &env, size_t ram_quota, size_t arg_buffer_size) : - Genode::Connection(env, - session(env.parent(), "ram_quota=%lu, arg_buffer_size=%lu, parent_levels=%u", - ram_quota + 10*1024, arg_buffer_size, parent_levels)), - Session_client(env.rm(), cap()) + Genode::Connection(env, Label(), Ram_quota { 10*1024 + ram_quota }, + Args("arg_buffer_size=", arg_buffer_size)), + Genode::Rpc_client(cap()), + _argument_buffer(env.rm(), call()), + _max_arg_size(arg_buffer_size) { } - Policy_id alloc_policy(size_t size) override + enum class Alloc_policy_error { INVALID }; + + using Alloc_policy_result = Attempt; + + /** + * Allocate policy-module backing store + */ + Alloc_policy_result alloc_policy(Policy_size size) { - return _retry([&] () { - return Session_client::alloc_policy(size); }); + if (size.num_bytes > _max_arg_size) + return Alloc_policy_error::INVALID; + + Alloc_policy_rpc_result const result = _retry([&] { + return call(size); }); + + return result.convert( + [&] (Policy_id const id) { return id; }, + [&] (Alloc_policy_rpc_error) { return Alloc_policy_error::INVALID; }); } - void trace(Subject_id s, Policy_id p, size_t buffer_size) override + /** + * Request policy-module backing store + * + * \return dataspace capability, or invalid capability if ID does not + * refer to a known policy + */ + Dataspace_capability policy(Policy_id id) { return call(id); } + + /** + * Remove a policy module from the TRACE service + */ + void unload_policy(Policy_id id) { call(id); } + + enum class Trace_error { FOREIGN, SOURCE_IS_DEAD, INVALID_SUBJECT, INVALID_POLICY }; + using Trace_result = Attempt; + + /** + * Start tracing of a subject + */ + Trace_result trace(Subject_id const s, Policy_id const p, Buffer_size const size) { - _retry([&] () { Session_client::trace(s, p, buffer_size); }); + Trace_rpc_result const rpc_result = + _retry([&] () -> Trace_rpc_result { + return call(s, p, size); }); + + return rpc_result.convert( + [&] (Trace_ok ok) { return ok; }, + [&] (Trace_rpc_error e) { + switch (e) { + case Trace_rpc_error::OUT_OF_RAM: /* cannot occur, handled by '_retry' above */ + case Trace_rpc_error::OUT_OF_CAPS: break; + case Trace_rpc_error::FOREIGN: return Trace_error::FOREIGN; + case Trace_rpc_error::SOURCE_IS_DEAD: return Trace_error::SOURCE_IS_DEAD; + case Trace_rpc_error::INVALID_SUBJECT: return Trace_error::INVALID_SUBJECT; + case Trace_rpc_error::INVALID_POLICY: break; + } + return Trace_error::INVALID_POLICY; + }); } - size_t subjects(Subject_id *dst, size_t dst_len) override + /** + * Retrieve subject directory + */ + Num_subjects subjects(Subject_id * const dst, Num_subjects const dst_num_subjects) { - return _retry([&] () { - return Session_client::subjects(dst, dst_len); }); + Subjects_rpc_result const result = _retry([&] { + return call(); }); + + return result.convert( + + [&] (Num_subjects const num_subjects) { + auto const n = min(num_subjects.value, dst_num_subjects.value); + memcpy(dst, _argument_buffer.local_addr(), n*sizeof(Subject_id)); + return Num_subjects { n }; + }, + + [&] (Alloc_rpc_error) { return Num_subjects { 0 }; }); } - template - For_each_subject_info_result for_each_subject_info(FN const &fn) + struct For_each_subject_info_result { unsigned count; unsigned limit; }; + + /** + * Call 'fn' for each trace subject with 'Subject_info' as argument + */ + For_each_subject_info_result for_each_subject_info(auto const &fn) { - return _retry([&] () { - return Session_client::for_each_subject_info(fn); }); + Infos_rpc_result const result = _retry([&] { + return call(); }); + + return result.convert( + [&] (Num_subjects const n) -> For_each_subject_info_result { + + size_t const subject_bytes = sizeof(Subject_info) + sizeof(Subject_id); + + unsigned const max_subjects = unsigned(_argument_buffer.size() / subject_bytes); + + Subject_info * const infos = _argument_buffer.local_addr(); + Subject_id * const ids = reinterpret_cast(infos + max_subjects); + + for (unsigned i = 0; i < n.value; i++) + fn(ids[i], infos[i]); + + return { .count = n.value, .limit = max_subjects }; + }, + + [&] (Alloc_rpc_error) { return For_each_subject_info_result { }; }); } + + /** + * Release subject and free buffers + * + * If the source still exists, the buffers are freed but the subject + * stays intact. + */ + void free(Subject_id id) { call(id); } + + /** + * Pause generation of tracing data + */ + void pause(Subject_id id) { call(id); } + + /** + * Resume generation of tracing data + */ + void resume(Subject_id id) { call(id); } + + /** + * Obtain trace buffer of given subject + */ + Dataspace_capability buffer(Subject_id id) { return call(id); } }; #endif /* _INCLUDE__TRACE_SESSION__CONNECTION_H_ */ diff --git a/repos/base/include/trace_session/trace_session.h b/repos/base/include/trace_session/trace_session.h index 3bd61ba442..8b8cd4bddb 100644 --- a/repos/base/include/trace_session/trace_session.h +++ b/repos/base/include/trace_session/trace_session.h @@ -14,7 +14,7 @@ #ifndef _INCLUDE__TRACE_SESSION__TRACE_SESSION_H_ #define _INCLUDE__TRACE_SESSION__TRACE_SESSION_H_ -#include +#include #include #include #include @@ -31,70 +31,17 @@ struct Genode::Trace::Session : Genode::Session enum { CAP_QUOTA = 6 }; - /** - * Allocate policy-module backing store - * - * \throw Out_of_ram - * \throw Out_of_caps - */ - virtual Policy_id alloc_policy(size_t size) = 0; + enum class Alloc_rpc_error { OUT_OF_RAM, OUT_OF_CAPS }; + enum class Alloc_policy_rpc_error { OUT_OF_RAM, OUT_OF_CAPS, INVALID }; + enum class Trace_rpc_error { OUT_OF_RAM, OUT_OF_CAPS, FOREIGN, + SOURCE_IS_DEAD, INVALID_SUBJECT, + INVALID_POLICY }; - /** - * Request policy-module backing store - * - * \throw Nonexistent_policy - */ - virtual Dataspace_capability policy(Policy_id) = 0; + using Alloc_policy_rpc_result = Attempt; + using Subjects_rpc_result = Attempt; + using Infos_rpc_result = Attempt; + using Trace_rpc_result = Attempt; - /** - * Remove a policy module from the TRACE service - */ - virtual void unload_policy(Policy_id) = 0; - - /** - * Start tracing of a subject - * - * \throw Out_of_ram - * \throw Out_of_caps - * \throw Already_traced - * \throw Source_is_dead - * \throw Nonexistent_policy - * \throw Nonexistent_subject - * \throw Traced_by_other_session - */ - virtual void trace(Subject_id, Policy_id, size_t buffer_size) = 0; - - /** - * Pause generation of tracing data - * - * \throw Nonexistent_subject - */ - virtual void pause(Subject_id) = 0; - - /** - * Resume generation of tracing data - * - * \throw Nonexistent_subject - * \throw Source_is_dead - */ - virtual void resume(Subject_id) = 0; - - /** - * Obtain trace buffer of given subject - * - * \throw Nonexistent_subject - */ - virtual Dataspace_capability buffer(Subject_id) = 0; - - /** - * Release subject and free buffers - * - * If the source still exists, the buffers are freed but the subject - * stays intact. - * - * \throw Nonexistent_subject - */ - virtual void free(Subject_id) = 0; virtual ~Session() { } @@ -104,34 +51,16 @@ struct Genode::Trace::Session : Genode::Session *********************/ GENODE_RPC(Rpc_dataspace, Dataspace_capability, dataspace); - GENODE_RPC_THROW(Rpc_alloc_policy, Policy_id, alloc_policy, - GENODE_TYPE_LIST(Out_of_ram, Out_of_caps), - size_t); - GENODE_RPC_THROW(Rpc_policy, Dataspace_capability, policy, - GENODE_TYPE_LIST(Nonexistent_policy), - Policy_id); - GENODE_RPC_THROW(Rpc_unload_policy, void, unload_policy, - GENODE_TYPE_LIST(Nonexistent_policy), Policy_id); - GENODE_RPC_THROW(Rpc_trace, void, trace, - GENODE_TYPE_LIST(Out_of_ram, Out_of_caps, Already_traced, - Source_is_dead, Nonexistent_subject, - Nonexistent_policy, - Traced_by_other_session), - Subject_id, Policy_id, size_t); - GENODE_RPC_THROW(Rpc_pause, void, pause, - GENODE_TYPE_LIST(Nonexistent_subject), Subject_id); - GENODE_RPC_THROW(Rpc_resume, void, resume, - GENODE_TYPE_LIST(Nonexistent_subject, Source_is_dead), - Subject_id); - GENODE_RPC_THROW(Rpc_subjects, size_t, subjects, - GENODE_TYPE_LIST(Out_of_ram, Out_of_caps)); - GENODE_RPC_THROW(Rpc_subject_infos, size_t, subject_infos, - GENODE_TYPE_LIST(Out_of_ram, Out_of_caps)); - GENODE_RPC_THROW(Rpc_buffer, Dataspace_capability, buffer, - GENODE_TYPE_LIST(Nonexistent_subject, Subject_not_traced), - Subject_id); - GENODE_RPC_THROW(Rpc_free, void, free, - GENODE_TYPE_LIST(Nonexistent_subject), Subject_id); + GENODE_RPC(Rpc_alloc_policy, Alloc_policy_rpc_result, alloc_policy, Policy_size); + GENODE_RPC(Rpc_policy, Dataspace_capability, policy, Policy_id); + GENODE_RPC(Rpc_unload_policy, void, unload_policy, Policy_id); + GENODE_RPC(Rpc_trace, Trace_rpc_result, trace, Subject_id, Policy_id, Buffer_size); + GENODE_RPC(Rpc_pause, void, pause, Subject_id); + GENODE_RPC(Rpc_resume, void, resume, Subject_id); + GENODE_RPC(Rpc_subjects, Subjects_rpc_result, subjects); + GENODE_RPC(Rpc_subject_infos, Infos_rpc_result, subject_infos); + GENODE_RPC(Rpc_buffer, Dataspace_capability, buffer, Subject_id); + GENODE_RPC(Rpc_free, void, free, Subject_id); GENODE_RPC_INTERFACE(Rpc_dataspace, Rpc_alloc_policy, Rpc_policy, Rpc_unload_policy, Rpc_trace, Rpc_pause, diff --git a/repos/base/include/util/arg_string.h b/repos/base/include/util/arg_string.h index 907134492e..8c5fbaeaa4 100644 --- a/repos/base/include/util/arg_string.h +++ b/repos/base/include/util/arg_string.h @@ -29,7 +29,6 @@ #include #include -#include namespace Genode { @@ -45,7 +44,7 @@ class Genode::Arg * * Argument-string tokens accept C-style identifiers. */ - typedef ::Genode::Token Token; + using Token = ::Genode::Token; friend class Arg_string; @@ -203,7 +202,7 @@ class Genode::Arg class Genode::Arg_string { - typedef Arg::Token Token; + using Token = Arg::Token; private: @@ -329,10 +328,8 @@ class Genode::Arg_string static bool set_arg(char *args, size_t args_len, const char *key, int value) { - enum { STRING_LONG_MAX = 32 }; - char buf[STRING_LONG_MAX]; - snprintf(buf, sizeof(buf), "%d", value); - return remove_arg(args, key) && add_arg(args, args_len, key, buf); + return remove_arg(args, key) + && add_arg(args, args_len, key, String<16>(value).string()); } /** diff --git a/repos/base/include/util/array.h b/repos/base/include/util/array.h index 3fd1467ead..e9b039c1b6 100644 --- a/repos/base/include/util/array.h +++ b/repos/base/include/util/array.h @@ -99,26 +99,23 @@ class Genode::Array * * \throw Index_out_of_bounds */ - template - void add(T obj, TAIL ... tail) + void add(T obj, auto &&... tail) { add(obj); add(tail...); } - template - void for_each(FUNC const &f) + void for_each(auto const &fn) { for (unsigned idx = 0; idx < _count; idx++) - f(idx, _objs[idx]); + fn(idx, _objs[idx]); } - template - void for_each(FUNC const &f) const + void for_each(auto const &fn) const { for (unsigned idx = 0; idx < _count; idx++) { T const & obj = _objs[idx]; - f(idx, obj); + fn(idx, obj); } } }; diff --git a/repos/base/include/util/attempt.h b/repos/base/include/util/attempt.h index 3d24734b9d..4df518e352 100644 --- a/repos/base/include/util/attempt.h +++ b/repos/base/include/util/attempt.h @@ -52,21 +52,19 @@ class Genode::Attempt Attempt(Attempt const &) = default; Attempt &operator = (Attempt const &) = default; - template - RET convert(ACCESS_FN const &access_fn, FAIL_FN const &fail_fn) const + template + RET convert(auto const &access_fn, auto const &fail_fn) const { return _ok ? RET { access_fn(_result) } : RET { fail_fn(_error) }; } - template - void with_result(ACCESS_FN const &access_fn, FAIL_FN const &fail_fn) const + void with_result(auto const &access_fn, auto const &fail_fn) const { _ok ? access_fn(_result) : fail_fn(_error); } - template - void with_error(FAIL_FN const &fail_fn) const + void with_error(auto const &fail_fn) const { if (!_ok) fail_fn(_error); diff --git a/repos/base/include/util/avl_string.h b/repos/base/include/util/avl_string.h deleted file mode 100644 index bcb8559b25..0000000000 --- a/repos/base/include/util/avl_string.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * \brief Utility for handling strings as AVL-node keys - * \author Norman Feske - * \date 2006-07-12 - */ - -/* - * Copyright (C) 2006-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _INCLUDE__UTIL__AVL_STRING_H_ -#define _INCLUDE__UTIL__AVL_STRING_H_ - -#include -#include - -namespace Genode { - - class Avl_string_base; - template class Avl_string; -} - - -class Genode::Avl_string_base : public Avl_node -{ - private: - - struct { const char *_str; }; - - protected: - - /** - * Constructor - * - * \noapi - */ - Avl_string_base(const char *str) : _str(str) { } - - public: - - const char *name() const { return _str; } - - - /************************ - ** Avl node interface ** - ************************/ - - bool higher(Avl_string_base *c) { return (strcmp(c->_str, _str) > 0); } - - /** - * Find by name - */ - Avl_string_base *find_by_name(const char *name) - { - if (strcmp(name, _str) == 0) return this; - - Avl_string_base *c = Avl_node::child(strcmp(name, _str) > 0); - return c ? c->find_by_name(name) : 0; - } -}; - - -/* - * The template pumps up the Avl_string_base object and provides the buffer for - * the actual string. - */ -template -class Genode::Avl_string : public Avl_string_base -{ - private: - - char _str_buf[STR_LEN]; - - public: - - Avl_string(const char *str) : Avl_string_base(_str_buf) - { - copy_cstring(_str_buf, str, sizeof(_str_buf)); - } -}; - -#endif /* _INCLUDE__UTIL__AVL_STRING_H_ */ diff --git a/repos/base/include/util/avl_tree.h b/repos/base/include/util/avl_tree.h index f128219ce3..5edf688b6b 100644 --- a/repos/base/include/util/avl_tree.h +++ b/repos/base/include/util/avl_tree.h @@ -67,7 +67,7 @@ class Genode::Avl_node_base : Noncopyable public: - typedef bool Side; + using Side = bool; enum { LEFT = false, RIGHT = true }; @@ -168,14 +168,13 @@ struct Genode::Avl_node : Avl_node_base /** * Apply a functor (read-only) to every node within this subtree * - * \param functor function that takes a const NT reference + * \param fn function that takes a const NT reference */ - template - void for_each(FUNC && functor) const + void for_each(auto const &fn) const { - if (NT * l = child(Avl_node::LEFT)) l->for_each(functor); - functor(*static_cast(this)); - if (NT * r = child(Avl_node::RIGHT)) r->for_each(functor); + if (NT * l = child(Avl_node::LEFT)) l->for_each(fn); + fn(*static_cast(this)); + if (NT * r = child(Avl_node::RIGHT)) r->for_each(fn); } }; @@ -229,13 +228,12 @@ class Genode::Avl_tree : Avl_node /** * Apply a functor (read-only) to every node within the tree * - * \param functor function that takes a const NT reference + * \param fn function that takes a const NT reference * * The iteration order corresponds to the order of the keys */ - template - void for_each(FUNC && functor) const { - if (first()) first()->for_each(functor); } + void for_each(auto const &fn) const { + if (first()) first()->for_each(fn); } }; #endif /* _INCLUDE__UTIL__AVL_TREE_H_ */ diff --git a/repos/base/include/util/bit_allocator.h b/repos/base/include/util/bit_allocator.h index bcd74920aa..050b5d490b 100644 --- a/repos/base/include/util/bit_allocator.h +++ b/repos/base/include/util/bit_allocator.h @@ -17,7 +17,7 @@ #include -namespace Genode { template class Bit_allocator; } +namespace Genode { template class Bit_allocator; } template diff --git a/repos/base/include/util/dictionary.h b/repos/base/include/util/dictionary.h index c393b0776c..4f920b29a4 100644 --- a/repos/base/include/util/dictionary.h +++ b/repos/base/include/util/dictionary.h @@ -44,7 +44,7 @@ class Genode::Dictionary : Noncopyable Dictionary &_dictionary; - bool higher(T const *other) const { return name > other->This::name; } + bool higher(T const *other) const { return other->This::name > name; } friend class Avl_tree; friend class Avl_node; @@ -52,7 +52,7 @@ class Genode::Dictionary : Noncopyable static T *_matching_sub_tree(T &curr, NAME const &name) { - typename Avl_node::Side side = (curr.This::name > name); + typename Avl_node::Side side = (name > curr.This::name); return curr.Avl_node::child(side); } @@ -81,9 +81,9 @@ class Genode::Dictionary : Noncopyable * matching dictionary element. If no maching element exists, * 'no_match_fn' is called without argument. */ - template - auto with_element(NAME const &name, FN1 const &match_fn, FN2 const &no_match_fn) - -> typename Trait::Functor::Return_type + template + auto with_element(NAME const &name, FN const &match_fn, auto const &no_match_fn) + -> typename Trait::Functor::Return_type { T *curr_ptr = _tree.first(); for (;;) { @@ -106,9 +106,9 @@ class Genode::Dictionary : Noncopyable * matching dictionary element. If no maching element exists, * 'no_match_fn' is called without argument. */ - template - auto with_element(NAME const &name, FN1 const &match_fn, FN2 const &no_match_fn) const - -> typename Trait::Functor::Return_type + template + auto with_element(NAME const &name, FN const &match_fn, auto const &no_match_fn) const + -> typename Trait::Functor::Return_type { auto const_match_fn = [&] (T const &e) { return match_fn(e); }; auto non_const_this = const_cast(this); @@ -124,8 +124,7 @@ class Genode::Dictionary : Noncopyable * This method is intended for the orderly destruction of a dictionary. * It allows for the consecutive destruction of all elements. */ - template - bool with_any_element(FUNC const &fn) + bool with_any_element(auto const &fn) { T *curr_ptr = _tree.first(); if (!curr_ptr) @@ -135,8 +134,7 @@ class Genode::Dictionary : Noncopyable return true; } - template - void for_each(FN const &fn) const { _tree.for_each(fn); } + void for_each(auto const &fn) const { _tree.for_each(fn); } bool exists(NAME const &name) const { diff --git a/repos/base/include/util/fifo.h b/repos/base/include/util/fifo.h index 83db99d1c1..e839dc30a1 100644 --- a/repos/base/include/util/fifo.h +++ b/repos/base/include/util/fifo.h @@ -75,10 +75,9 @@ class Genode::Fifo Fifo() { } /** - * Call 'func' of type 'void (QT&)' the head element + * Call 'fn' of type 'void (QT&)' the head element */ - template - void head(FUNC const &func) const { if (_head) func(*_head); } + void head(auto const &fn) const { if (_head) fn(*_head); } /** * Remove element explicitly from queue @@ -130,25 +129,23 @@ class Genode::Fifo } /** - * Call 'func' of type 'void (QT&)' for each element in order + * Call 'fn' of type 'void (QT&)' for each element in order */ - template - void for_each(FUNC const &func) const + void for_each(auto const &fn) const { QT *elem = _head; while (elem != nullptr) { - /* take the next pointer so 'func' cannot modify it */ + /* take the next pointer so 'fn' cannot modify it */ QT *next = elem->Fifo::Element::_next;; - func(*elem); + fn(*elem); elem = next; } } /** - * Remove head and call 'func' of type 'void (QT&)' + * Remove head and call 'fn' of type 'void (QT&)' */ - template - void dequeue(FUNC const &func) + void dequeue(auto const &fn) { QT *result = _head; @@ -165,7 +162,7 @@ class Genode::Fifo result->Fifo::Element::_enqueued = false; /* pass to caller */ - func(*result); + fn(*result); } } @@ -173,13 +170,12 @@ class Genode::Fifo * Remove all fifo elements * * This method removes all elements in order and calls the lambda - * 'func' of type 'void (QT&)' for each element. It is intended to be + * 'fn' of type 'void (QT&)' for each element. It is intended to be * used prior the destruction of the FIFO. */ - template - void dequeue_all(FUNC const &func) + void dequeue_all(auto const &fn) { - while (_head != nullptr) dequeue(func); + while (_head != nullptr) dequeue(fn); } }; diff --git a/repos/base/include/util/geometry.h b/repos/base/include/util/geometry.h new file mode 100644 index 0000000000..0266ef6be9 --- /dev/null +++ b/repos/base/include/util/geometry.h @@ -0,0 +1,253 @@ +/* + * \brief Geometric primitives + * \author Norman Feske + * \date 2006-08-05 + */ + +/* + * Copyright (C) 2006-2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _INCLUDE__UTIL__GEOMETRY_H_ +#define _INCLUDE__UTIL__GEOMETRY_H_ + +#include +#include +#include +#include + +namespace Genode { + template class Point; + template class Area; + template class Rect; +} + + +/** + * \param CT coordinate type + */ +template +struct Genode::Point +{ + CT x {}, y {}; + + /** + * Operator for adding points + */ + Point operator + (Point const &p) const { return Point(x + p.x, y + p.y); } + + /** + * Operator for subtracting points + */ + Point operator - (Point const &p) const { return Point(x - p.x, y - p.y); } + + /** + * Operator for testing non-equality of two points + */ + bool operator != (Point const &p) const { return p.x != x || p.y != y; } + + /** + * Operator for testing equality of two points + */ + bool operator == (Point const &p) const { return p.x == x && p.y == y; } + + void print(Output &out) const + { + auto abs = [] (auto v) { return v >= 0 ? v : -v; }; + + Genode::print(out, x >= 0 ? "+" : "-", abs(x), + y >= 0 ? "+" : "-", abs(y)); + } + + /** + * Construct point from XML node attributes + * + * The XML node is expected to feature the attributes 'xpos' and 'ypos'. + */ + static Point from_xml(Xml_node const &node) + { + return Point(node.attribute_value("xpos", CT{}), + node.attribute_value("ypos", CT{})); + } +}; + + +/** + * \param DT distance type + */ +template +struct Genode::Area +{ + DT w {}, h {}; + + bool valid() const { return w > 0 && h > 0; } + + size_t count() const { return size_t(w)*size_t(h); } + + /** + * Operator for testing non-equality of two areas + */ + bool operator != (Area const &a) const { return a.w != w || a.h != h; } + + /** + * Operator for testing equality of two areas + */ + bool operator == (Area const &a) const { return a.w == w && a.h == h; } + + void print(Output &out) const { Genode::print(out, w, "x", h); } + + /** + * Construct area from XML node attributes + * + * The XML node is expected to feature the attributes 'width' and + * 'height'. + */ + static Area from_xml(Xml_node const &node) + { + return Area(node.attribute_value("width", DT{}), + node.attribute_value("height", DT{})); + } +}; + + +/** + * Rectangle + * + * A valid rectangle consists of two points wheras point 2 has higher or equal + * coordinates than point 1. All other cases are threated as invalid + * rectangles. + * + * \param CT coordinate type + * \param DT distance type + */ +template +struct Genode::Rect +{ + using Point = Genode::Point; + using Area = Genode::Area
; + + Point at {}; + Area area {}; + + /** + * Construct rectangle from two given points + * + * The x and y coordinates of p1 must not be higher than those of p2. + */ + static constexpr Rect compound(Point const p1, Point const p2) + { + if (p1.x > p2.x || p1.y > p2.y) return { /* invalid */ }; + + return { .at = p1, + .area = { .w = DT(p2.x - p1.x + 1), + .h = DT(p2.y - p1.y + 1) } }; + } + + /** + * Construct compounding rectangle of two rectangles + */ + static constexpr Rect compound(Rect r1, Rect r2) + { + return compound(Point(min(r1.x1(), r2.x1()), min(r1.y1(), r2.y1())), + Point(max(r1.x2(), r2.x2()), max(r1.y2(), r2.y2()))); + } + + /** + * Construct rectangle by intersecting two rectangles + */ + static constexpr Rect intersect(Rect const r1, Rect const r2) + { + return Rect::compound(Point(max(r1.x1(), r2.x1()), max(r1.y1(), r2.y1())), + Point(min(r1.x2(), r2.x2()), min(r1.y2(), r2.y2()))); + } + + CT x1() const { return at.x; } + CT y1() const { return at.y; } + CT x2() const { return at.x + area.w - 1; } + CT y2() const { return at.y + area.h - 1; } + DT w() const { return area.w; } + DT h() const { return area.h; } + Point p1() const { return at; } + Point p2() const { return { x2(), y2() }; } + + /** + * Return true if rectangle area is greater than zero + */ + bool valid() const { return area.valid(); } + + /** + * Return true if area fits in rectangle + */ + bool fits(Area const area) const { return w() >= area.w && h() >= area.h; } + + /** + * Return true if the specified point lies within the rectangle + */ + bool contains(Point const p) const + { + return p.x >= x1() && p.x <= x2() && p.y >= y1() && p.y <= y2(); + } + + struct Cut_remainder + { + Rect top, left, right, bottom; + + void for_each(auto const &fn) const { fn(top); fn(left); fn(right); fn(bottom); } + }; + + /** + * Cut out rectangle from rectangle + * + * \param r rectangle to cut out + * + * In the worst case (if we cut a hole into the rectangle) we get + * four valid resulting rectangles. + */ + Cut_remainder cut(Rect r) const + { + /* limit the cut-out area to the actual rectangle */ + r = intersect(r, *this); + + return { + .top = compound(Point(x1(), y1()), Point(x2(), r.y1() - 1)), + .left = compound(Point(x1(), r.y1()), Point(r.x1() - 1, r.y2())), + .right = compound(Point(r.x2() + 1, r.y1()), Point(x2(), r.y2())), + .bottom = compound(Point(x1(), r.y2() + 1), Point(x2(), y2())) + }; + } + + /** + * Return position of an area when centered within the rectangle + */ + Point center(Area const area) const + { + return Point((CT(w()) - CT(area.w))/2, + (CT(h()) - CT(area.h))/2) + at; + } + + /** + * Print rectangle coordinates + * + * The output has the form 'width' x 'height' +/- 'p1.x' +/- 'p1.y'. + * For example, a rectange of size 15x16 as position (-13, 14) is + * printed as "15x16-13+14". + */ + void print(Output &out) const { Genode::print(out, area, at); } + + /** + * Construct rectangle from XML node attributes + * + * The XML node is expected to feature the attributes 'xpos', 'ypos'. + * 'width', and 'height'. If an attribute is absent, the corresponding + * value is set to 0. + */ + static Rect from_xml(Xml_node const &node) + { + return Rect(Point::from_xml(node), Area::from_xml(node)); + } +}; + +#endif /* _INCLUDE__UTIL__GEOMETRY_H_ */ diff --git a/repos/base/include/util/list_model.h b/repos/base/include/util/list_model.h index 5334f60228..a3598d297e 100644 --- a/repos/base/include/util/list_model.h +++ b/repos/base/include/util/list_model.h @@ -4,13 +4,51 @@ * \date 2017-08-09 * * The 'List_model' stores a component-internal representation of XML-node - * content. The XML information is imported according to an 'Update_policy', - * which specifies how the elements of the data model are created, destroyed, - * and updated. The elements are ordered according to the order of XML nodes. + * content. The internal representation 'ELEM' carries two methods 'matches' + * and 'type_matches' that define the relation of the elements to XML nodes. + * E.g., + * + * ! struct Item : List_model::Element + * ! { + * ! static bool type_matches(Xml_node const &); + * ! + * ! bool matches(Xml_node const &) const; + * ! ... + * ! }; + * + * The class function 'type_matches' returns true if the specified XML node + * matches the 'Item' type. It can thereby be used to control the creation + * of 'ELEM' nodes by responding to specific XML tags while ignoring unrelated + * XML tags. + * + * The 'matches' method returns true if the concrete element instance matches + * the given XML node. It is used to correlate existing 'ELEM' objects with + * new versions of XML nodes to update the 'ELEM' objects. + * + * The functor arguments 'create_fn', 'destroy_fn', and 'update_fn' for the + * 'update_from_xml' method define how objects are created, destructed, and + * updated. E.g., + * + * ! _list_model.update_from_xml(node, + * ! + * ! [&] (Xml_node const &node) -> Item & { + * ! return *new (alloc) Item(node); }, + * ! + * ! [&] (Item &item) { destroy(alloc, &item); }, + * ! + * ! [&] (Item &item, Xml_node const &node) { item.update(node); } + * ! ); + * + * The elements are ordered according to the order of XML nodes. + * + * The list model is a container owning the elements. Before destructing a + * list model, its elements must be removed by calling 'update_from_xml' + * with an 'Xml_node("")' as argument, which results in the call + * of 'destroy_fn' for each element. */ /* - * Copyright (C) 2017 Genode Labs GmbH + * Copyright (C) 2017-2023 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -20,26 +58,16 @@ #define _INCLUDE__UTIL__LIST_MODEL_H_ /* Genode includes */ +#include #include #include #include -namespace Genode { - - template class List_model; - - template - static inline void update_list_model_from_xml(List_model &, - Xml_node const &, - CREATE_FN const &, - DESTROY_FN const &, - UPDATE_FN const &); -} +namespace Genode { template class List_model; } template -class Genode::List_model +class Genode::List_model : Noncopyable { private: @@ -59,8 +87,16 @@ class Genode::List_model ELEM *_next() const { return List::Element::next(); } + /** + * Noncopyable + */ + Element(Element const &) = delete; + Element & operator = (Element const &) = delete; + public: + Element() { }; + /** * Return the element's neighbor if present, otherwise nullptr */ @@ -76,18 +112,17 @@ class Genode::List_model } /** - * Update data model according to XML structure 'node' - * - * \throw Unknown_element_type + * Update data model according to the given XML node */ - template - inline void update_from_xml(POLICY &policy, Xml_node node); + inline void update_from_xml(Xml_node const &, + auto const &create_fn, + auto const &destroy_fn, + auto const &update_fn); /** * Call functor 'fn' for each const element */ - template - void for_each(FN const &fn) const + void for_each(auto const &fn) const { for (Element const *e = _elements.first(); e; e = e->next()) fn(static_cast(*e)); @@ -96,8 +131,7 @@ class Genode::List_model /** * Call functor 'fn' for each non-const element */ - template - void for_each(FN const &fn) + void for_each(auto const &fn) { Element *next = nullptr; for (Element *e = _elements.first(); e; e = next) { @@ -107,195 +141,74 @@ class Genode::List_model } /** - * Apply functor 'fn' to the first element of the list model + * Call functor 'fn' with the first element of the list model * - * Using this method combined with the 'Element::next' method, the list - * model can be traversed manually. This is handy in situations where - * the list-model elements are visited via recursive function calls + * Using this method combined with 'Element::next', the list model + * can be traversed manually. This is handy in situations where the + * list-model elements are visited via recursive function calls * instead of a 'for_each' loop. */ - template - void apply_first(FN const &fn) const + void with_first(auto const &fn) const { if (Element const *e = _elements.first()) fn(static_cast(*e)); } - - /** - * Remove all elements from the data model - * - * This method should be called at the destruction time of the - * 'List_model'. - * - * List-model elements are not implicitly destroyed by the destructor - * because the 'policy' needed to destruct elements is not kept as - * member of the list model (multiple policies may applied to the same - * list model). - */ - template - void destroy_all_elements(POLICY &policy) - { - Element *next = nullptr; - for (Element *e = _elements.first(); e; e = next) { - next = e->_next(); - ELEM &elem = static_cast(*e); - _elements.remove(&elem); - policy.destroy_element(elem); - } - } }; template -template -void Genode::List_model::update_from_xml(POLICY &policy, Xml_node node) +void Genode::List_model::update_from_xml(Xml_node const &node, + auto const &create_fn, + auto const &destroy_fn, + auto const &update_fn) { - typedef typename POLICY::Element Element; + List updated_list; - List updated_list; - - Element *last_updated = nullptr; /* used for appending to 'updated_list' */ + ELEM *last_updated = nullptr; /* used for appending to 'updated_list' */ node.for_each_sub_node([&] (Xml_node sub_node) { /* skip XML nodes that are unrelated to the data model */ - if (!policy.node_is_element(sub_node)) + if (!ELEM::type_matches(sub_node)) return; /* check for duplicates, which must not exist in the list model */ - for (Element *dup = updated_list.first(); dup; dup = dup->_next()) { + for (ELEM *dup = updated_list.first(); dup; dup = dup->_next()) { /* update existing element with information from later node */ - if (policy.element_matches_xml_node(*dup, sub_node)) { - policy.update_element(*dup, sub_node); + if (dup->matches(sub_node)) { + update_fn(*dup, sub_node); return; } } /* look up corresponding element in original list */ - Element *curr = _elements.first(); - while (curr && !policy.element_matches_xml_node(*curr, sub_node)) + ELEM *curr = _elements.first(); + while (curr && !curr->matches(sub_node)) curr = curr->_next(); /* consume existing element or create new one */ - if (curr) { + if (curr) _elements.remove(curr); - } else { - /* \throw Unknown_element_type */ - curr = &policy.create_element(sub_node); - } + else + curr = &create_fn(sub_node); /* append current element to 'updated_list' */ updated_list.insert(curr, last_updated); last_updated = curr; - policy.update_element(*curr, sub_node); + update_fn(*curr, sub_node); }); /* remove stale elements */ - Element *next = nullptr; - for (Element *e = _elements.first(); e; e = next) { + ELEM *next = nullptr; + for (ELEM *e = _elements.first(); e; e = next) { next = e->_next(); - policy.destroy_element(*e); + destroy_fn(*e); } /* use 'updated_list' list new data model */ _elements = updated_list; } - -/** - * Policy interface to be supplied to 'List_model::update_from_xml' - * - * \param ELEM element type, must be a list element - * - * This class template is merely a blue print of a policy to document the - * interface. - */ -template -struct Genode::List_model::Update_policy -{ - typedef List_model::Unknown_element_type Unknown_element_type; - - /* - * Type that needs to be supplied by the policy implementation - */ - typedef ELEM Element; - - /** - * Destroy element - * - * When this function is called, the element is no longer contained - * in the model's list. - */ - void destroy_element(ELEM &elem); - - /** - * Create element of the type given in the 'elem_node' - * - * \throw List_model::Unknown_element_type - */ - ELEM &create_element(Xml_node elem_node); - - /** - * Import element properties from XML node - */ - void update_element(ELEM &elem, Xml_node elem_node); - - /** - * Return true if element corresponds to XML node - */ - static bool element_matches_xml_node(Element const &, Xml_node); - - /** - * Return true if XML node should be imported - * - * This method allows the policy to disregard certain XML node types from - * building the data model. - */ - static bool node_is_element(Xml_node) { return true; } -}; - - -template -void Genode::update_list_model_from_xml(List_model &model, - Xml_node const &xml, - CREATE_FN const &create, - DESTROY_FN const &destroy, - UPDATE_FN const &update) -{ - struct Model_update_policy : List_model::Update_policy - { - CREATE_FN const &_create_fn; - DESTROY_FN const &_destroy_fn; - UPDATE_FN const &_update_fn; - - Model_update_policy(CREATE_FN const &create_fn, - DESTROY_FN const &destroy_fn, - UPDATE_FN const &update_fn) - : - _create_fn(create_fn), _destroy_fn(destroy_fn), _update_fn(update_fn) - { } - - void destroy_element(NODE &node) { _destroy_fn(node); } - - NODE &create_element(Xml_node xml) { return _create_fn(xml); } - - void update_element(NODE &node, Xml_node xml) { _update_fn(node, xml); } - - static bool element_matches_xml_node(NODE const &node, Xml_node xml) - { - return node.matches(xml); - } - - static bool node_is_element(Xml_node node) - { - return NODE::type_matches(node); - } - - } policy(create, destroy, update); - - model.update_from_xml(policy, xml); -} - #endif /* _INCLUDE__UTIL__LIST_MODEL_H_ */ diff --git a/repos/base/include/util/meta.h b/repos/base/include/util/meta.h index 7faee55786..5faebaa1c5 100644 --- a/repos/base/include/util/meta.h +++ b/repos/base/include/util/meta.h @@ -22,22 +22,22 @@ namespace Genode { ** Reference and non-reference types ** ***************************************/ - template struct Reference { typedef T& Type; }; - template struct Reference { typedef T* Type; }; - template struct Reference { typedef T& Type; }; + template struct Reference { using Type = T&; }; + template struct Reference { using Type = T*; }; + template struct Reference { using Type = T&; }; - template struct Non_reference { typedef T Type; }; - template struct Non_reference { typedef T Type; }; - template struct Non_reference { typedef T Type; }; + template struct Non_reference { using Type = T; }; + template struct Non_reference { using Type = T; }; + template struct Non_reference { using Type = T; }; - template struct Non_const { typedef T Type; }; - template struct Non_const { typedef T Type; }; + template struct Non_const { using Type = T; }; + template struct Non_const { using Type = T; }; /** * Determine plain-old-data type corresponding to type 'T' */ template struct Pod { - typedef typename Non_const::Type>::Type Type; }; + using Type = typename Non_const::Type>::Type; }; } /* namespace Trait */ @@ -80,8 +80,8 @@ namespace Genode { template struct Type_tuple { - typedef HEAD Head; - typedef TAIL Tail; + using Head = HEAD; + using Tail = TAIL; }; /** @@ -91,7 +91,7 @@ namespace Genode { struct Type_list; template <> - struct Type_list<> { typedef Empty Head; }; + struct Type_list<> { using Head = Empty; }; template struct Type_list : Type_tuple { }; @@ -136,18 +136,18 @@ namespace Genode { class Append { /* pass appendix towards the end of the typelist */ - typedef typename Append::Type _Tail; + using _Tail = typename Append::Type; public: /* keep head, replace tail */ - typedef Type_tuple Type; + using Type = Type_tuple; }; /* replace end of type list ('Empty' type) with appendix */ template - struct Append { typedef APPENDIX Type; }; + struct Append { using Type = APPENDIX; }; /** @@ -155,17 +155,17 @@ namespace Genode { */ template struct Type_at { - typedef typename Type_at::Type Type; }; + using Type = typename Type_at::Type; }; /* end recursion if we reached the type */ template - struct Type_at { typedef typename TL::Head Type; }; + struct Type_at { using Type = typename TL::Head; }; /* end recursion at the end of type list */ - template struct Type_at { typedef void Type; }; + template struct Type_at { using Type = void; }; /* resolve ambiguous specializations */ - template <> struct Type_at { typedef void Type; }; + template <> struct Type_at { using Type = void; }; /** @@ -300,12 +300,12 @@ namespace Genode { template struct Pod_tuple { - typedef typename Trait::Pod::Type Stored_head; + using Stored_head = typename Trait::Pod::Type; Stored_head _1; TAIL _2; - typedef HEAD Head; - typedef TAIL Tail; + using Head = HEAD; + using Tail = TAIL; /** * Accessor for requesting the data reference to '_1' @@ -324,12 +324,12 @@ namespace Genode { template struct Pod_tuple { - typedef typename Trait::Non_reference::Type Stored_head; + using Stored_head = typename Trait::Non_reference::Type; Stored_head _1; TAIL _2; - typedef HEAD* Head; - typedef TAIL Tail; + using Head = HEAD*; + using Tail = TAIL; HEAD *get() { return &_1; } }; @@ -355,35 +355,35 @@ namespace Genode { template <> struct Ref_args { - typedef Empty Type; }; + using Type = Empty; }; template struct Ref_args { - typedef Ref_tuple Type; }; + using Type = Ref_tuple; }; template struct Ref_args { - typedef Ref_tuple_3 Type; }; + using Type = Ref_tuple_3; }; template struct Ref_args { - typedef Ref_tuple_4 Type; }; + using Type = Ref_tuple_4; }; template struct Ref_args { - typedef Ref_tuple_5 Type; }; + using Type = Ref_tuple_5; }; template struct Ref_args { - typedef Ref_tuple_6 Type; }; + using Type = Ref_tuple_6; }; template struct Ref_args { - typedef Ref_tuple_7 Type; }; + using Type = Ref_tuple_7; }; template struct Ref_args { - typedef Ref_tuple_8 Type; }; + using Type = Ref_tuple_8; }; /** @@ -398,28 +398,28 @@ namespace Genode { struct Pod_args; template <> - struct Pod_args { typedef Empty Type; }; + struct Pod_args { using Type = Empty; }; template - struct Pod_args { typedef Pod_tuple Type; }; + struct Pod_args { using Type = Pod_tuple; }; template - struct Pod_args { typedef Pod_tuple::Type> Type; }; + struct Pod_args { using Type = Pod_tuple::Type>; }; template - struct Pod_args { typedef Pod_tuple::Type> Type; }; + struct Pod_args { using Type = Pod_tuple::Type>; }; template - struct Pod_args { typedef Pod_tuple::Type> Type; }; + struct Pod_args { using Type = Pod_tuple::Type>; }; template - struct Pod_args { typedef Pod_tuple::Type> Type; }; + struct Pod_args { using Type = Pod_tuple::Type>; }; template - struct Pod_args { typedef Pod_tuple::Type> Type; }; + struct Pod_args { using Type = Pod_tuple::Type>; }; template - struct Pod_args { typedef Pod_tuple::Type> Type; }; + struct Pod_args { using Type = Pod_tuple::Type>; }; /** @@ -619,8 +619,8 @@ namespace Genode { * Make class unique for different template arguments. The types * are never used. */ - typedef T1 _T1; - typedef T2 _T2; + using _T1 = T1; + using _T2 = T2; /* prevent zero initialization of objects */ Overload_selector() { } diff --git a/repos/base/include/util/misc_math.h b/repos/base/include/util/misc_math.h index 3f9162b778..31d079d7f2 100644 --- a/repos/base/include/util/misc_math.h +++ b/repos/base/include/util/misc_math.h @@ -22,9 +22,6 @@ namespace Genode { template static constexpr T1 min(T1 v1, T2 v2) { return v1 < v2 ? v1 : v2; } - template - static constexpr T abs(T value) { return value >= 0 ? value : -value; } - /* * Alignment to the power of two diff --git a/repos/base/include/util/mmio.h b/repos/base/include/util/mmio.h index 58301b6aa9..1da6e2ddc7 100644 --- a/repos/base/include/util/mmio.h +++ b/repos/base/include/util/mmio.h @@ -15,12 +15,14 @@ #define _INCLUDE__UTIL__MMIO_H_ /* Genode includes */ +#include +#include #include namespace Genode { class Mmio_plain_access; - class Mmio; + template class Mmio; } /** @@ -32,27 +34,24 @@ class Genode::Mmio_plain_access private: - addr_t const _base; + Byte_range_ptr const _range; /** - * Write '_ACCESS_T' typed 'value' to MMIO base + 'offset' + * Write 'ACCESS_T' typed 'value' to MMIO base + 'offset' */ template inline void _write(off_t const offset, ACCESS_T const value) { - addr_t const dst = _base + offset; - *(ACCESS_T volatile *)dst = value; + *(ACCESS_T volatile *)(_range.start + offset) = value; } /** - * Read '_ACCESS_T' typed from MMIO base + 'offset' + * Read 'ACCESS_T' typed from MMIO base + 'offset' */ template inline ACCESS_T _read(off_t const &offset) const { - addr_t const dst = _base + offset; - ACCESS_T const value = *(ACCESS_T volatile *)dst; - return value; + return *(ACCESS_T volatile *)(_range.start + offset); } public: @@ -62,9 +61,16 @@ class Genode::Mmio_plain_access * * \param base base address of targeted MMIO region */ - Mmio_plain_access(addr_t const base) : _base(base) { } + Mmio_plain_access(Byte_range_ptr const &range) : _range(range.start, range.num_bytes) { } - addr_t base() const { return _base; } + Byte_range_ptr range_at(off_t offset) const + { + return {_range.start + offset, _range.num_bytes - offset}; + } + + Byte_range_ptr range() const { return range_at(0); } + + addr_t base() const { return (addr_t)range().start; } }; @@ -73,17 +79,28 @@ class Genode::Mmio_plain_access * * For further details refer to the documentation of the 'Register_set' class. */ -struct Genode::Mmio : Mmio_plain_access, Register_set +template +struct Genode::Mmio : Mmio_plain_access, Register_set { + static constexpr size_t SIZE = MMIO_SIZE; + + class Range_violation : Exception { }; + /** * Constructor * - * \param base base address of targeted MMIO region + * \param range byte range of targeted MMIO region */ - Mmio(addr_t const base) + Mmio(Byte_range_ptr const &range) : - Mmio_plain_access(base), - Register_set(*static_cast(this)) { } + Mmio_plain_access(range), + Register_set(*static_cast(this)) + { + if (range.num_bytes < SIZE) { + error("MMIO range is unexpectedly too small"); + throw Range_violation { }; + } + } }; #endif /* _INCLUDE__UTIL__MMIO_H_ */ diff --git a/repos/base/include/util/print_lines.h b/repos/base/include/util/print_lines.h index d88b441aeb..4d79ac8bdd 100644 --- a/repos/base/include/util/print_lines.h +++ b/repos/base/include/util/print_lines.h @@ -18,8 +18,8 @@ namespace Genode { - template - static inline void print_lines(char const *, size_t, FUNC const &); + template + static inline void print_lines(char const *, size_t, auto const &); } @@ -30,7 +30,7 @@ namespace Genode { * on the stack * \param string character buffer, not necessarily null-terminated * \param len number of characters to print - * \param func functor called for each line with 'char const *' as + * \param fn functor called for each line with 'char const *' as * argument * * In situations where a string is supplied by an untrusted client, we cannot @@ -42,8 +42,8 @@ namespace Genode { * The output stops when reaching the end of the buffer or when a null * character is encountered. */ -template -void Genode::print_lines(char const *string, size_t len, FUNC const &func) +template +void Genode::print_lines(char const *string, size_t len, auto const &fn) { /* skip leading line breaks */ for (; *string == '\n'; string++); @@ -67,17 +67,16 @@ void Genode::print_lines(char const *string, size_t len, FUNC const &func) string += num_indent_chars; size_t line_len = 0; - size_t skip_char = 1; + size_t skip_char = 0; for (; line_len < len; line_len++) { if (string[line_len] == '\0' || string[line_len] == '\n') { line_len++; + skip_char = 1; break; } - if (line_len == MAX_LINE_LEN) { - skip_char = 0; + if (line_len == MAX_LINE_LEN) break; - } } if (!line_len) @@ -90,7 +89,7 @@ void Genode::print_lines(char const *string, size_t len, FUNC const &func) copy_cstring(line_buf, string, line_len - skip_char + 1); /* process null-terminated string in buffer */ - func(line_buf); + fn(line_buf); /* move forward to the next sub-string to process */ string += line_len; diff --git a/repos/base/include/util/reconstructible.h b/repos/base/include/util/reconstructible.h index efb02ba3f3..32edea772a 100644 --- a/repos/base/include/util/reconstructible.h +++ b/repos/base/include/util/reconstructible.h @@ -52,7 +52,7 @@ Genode::Reconstructible : Noncopyable */ bool _constructed = false; - template void _do_construct(ARGS &&... args) + void _do_construct(auto &&... args) { construct_at(_space, args...); _constructed = true; @@ -91,11 +91,7 @@ Genode::Reconstructible : Noncopyable * The arguments are forwarded to the constructor of the embedded * object. */ - template - Reconstructible(ARGS &&... args) - { - _do_construct(args...); - } + Reconstructible(auto &&... args) { _do_construct(args...); } ~Reconstructible() { destruct(); } @@ -105,8 +101,7 @@ Genode::Reconstructible : Noncopyable * If the 'Reconstructible' already hosts a constructed object, the old * object will be destructed first. */ - template - void construct(ARGS &&... args) + void construct(auto &&... args) { destruct(); _do_construct(args...); @@ -134,8 +129,7 @@ Genode::Reconstructible : Noncopyable /** * Construct or destruct volatile object according to 'condition' */ - template - void conditional(bool condition, ARGS &&... args) + void conditional(bool condition, auto &&... args) { if (condition && !constructed()) construct(args...); diff --git a/repos/base/include/util/register.h b/repos/base/include/util/register.h index b528e2243f..932009822a 100644 --- a/repos/base/include/util/register.h +++ b/repos/base/include/util/register.h @@ -33,8 +33,7 @@ namespace Genode { namespace Trait { template struct Raise_to_uint_width { - enum { WIDTH = _WIDTH < 2 ? 1 : - _WIDTH < 9 ? 8 : + enum { WIDTH = _WIDTH < 9 ? 8 : _WIDTH < 17 ? 16 : _WIDTH < 33 ? 32 : _WIDTH < 65 ? 64 : 0, }; @@ -45,10 +44,10 @@ namespace Genode { namespace Trait { */ template struct Uint_width; - template <> struct Uint_width<1> + template <> struct Uint_width<8> { - typedef bool Type; - enum { WIDTH_LOG2 = 0 }; + using Type = uint8_t; + enum { WIDTH_LOG2 = 3 }; /** * Access widths wich are dividers to the compound type width @@ -56,31 +55,25 @@ namespace Genode { namespace Trait { template struct Divisor; }; - template <> struct Uint_width<8> : Uint_width<1> - { - typedef uint8_t Type; - enum { WIDTH_LOG2 = 3 }; - }; - template <> struct Uint_width<16> : Uint_width<8> { - typedef uint16_t Type; + using Type = uint16_t; enum { WIDTH_LOG2 = 4 }; }; template <> struct Uint_width<32> : Uint_width<16> { - typedef uint32_t Type; + using Type = uint32_t; enum { WIDTH_LOG2 = 5 }; }; template <> struct Uint_width<64> : Uint_width<32> { - typedef uint64_t Type; + using Type = uint64_t; enum { WIDTH_LOG2 = 6 }; }; - template <> struct Uint_width<1>::Divisor<1> { enum { WIDTH_LOG2 = 0 }; }; + template <> struct Uint_width<8>::Divisor<1> { enum { WIDTH_LOG2 = 0 }; }; template <> struct Uint_width<8>::Divisor<2> { enum { WIDTH_LOG2 = 1 }; }; template <> struct Uint_width<8>::Divisor<4> { enum { WIDTH_LOG2 = 2 }; }; template <> struct Uint_width<8>::Divisor<8> { enum { WIDTH_LOG2 = 3 }; }; @@ -93,7 +86,6 @@ namespace Genode { namespace Trait { */ template struct Uint_type; - template <> struct Uint_type : Uint_width<1> { }; template <> struct Uint_type : Uint_width<8> { }; template <> struct Uint_type : Uint_width<16> { }; template <> struct Uint_type : Uint_width<32> { }; @@ -115,13 +107,11 @@ namespace Genode { namespace Trait { template struct Genode::Register { - enum { - ACCESS_WIDTH = _ACCESS_WIDTH, - ACCESS_WIDTH_LOG2 = Trait::Uint_width::WIDTH_LOG2, - BITFIELD_WIDTH = ACCESS_WIDTH, - }; + static constexpr size_t ACCESS_WIDTH = _ACCESS_WIDTH; + static constexpr size_t ACCESS_WIDTH_LOG2 = Trait::Uint_width::WIDTH_LOG2; + static constexpr size_t BITFIELD_WIDTH = ACCESS_WIDTH; - typedef typename Trait::Uint_width::Type access_t; + using access_t = typename Trait::Uint_width::Type; /** * A bitregion within a register @@ -136,15 +126,15 @@ struct Genode::Register template struct Bitfield { - enum { + /** + * Fetch template parameters + */ + static constexpr size_t SHIFT = _SHIFT; + static constexpr size_t WIDTH = _WIDTH; + static constexpr size_t BITFIELD_WIDTH = WIDTH; - /** - * Fetch template parameters - */ - SHIFT = _SHIFT, - WIDTH = _WIDTH, - BITFIELD_WIDTH = WIDTH, - }; + using bitfield_t = + typename Trait::Uint_width::WIDTH>::Type; /** * Get an unshifted mask of this field @@ -172,7 +162,7 @@ struct Genode::Register /** * Back reference to containing register */ - typedef Register Compound_reg; + using Compound_reg = Register; /** * Get register with this bitfield set to 'value' and rest left 0 @@ -195,8 +185,8 @@ struct Genode::Register /** * Get value of this bitfield from 'reg' */ - static inline access_t get(access_t const reg) - { return (reg >> SHIFT) & mask(); } + static inline bitfield_t get(access_t const reg) + { return (bitfield_t)((reg >> SHIFT) & mask()); } /** * Get register value 'reg' with this bitfield set to zero @@ -226,16 +216,16 @@ struct Genode::Register template struct Genode::Bitset_2 { - typedef _BITS_0 Bits_0; - typedef _BITS_1 Bits_1; - enum { - WIDTH = Bits_0::BITFIELD_WIDTH + - Bits_1::BITFIELD_WIDTH, - BITFIELD_WIDTH = WIDTH, - ACCESS_WIDTH = Trait::Raise_to_uint_width::WIDTH, - }; - typedef typename Trait::Uint_width::Type access_t; - typedef Bitset_2 Bitset_2_base; + using Bits_0 = _BITS_0; + using Bits_1 = _BITS_1; + + static constexpr size_t WIDTH = Bits_0::BITFIELD_WIDTH + + Bits_1::BITFIELD_WIDTH; + static constexpr size_t BITFIELD_WIDTH = WIDTH; + static constexpr size_t ACCESS_WIDTH = Trait::Raise_to_uint_width::WIDTH; + + using access_t = typename Trait::Uint_width::Type; + using Bitset_2_base = Bitset_2; /** * Convert bitset value to register representation @@ -263,7 +253,7 @@ struct Genode::Bitset_2 Bits_1::clear(reg); Bits_0::set(reg, value); Bits_1::set(reg, value >> Bits_0::WIDTH); - }; + } /** * Read bitset from a given register value @@ -276,7 +266,8 @@ struct Genode::Bitset_2 template static inline access_t get(T const reg) { - return Bits_0::get(reg) | (Bits_1::get(reg) << Bits_0::WIDTH); + return (access_t) + (Bits_0::get(reg) | (Bits_1::get(reg) << Bits_0::WIDTH)); } }; @@ -292,19 +283,19 @@ struct Genode::Bitset_2 template struct Genode::Bitset_3 { - typedef _BITS_0 Bits_0; - typedef _BITS_1 Bits_1; - typedef _BITS_2 Bits_2; - typedef Bitset_2 Bits_0_1; - enum { - WIDTH = Bits_0::BITFIELD_WIDTH + - Bits_1::BITFIELD_WIDTH + - Bits_2::BITFIELD_WIDTH, - BITFIELD_WIDTH = WIDTH, - ACCESS_WIDTH = Trait::Raise_to_uint_width::WIDTH, - }; - typedef typename Trait::Uint_width::Type access_t; - typedef Bitset_3 Bitset_3_base; + using Bits_0 = _BITS_0; + using Bits_1 = _BITS_1; + using Bits_2 = _BITS_2; + using Bits_0_1 = Bitset_2; + + static constexpr size_t WIDTH = Bits_0::BITFIELD_WIDTH + + Bits_1::BITFIELD_WIDTH + + Bits_2::BITFIELD_WIDTH; + static constexpr size_t BITFIELD_WIDTH = WIDTH; + static constexpr size_t ACCESS_WIDTH = Trait::Raise_to_uint_width::WIDTH; + + using access_t = typename Trait::Uint_width::Type; + using Bitset_3_base = Bitset_3; /** * Convert bitset value to register representation @@ -333,7 +324,7 @@ struct Genode::Bitset_3 Bits_2::clear(reg); Bits_0_1::set(reg, value); Bits_2::set(reg, value >> Bits_0_1::WIDTH); - }; + } /** * Read bitset from a given register value diff --git a/repos/base/include/util/register_set.h b/repos/base/include/util/register_set.h index 7c8f4629d6..aaca5c46a8 100644 --- a/repos/base/include/util/register_set.h +++ b/repos/base/include/util/register_set.h @@ -23,7 +23,8 @@ namespace Genode { struct Register_set_plain_access; - template class Register_set; + struct Register_set_base; + template class Register_set; } @@ -68,6 +69,21 @@ struct Genode::Register_set_plain_access }; +struct Genode::Register_set_base : Noncopyable +{ + /** + * Interface for delaying the execution of a calling thread + */ + struct Delayer : Interface + { + /** + * Delay execution of the caller for 'us' microseconds + */ + virtual void usleep(uint64_t us) = 0; + }; +}; + + /** * Set of fine-grained and typesafe accessible registers with offsets * @@ -83,8 +99,8 @@ struct Genode::Register_set_plain_access * must not define members named 'Register_base', 'Bitfield_base', * 'Register_array_base' or 'Array_bitfield_base'. */ -template -class Genode::Register_set : Noncopyable +template +class Genode::Register_set : public Register_set_base { private: @@ -149,13 +165,13 @@ class Genode::Register_set : Noncopyable { private: - typedef typename T::access_t access_t; + using access_t = typename T::access_t; access_t const _reference_val; public: - typedef T Object; + using Object = T; /** * Constructor @@ -198,7 +214,6 @@ class Genode::Register_set : Noncopyable */ template - struct Register : public Genode::Register<_ACCESS_WIDTH>, @@ -220,11 +235,10 @@ class Genode::Register_set : Noncopyable * that solely must not be redefined by the deriving * class to ensure correct template selection. */ - typedef Register<_OFFSET, _ACCESS_WIDTH, _STRICT_WRITE> - Register_base; + using Register_base = Register<_OFFSET, _ACCESS_WIDTH, _STRICT_WRITE>; + using access_t = typename Genode::Register<_ACCESS_WIDTH>::access_t; - typedef typename Genode::Register<_ACCESS_WIDTH>::access_t - access_t; + static_assert(OFFSET + sizeof(access_t) <= REGISTER_SET_SIZE); /** * A region within a register @@ -243,13 +257,11 @@ class Genode::Register_set : Noncopyable public Conditions > { /* analogous to 'Register_set::Register::Register_base' */ - typedef Bitfield<_SHIFT, _WIDTH> Bitfield_base; + using Bitfield_base = Bitfield<_SHIFT, _WIDTH>; /* back reference to containing register */ - typedef Register<_OFFSET, _ACCESS_WIDTH, _STRICT_WRITE> - Compound_reg; - - typedef Compound_reg::access_t access_t; + using Compound_reg = Register<_OFFSET, _ACCESS_WIDTH, _STRICT_WRITE>; + using access_t = Compound_reg::access_t; }; }; @@ -286,12 +298,11 @@ class Genode::Register_set : Noncopyable template - struct Register_array : public Register<_OFFSET, _ACCESS_WIDTH, _STRICT_WRITE> { - typedef typename Trait::Uint_width<_ACCESS_WIDTH>:: - template Divisor<_ITEM_WIDTH> Item; + using Item = typename Trait::Uint_width<_ACCESS_WIDTH> + ::template Divisor<_ITEM_WIDTH>; enum { STRICT_WRITE = _STRICT_WRITE, @@ -306,12 +317,11 @@ class Genode::Register_set : Noncopyable }; /* analogous to 'Register_set::Register::Register_base' */ - typedef Register_array - Register_array_base; + using Register_array_base = Register_array; - typedef typename Register:: - access_t access_t; + using access_t = + typename Register:: access_t; /** * A bit region within a register array item @@ -327,36 +337,34 @@ class Genode::Register_set : Noncopyable template Bitfield<_SHIFT, _SIZE> { /* analogous to 'Register_set::Register::Register_base' */ - typedef Bitfield<_SHIFT, _SIZE> Array_bitfield_base; + using Array_bitfield_base = Bitfield<_SHIFT, _SIZE>; /* back reference to containing register array */ - typedef Register_array - Compound_array; + using Compound_array = Register_array; }; + + struct Dst { off_t offset; uint8_t shift; }; + /** * Calculate destination of an array-item access * - * \param offset Gets overridden with the offset of the - * access type instance, that contains the - * access destination - * \param shift Gets overridden with the shift of the - * destination within the access type instance - * targeted by 'offset'. * \param index index of the targeted array item */ - static inline void dst(off_t & offset, - unsigned long & shift, - unsigned long const index) + static constexpr Dst dst(unsigned long index) { - unsigned long const bit_off = index << ITEM_WIDTH_LOG2; - offset = (off_t) ((bit_off >> BYTE_WIDTH_LOG2) - & ~(sizeof(access_t)-1) ); - shift = bit_off - ( offset << BYTE_WIDTH_LOG2 ); + off_t bit_offset = off_t(index << ITEM_WIDTH_LOG2); + off_t byte_offset = bit_offset >> BYTE_WIDTH_LOG2; + off_t offset = byte_offset & ~(sizeof(access_t) - 1); + uint8_t shift = uint8_t(bit_offset - (offset << BYTE_WIDTH_LOG2)); offset += OFFSET; + + return { .offset = offset, .shift = shift }; } + static_assert(dst(MAX_INDEX).offset + sizeof(access_t) <= REGISTER_SET_SIZE); + /** * Calc destination of a simple array-item access without shift * @@ -391,8 +399,8 @@ class Genode::Register_set : Noncopyable template inline typename T::Register_base::access_t read() const { - typedef typename T::Register_base Register; - typedef typename Register::access_t access_t; + using Register = typename T::Register_base; + using access_t = typename Register::access_t; return Plain_access::read(_plain_access, Register::OFFSET); } @@ -404,8 +412,8 @@ class Genode::Register_set : Noncopyable inline void write(typename T::Register_base::access_t const value) { - typedef typename T::Register_base Register; - typedef typename Register::access_t access_t; + using Register = typename T::Register_base; + using access_t = typename Register::access_t; Plain_access::write(_plain_access, Register::OFFSET, value); } @@ -418,12 +426,12 @@ class Genode::Register_set : Noncopyable * Read the bitfield 'T' of a register */ template - inline typename T::Bitfield_base::Compound_reg::access_t + inline typename T::Bitfield_base::bitfield_t read() const { - typedef typename T::Bitfield_base Bitfield; - typedef typename Bitfield::Compound_reg Register; - typedef typename Register::access_t access_t; + using Bitfield = typename T::Bitfield_base; + using Register = typename Bitfield::Compound_reg; + using access_t = typename Register::access_t; return Bitfield::get(Plain_access::read(_plain_access, Register::OFFSET)); @@ -438,9 +446,9 @@ class Genode::Register_set : Noncopyable inline void write(typename T::Bitfield_base::Compound_reg::access_t const value) { - typedef typename T::Bitfield_base Bitfield; - typedef typename Bitfield::Compound_reg Register; - typedef typename Register::access_t access_t; + using Bitfield = typename T::Bitfield_base; + using Register = typename Bitfield::Compound_reg; + using access_t = typename Register::access_t; /* initialize the pattern written finally to the register */ access_t write_value; @@ -473,8 +481,8 @@ class Genode::Register_set : Noncopyable inline typename T::Register_array_base::access_t read(unsigned long const index) const { - typedef typename T::Register_array_base Array; - typedef typename Array::access_t access_t; + using Array = typename T::Register_array_base; + using access_t = typename Array::access_t; /* reads outside the array return 0 */ if (index > Array::MAX_INDEX) return 0; @@ -487,10 +495,9 @@ class Genode::Register_set : Noncopyable /* access width and item width differ */ } else { - long unsigned shift; - Array::dst(offset, shift, index); - return (Plain_access::read(_plain_access, offset) - >> shift) & Array::ITEM_MASK; + typename Array::Dst dst { Array::dst(index) }; + return (Plain_access::read(_plain_access, dst.offset) + >> dst.shift) & Array::ITEM_MASK; } } @@ -505,8 +512,8 @@ class Genode::Register_set : Noncopyable write(typename T::Register_array_base::access_t const value, unsigned long const index) { - typedef typename T::Register_array_base Array; - typedef typename Array::access_t access_t; + using Array = typename T::Register_array_base; + using access_t = typename Array::access_t; /* ignore writes outside the array */ if (index > Array::MAX_INDEX) return; @@ -519,8 +526,7 @@ class Genode::Register_set : Noncopyable /* access width and item width differ */ } else { - long unsigned shift; - Array::dst(offset, shift, index); + typename Array::Dst dst { Array::dst(index) }; /* insert new value into old register value */ access_t write_value; @@ -532,12 +538,12 @@ class Genode::Register_set : Noncopyable /* apply bitfield to the old register value */ write_value = Plain_access::read(_plain_access, - offset); - write_value &= ~(Array::ITEM_MASK << shift); + dst.offset); + write_value &= ~(Array::ITEM_MASK << dst.shift); } /* apply bitfield value and override register */ - write_value |= (value & Array::ITEM_MASK) << shift; - Plain_access::write(_plain_access, offset, + write_value |= (value & Array::ITEM_MASK) << dst.shift; + Plain_access::write(_plain_access, dst.offset, write_value); } } @@ -553,11 +559,11 @@ class Genode::Register_set : Noncopyable * \param index index of the targeted item */ template - inline typename T::Array_bitfield_base::Compound_array::access_t + inline typename T::Array_bitfield_base::bitfield_t read(unsigned long const index) const { - typedef typename T::Array_bitfield_base Bitfield; - typedef typename Bitfield::Compound_array Array; + using Bitfield = typename T::Array_bitfield_base; + using Array = typename Bitfield::Compound_array; return Bitfield::get(read(index)); } @@ -572,9 +578,9 @@ class Genode::Register_set : Noncopyable write(typename T::Array_bitfield_base::Compound_array::access_t const value, long unsigned const index) { - typedef typename T::Array_bitfield_base Bitfield; - typedef typename Bitfield::Compound_array Array; - typedef typename Array::access_t access_t; + using Bitfield = typename T::Array_bitfield_base; + using Array = typename Bitfield::Compound_array; + using access_t = typename Array::access_t; /* initialize the pattern written finally to the register */ access_t write_value; @@ -604,9 +610,9 @@ class Genode::Register_set : Noncopyable template inline typename T::Bitset_2_base::access_t const read() { - typedef typename T::Bitset_2_base::Bits_0 Bits_0; - typedef typename T::Bitset_2_base::Bits_1 Bits_1; - typedef typename T::Bitset_2_base::access_t access_t; + using Bits_0 = typename T::Bitset_2_base::Bits_0; + using Bits_1 = typename T::Bitset_2_base::Bits_1; + using access_t = typename T::Bitset_2_base::access_t; enum { V1_SHIFT = Bits_0::BITFIELD_WIDTH }; access_t const v0 = read(); access_t const v1 = read(); @@ -621,10 +627,10 @@ class Genode::Register_set : Noncopyable template inline void write(typename T::Bitset_2_base::access_t v) { - typedef typename T::Bitset_2_base::Bits_0 Bits_0; - typedef typename T::Bitset_2_base::Bits_1 Bits_1; - write(v); - write(v >> Bits_0::BITFIELD_WIDTH); + using Bits_0 = typename T::Bitset_2_base::Bits_0; + using Bits_1 = typename T::Bitset_2_base::Bits_1; + write(typename Bits_0::access_t(v)); + write(typename Bits_1::access_t(v >> Bits_0::BITFIELD_WIDTH)); } /** @@ -633,15 +639,15 @@ class Genode::Register_set : Noncopyable template inline typename T::Bitset_3_base::access_t const read() { - typedef typename T::Bitset_3_base::Bits_0 Bits_0; - typedef typename T::Bitset_3_base::Bits_1 Bits_1; - typedef typename T::Bitset_3_base::Bits_2 Bits_2; - typedef typename T::Bitset_3_base::access_t access_t; - enum { - BITS_0_WIDTH = Bits_0::BITFIELD_WIDTH, - BITS_1_WIDTH = Bits_1::BITFIELD_WIDTH, - V1_SHIFT = BITS_0_WIDTH + BITS_1_WIDTH, - }; + using Bits_0 = typename T::Bitset_3_base::Bits_0; + using Bits_1 = typename T::Bitset_3_base::Bits_1; + using Bits_2 = typename T::Bitset_3_base::Bits_2; + using access_t = typename T::Bitset_3_base::access_t; + + static constexpr size_t BITS_0_WIDTH = Bits_0::BITFIELD_WIDTH; + static constexpr size_t BITS_1_WIDTH = Bits_1::BITFIELD_WIDTH; + static constexpr size_t V1_SHIFT = BITS_0_WIDTH + BITS_1_WIDTH; + access_t const v0 = read >(); access_t const v1 = read(); return v0 | (v1 << V1_SHIFT); @@ -655,12 +661,12 @@ class Genode::Register_set : Noncopyable template inline void write(typename T::Bitset_3_base::access_t v) { - typedef typename T::Bitset_3_base::Bits_0 Bits_0; - typedef typename T::Bitset_3_base::Bits_1 Bits_1; - typedef typename T::Bitset_3_base::Bits_2 Bits_2; - write >(v); - write(v >> (Bits_0::BITFIELD_WIDTH + - Bits_1::BITFIELD_WIDTH)); + using Bits_0 = typename T::Bitset_3_base::Bits_0; + using Bits_1 = typename T::Bitset_3_base::Bits_1; + using Bits_2 = typename T::Bitset_3_base::Bits_2; + write >(typename Bitset_2::access_t(v)); + write(typename Bits_2::access_t(v >> (Bits_0::BITFIELD_WIDTH + + Bits_1::BITFIELD_WIDTH))); } @@ -682,17 +688,6 @@ class Genode::Register_set : Noncopyable explicit Microseconds(uint64_t value) : value(value) { } }; - /** - * Interface for delaying the execution of a calling thread - */ - struct Delayer : Interface - { - /** - * Delay execution of the caller for 'us' microseconds - */ - virtual void usleep(uint64_t us) = 0; - }; - /** * Wait until a list of IO conditions is met diff --git a/repos/base/include/util/retry.h b/repos/base/include/util/retry.h index abd62f395f..406c5ac3bf 100644 --- a/repos/base/include/util/retry.h +++ b/repos/base/include/util/retry.h @@ -17,9 +17,9 @@ namespace Genode { - template - auto retry(FUNC func, HANDLER handler, - unsigned attempts = ~0U) -> decltype(func()); + template + auto retry(auto const &fn, auto const &, + unsigned attempts = ~0U) -> decltype(fn()); } /** @@ -29,20 +29,20 @@ namespace Genode { * is called and the function call is retried. * * \param EXC exception type to handle - * \param func functor to execute - * \param handler exception handler executed if 'func' raised an exception + * \param fn functor to execute + * \param exc_fn exception handler executed if 'fn' raised an exception * of type 'EXC' * \param attempts number of attempts to execute 'func' before giving up * and reflecting the exception 'EXC' to the caller. If not * specified, attempt infinitely. */ -template -auto Genode::retry(FUNC func, HANDLER handler, - unsigned attempts) -> decltype(func()) +template +auto Genode::retry(auto const &fn, auto const &exc_fn, + unsigned attempts) -> decltype(fn()) { for (unsigned i = 0; attempts == ~0U || i < attempts; i++) - try { return func(); } - catch (EXC) { handler(); } + try { return fn(); } + catch (EXC) { exc_fn(); } throw EXC(); } diff --git a/repos/base/include/util/string.h b/repos/base/include/util/string.h index 5eb4eb2162..0088a83e8f 100644 --- a/repos/base/include/util/string.h +++ b/repos/base/include/util/string.h @@ -18,12 +18,14 @@ #include #include #include +#include #include namespace Genode { class Number_of_bytes; class Byte_range_ptr; + class Const_byte_range_ptr; class Cstring; template class String; } @@ -69,21 +71,47 @@ class Genode::Number_of_bytes /** - * Data structure for describing a byte buffer + * Data structure for describing a mutable byte buffer * * The type is intended to be used as 'Byte_range_ptr const &' argument. - * It is deliberately non-copyable. */ -struct Genode::Byte_range_ptr +struct Genode::Byte_range_ptr : Noncopyable { - char * const start; - size_t const num_bytes; + struct { + char * const start; + size_t const num_bytes; + }; Byte_range_ptr(char *start, size_t num_bytes) : start(start), num_bytes(num_bytes) { } }; +/** + * Data structure for describing a constant byte buffer + */ +struct Genode::Const_byte_range_ptr : Noncopyable +{ + struct { + char const * const start; + size_t const num_bytes; + }; + + bool contains(char const *ptr) const + { + return (ptr >= start) && (ptr <= start + num_bytes - 1); + } + + bool contains(void const *ptr) const + { + return contains((char const *)ptr); + } + + Const_byte_range_ptr(char const *start, size_t num_bytes) + : start(start), num_bytes(num_bytes) { } +}; + + /*********************** ** Utility functions ** ***********************/ @@ -93,6 +121,7 @@ namespace Genode { /** * Return length of null-terminated string in bytes */ + __attribute((optimize("no-tree-loop-distribute-patterns"))) inline size_t strlen(const char *s) { size_t res = 0; @@ -246,7 +275,7 @@ namespace Genode { __attribute((optimize("no-tree-loop-distribute-patterns"))) inline void *memset(void *dst, uint8_t i, size_t size) { - typedef unsigned long word_t; + using word_t = unsigned long; enum { LEN = sizeof(word_t), @@ -742,12 +771,12 @@ class Genode::String * may fit perfectly into the buffer or may have been truncated. * In general, it would be safe to assume the latter. */ - template - String(T const &arg, TAIL &&... args) + template + String(T const &head, auto &&... tail) { /* initialize string content */ Local_output output(_buf); - Genode::print(output, arg, args...); + Genode::print(output, head, tail...); /* add terminating null */ _buf[output.num_chars()] = 0; diff --git a/repos/base/include/util/token.h b/repos/base/include/util/token.h index 2d60d00b94..1bef51d284 100644 --- a/repos/base/include/util/token.h +++ b/repos/base/include/util/token.h @@ -123,7 +123,7 @@ class Genode::Token /** * Return next token after delimiter */ - Token next_after(char const *delim) + Token next_after(char const *delim) const { size_t const len = strlen(delim); @@ -141,7 +141,7 @@ class Genode::Token /** * Return true if token starts with pattern */ - bool matches(char const *pattern) + bool matches(char const *pattern) const { size_t const len = strlen(pattern); diff --git a/repos/base/include/util/xml_generator.h b/repos/base/include/util/xml_generator.h index 16e1926623..5388657d58 100644 --- a/repos/base/include/util/xml_generator.h +++ b/repos/base/include/util/xml_generator.h @@ -16,7 +16,6 @@ #include #include -#include namespace Genode { class Xml_generator; } @@ -297,26 +296,23 @@ class Genode::Xml_generator public: - template - Xml_generator(char *dst, size_t dst_len, - char const *name, FUNC const &func) + Xml_generator(char *dst, size_t dst_len, char const *name, auto const &fn) : _out_buffer(dst, dst_len) { if (dst) { - node(name, func); + node(name, fn); _out_buffer.append('\n'); _out_buffer.append('\0'); } } - template - void node(char const *name, FUNC const &func = [] () { } ) + void node(char const *name, auto const &fn = [] { } ) { - Node(*this, name, func); + Node(*this, name, fn); } - void node(char const *name) { Node(*this, name, [] () { }); } + void node(char const *name) { Node(*this, name, [] { }); } void attribute(char const *name, char const *str) { @@ -336,9 +332,7 @@ class Genode::Xml_generator void attribute(char const *name, long long value) { - char buf[64]; - Genode::snprintf(buf, sizeof(buf), "%lld", value); - _curr_node->insert_attribute(name, buf); + _curr_node->insert_attribute(name, String<64>(value).string()); } void attribute(char const *name, long value) @@ -353,9 +347,7 @@ class Genode::Xml_generator void attribute(char const *name, unsigned long long value) { - char buf[64]; - Genode::snprintf(buf, sizeof(buf), "%llu", value); - _curr_node->insert_attribute(name, buf); + _curr_node->insert_attribute(name, String<64>(value).string()); } void attribute(char const *name, unsigned long value) @@ -399,8 +391,7 @@ class Genode::Xml_generator * * This method must not be followed by calls of 'attribute'. */ - template - void append_content(ARGS &&... args) + void append_content(auto &&... args) { struct Node_output : Genode::Output { diff --git a/repos/base/include/util/xml_node.h b/repos/base/include/util/xml_node.h index 7dd4eefd0c..d94f709102 100644 --- a/repos/base/include/util/xml_node.h +++ b/repos/base/include/util/xml_node.h @@ -50,7 +50,7 @@ class Genode::Xml_attribute /** * Define tokenizer that matches XML tags (with hyphens) as identifiers */ - typedef ::Genode::Token Token; + using Token = ::Genode::Token; struct Tokens { @@ -93,7 +93,7 @@ class Genode::Xml_attribute explicit Xml_attribute(Token t) : _tokens(t) { if (_tokens.name.type() != Token::IDENT) - throw Nonexistent_attribute(); + throw Invalid_syntax(); if (!_tokens.valid()) throw Invalid_syntax(); @@ -110,18 +110,17 @@ class Genode::Xml_attribute ** Exception types ** *********************/ - class Invalid_syntax : public Exception { }; - class Nonexistent_attribute : public Exception { }; + class Invalid_syntax : public Exception { }; - typedef String<64> Name; + using Name = String<64>; Name name() const { return Name(Cstring(_tokens.name.start(), _tokens.name.len())); } /** * Return true if attribute has specified type */ - bool has_type(char const *type) { + bool has_type(char const *type) const { return strlen(type) == _tokens.name.len() && strcmp(type, _tokens.name.start(), _tokens.name.len()) == 0; } @@ -156,8 +155,7 @@ class Genode::Xml_attribute * Note that the content of the buffer is not null-terminated but * delimited by the size argument. */ - template - void with_raw_value(FN const &fn) const + void with_raw_value(auto const &fn) const { /* * Skip leading quote of the '_value' to access the actual value. @@ -173,8 +171,7 @@ class Genode::Xml_attribute * false if attribute is invalid or value * conversion failed */ - template - bool value(T &out) const + bool value(auto &out) const { bool result = false; @@ -208,7 +205,7 @@ class Genode::Xml_node { private: - typedef Xml_attribute::Token Token; + using Token = Xml_attribute::Token; /** * Forward declaration needed for befriending Tag with Xml_attribute @@ -223,9 +220,7 @@ class Genode::Xml_node ** Exception types ** *********************/ - typedef Genode::Exception Exception; - typedef Xml_attribute::Nonexistent_attribute Nonexistent_attribute; - typedef Xml_attribute::Invalid_syntax Invalid_syntax; + using Invalid_syntax = Xml_attribute::Invalid_syntax; class Nonexistent_sub_node : public Exception { }; @@ -233,7 +228,7 @@ class Genode::Xml_node /** * Type definition for maintaining backward compatibility */ - typedef Xml_attribute Attribute; + using Attribute = Xml_attribute; private: @@ -660,7 +655,7 @@ class Genode::Xml_node /** * Request type name of XML node as null-terminated string */ - typedef String<64> Type; + using Type = String<64>; Type type() const { Token name = _tags.start.name(); @@ -678,8 +673,7 @@ class Genode::Xml_node /** * Call functor 'fn' with the node data '(char const *, size_t)' */ - template - void with_raw_node(FN const &fn) const + void with_raw_node(auto const &fn) const { char const *start_ptr = _tags.start.token().start(); fn(start_ptr, _tags.end.next_token().start() - start_ptr); @@ -693,8 +687,7 @@ class Genode::Xml_node * * If the node has no content, the functor 'fn' is not called. */ - template - void with_raw_content(FN const &fn) const + void with_raw_content(auto const &fn) const { if (_tags.start.type() == Tag::EMPTY) return; @@ -844,8 +837,7 @@ class Genode::Xml_node * The functor is called with the sub node as argument. * If no matching sub node exists, the functor is not called. */ - template - void with_optional_sub_node(char const *type, FN const &fn) const + void with_optional_sub_node(char const *type, auto const &fn) const { if (has_sub_node(type)) fn(sub_node(type)); @@ -855,22 +847,20 @@ class Genode::Xml_node * Apply functor 'fn' to first sub node of specified type * * The functor is called with the sub node as argument. - * If no matching sub node exists, the functor 'fn_nexists' is called. + * If no matching sub node exists, the functor 'missing_fn' is called. */ - template - void with_sub_node(char const *type, FN const &fn, FN_NEXISTS const &fn_nexists) const + void with_sub_node(char const *type, auto const &fn, auto const &missing_fn) const { if (has_sub_node(type)) fn(sub_node(type)); else - fn_nexists(); + missing_fn(); } /** * Execute functor 'fn' for each sub node of specified type */ - template - void for_each_sub_node(char const *type, FN const &fn) const + void for_each_sub_node(char const *type, auto const &fn) const { if (!has_sub_node(type)) return; @@ -887,47 +877,11 @@ class Genode::Xml_node /** * Execute functor 'fn' for each sub node */ - template - void for_each_sub_node(FN const &fn) const + void for_each_sub_node(auto const &fn) const { for_each_sub_node(nullptr, fn); } - /** - * Return Nth attribute of XML node - * - * \param idx attribute index, - * first attribute has index 0 - * \throw Nonexistent_attribute no such attribute exists - * \return XML attribute - */ - Xml_attribute attribute(unsigned idx) const - { - Xml_attribute attr = _tags.start.attribute(); - for (unsigned i = 0; i < idx; i++) - attr = Xml_attribute(attr._next_token()); - - return attr; - } - - /** - * Return attribute of specified type - * - * \param type name of attribute type - * \throw Nonexistent_attribute no such attribute exists - * \return XML attribute - */ - Xml_attribute attribute(char const *type) const - { - for (Xml_attribute attr = _tags.start.attribute(); ;) { - if (attr.has_type(type)) - return attr; - - attr = Xml_attribute(attr._next_token()); - } - throw Nonexistent_attribute(); - } - /** * Read attribute value from XML node * @@ -990,6 +944,25 @@ class Genode::Xml_node } } + /** + * Execute functor 'fn' for each attribute + */ + void for_each_attribute(auto const &fn) const + { + if (!_tags.start.has_attribute()) + return; + + for (Xml_attribute attr = _tags.start.attribute(); ; ) { + fn(attr); + + Token const next = attr._next_token(); + if (!Xml_attribute::_valid(next)) + return; + + attr = Xml_attribute(next); + } + } + /** * Return true if sub node of specified type exists */ @@ -1021,10 +994,14 @@ class Genode::Xml_node /** * Return true if this node differs from 'another' */ - bool differs_from(Xml_node const &another) const + bool differs_from(Xml_node const &other) const { - return size() != another.size() || - memcmp(_addr, another._addr, size()) != 0; + bool result = false; + other.with_raw_node([&] (char const * const other_start, size_t other_len) { + with_raw_node([&] (char const * const start, size_t len) { + result = (len != other_len) + || (memcmp(start, other_start, len) != 0); }); }); + return result; } }; @@ -1050,7 +1027,7 @@ class Genode::Xml_unquoted : Noncopyable template Xml_unquoted(String const &string) - : _content_ptr({ string.string(), string.length() - 1}) + : _content_ptr({ string.string(), string.length() ? string.length() - 1 : 0 }) { } void print(Output &out) const diff --git a/repos/base/include/vm_session/connection.h b/repos/base/include/vm_session/connection.h index b957846fa9..054de982b0 100644 --- a/repos/base/include/vm_session/connection.h +++ b/repos/base/include/vm_session/connection.h @@ -2,6 +2,7 @@ * \brief Connection to a VM service * \author Stefan Kalkowski * \author Christian Helmuth + * \author Benjamin Lamowski * \date 2012-10-02 * * The VM connection is the API for VM and vCPU handling and implemented @@ -9,7 +10,7 @@ */ /* - * Copyright (C) 2012-2021 Genode Labs GmbH + * Copyright (C) 2012-2023 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -22,6 +23,7 @@ #include #include #include +#include #include #include @@ -35,19 +37,6 @@ namespace Genode { struct Genode::Vm_connection : Connection, Rpc_client { - /** - * Issue session request - * - * \noapi - */ - Capability _session(Parent &parent, char const *label, long priority, - unsigned long affinity) - { - return session(parent, - "priority=0x%lx, affinity=0x%lx, ram_quota=16K, cap_quota=10, label=\"%s\"", - priority, affinity, label); - } - /* * VM-Exit state-transfer configuration * @@ -60,6 +49,12 @@ struct Genode::Vm_connection : Connection, Rpc_client /* for example OMIT_FPU_ON_IRQ */ }; + + struct Call_with_state : Genode::Interface + { + virtual bool call_with_state(Vcpu_state &) = 0; + }; + /** * Virtual CPU * @@ -68,13 +63,28 @@ struct Genode::Vm_connection : Connection, Rpc_client */ struct Vcpu : Genode::Noncopyable { + void _with_state(Call_with_state &); + Native_vcpu &_native_vcpu; Vcpu(Vm_connection &, Allocator &, Vcpu_handler_base &, Exit_config const &); - void run(); - void pause(); - Vcpu_state & state(); + template + void with_state(FN const &fn) + { + struct Untyped_fn : Call_with_state + { + FN const &_fn; + Untyped_fn(FN const &fn) : _fn(fn) {} + + bool call_with_state(Vcpu_state &state) override + { + return _fn(state); + } + } untyped_fn(fn); + + _with_state(untyped_fn); + } }; friend class Vcpu; @@ -82,38 +92,39 @@ struct Genode::Vm_connection : Connection, Rpc_client /** * Constructor * - * \param label initial session label * \param priority designated priority of the VM * \param affinity which physical CPU the VM should run on top of */ - Vm_connection(Env &env, const char *label = "", + Vm_connection(Env &env, Label const &label = Label(), long priority = Cpu_session::DEFAULT_PRIORITY, unsigned long affinity = 0) : - Connection(env, _session(env.parent(), label, priority, affinity)), + Connection(env, label, Ram_quota { 16*1024 }, Affinity(), + Args("priority=", Hex(priority), ", " + "affinity=", Hex(affinity))), Rpc_client(cap()) { } - template - auto with_upgrade(FUNC func) -> decltype(func()) + auto with_upgrade(auto const &fn) -> decltype(fn()) { return Genode::retry( - [&] () { + [&] { return Genode::retry( - [&] () { return func(); }, - [&] () { this->upgrade_caps(2); }); + [&] { return fn(); }, + [&] { this->upgrade_caps(2); }); }, - [&] () { this->upgrade_ram(4096); } + [&] { this->upgrade_ram(4096); } ); } + /************************** ** Vm_session interface ** **************************/ void attach(Dataspace_capability ds, addr_t vm_addr, Attach_attr attr) override { - with_upgrade([&] () { + with_upgrade([&] { call(ds, vm_addr, attr); }); } diff --git a/repos/base/include/vm_session/handler.h b/repos/base/include/vm_session/handler.h index b745c9e1f7..31564a3bd2 100644 --- a/repos/base/include/vm_session/handler.h +++ b/repos/base/include/vm_session/handler.h @@ -27,16 +27,17 @@ class Genode::Vcpu_handler_base : public Signal_dispatcher_base { protected: - Rpc_entrypoint &_rpc_ep; + Entrypoint &_ep; Signal_context_capability _signal_cap { }; Genode::Semaphore _ready_semaphore { 0 }; public: - Vcpu_handler_base(Rpc_entrypoint &rpc) - : _rpc_ep(rpc) { } + Vcpu_handler_base(Entrypoint &ep) + : _ep(ep) { } - Rpc_entrypoint & rpc_ep() { return _rpc_ep; } + Rpc_entrypoint & rpc_ep() { return _ep.rpc_ep(); } + Entrypoint & ep() { return _ep; } Signal_context_capability signal_cap() { return _signal_cap; } Genode::Semaphore & ready_semaphore() { return _ready_semaphore; } }; @@ -66,7 +67,7 @@ class Genode::Vcpu_handler : public Vcpu_handler_base */ Vcpu_handler(EP &ep, T &obj, void (T::*member)()) : - Vcpu_handler_base(ep.rpc_ep()), + Vcpu_handler_base(ep), _ep(ep), _obj(obj), _member(member) diff --git a/repos/base/include/vm_session/vm_session.h b/repos/base/include/vm_session/vm_session.h index e4087759c3..1872f9ce3c 100644 --- a/repos/base/include/vm_session/vm_session.h +++ b/repos/base/include/vm_session/vm_session.h @@ -37,7 +37,7 @@ struct Genode::Vm_session : Session bool writeable; }; - enum { CAP_QUOTA = 3 }; + enum { CAP_QUOTA = 10 }; class Invalid_dataspace : Exception { }; class Region_conflict : Exception { }; diff --git a/repos/base/lib/README b/repos/base/lib/README deleted file mode 100644 index 8b5b8affc6..0000000000 --- a/repos/base/lib/README +++ /dev/null @@ -1 +0,0 @@ -This directory holds library-description files. diff --git a/repos/base/lib/mk/README b/repos/base/lib/mk/README index 6e3381812a..d829a9ce54 100644 --- a/repos/base/lib/mk/README +++ b/repos/base/lib/mk/README @@ -1,24 +1,12 @@ -This directory contains library description files. Each '.mk' file -holds the instruction for building the library ''. These makefiles are -never used directly but they are called from the build system when required. -When called, the build system passes the following variables: +This directory contains library-description files. Each _.mk_ file +contains the instructions for building the library __. The .mk files +are never used directly but they are implicitely processed by the build +system. -:'BASE_DIR': This is the base directory of the source tree. - -Source codes are specified by setting the 'SRC_CC' and 'SRC_C' variables. -The source code locations must be specified via 'vpath'. -A library can include other libraries by setting the 'LIBS' -variable. - -Each '.mk' file must include the 'lib.mk' role file: - -! include $(BASE_DIR)/mk/lib.mk - -Libraries implementing one and the same library interface may have specific -implementations for different platforms. Such platform-specific '.mk' -files should be placed into corresponding subdirectories. For example, the -'linux'-specific implementation of the 'server' library resides in the 'linux/' -subdirectory. The build system automatically searches the right '.mk' -file by evaluating the 'SPECS' configuration variable. If 'SPECS' is set to -'host linux', the build system will look into the directories './', './host', -and './linux'. +Libraries implementing one interface may have specialized implementations for +different CPU architectures. Such architecture-specific _.mk_ files +are located in corresponding _spec/_ subdirectories. For example, the .mk +files of ARM-specific library variants reside in the _spec/arm/_ subdirectory. +The build system automatically finds the appropriate _.mk_ file by +evaluating the 'SPECS' build-configuration variable. Whenever the 'SPECS' +variable contains 'arm', the build system considers the _spec/arm/_ directory. diff --git a/repos/base/lib/mk/base-common.inc b/repos/base/lib/mk/base-common.inc index 276f638946..fc66779e1d 100644 --- a/repos/base/lib/mk/base-common.inc +++ b/repos/base/lib/mk/base-common.inc @@ -9,7 +9,6 @@ SRC_CC += slab.cc SRC_CC += allocator_avl.cc SRC_CC += heap.cc sliced_heap.cc SRC_CC += registry.cc -SRC_CC += console.cc SRC_CC += output.cc SRC_CC += child.cc SRC_CC += child_process.cc @@ -23,14 +22,11 @@ SRC_CC += raw_output.cc SRC_CC += rpc_entrypoint.cc SRC_CC += signal_common.cc SRC_CC += sleep.cc -SRC_CC += entrypoint.cc -SRC_CC += component.cc SRC_CC += region_map_client.cc SRC_CC += rm_session_client.cc SRC_CC += stack_allocator.cc SRC_CC += trace.cc SRC_CC += trace_buffer.cc -SRC_CC += root_proxy.cc SRC_CC += env_session_id_space.cc SRC_CC += stack_protector.cc SRC_CC += xml_generator.cc diff --git a/repos/base/lib/mk/base.inc b/repos/base/lib/mk/base.inc index c72150c8f9..80a88f4cd6 100644 --- a/repos/base/lib/mk/base.inc +++ b/repos/base/lib/mk/base.inc @@ -1,5 +1,8 @@ +SRC_CC += component.cc SRC_CC += default_log.cc -SRC_CC += env_deprecated.cc stack_area.cc main_thread_cap.cc +SRC_CC += entrypoint.cc +SRC_CC += platform.cc stack_area.cc +SRC_CC += root_proxy.cc SRC_CC += rpc_cap_alloc.cc heartbeat.cc SRC_CC += vm.cc diff --git a/repos/base/lib/mk/ld-platform.inc b/repos/base/lib/mk/ld-platform.inc index 9b80296614..c7f983d1c1 100644 --- a/repos/base/lib/mk/ld-platform.inc +++ b/repos/base/lib/mk/ld-platform.inc @@ -20,6 +20,7 @@ SYMBOLS := $(BASE_DIR)/lib/symbols/ld # Generate symbol map from the ABI # $(LIB).lib.so: symbol.map +$(LIB).abi.so: symbol.map symbol.map: $(MAKEFILE_LIST) symbol.map: $(BASE_DIR)/lib/symbols/ld $(MSG_CONVERT)$@ diff --git a/repos/base/lib/mk/ld.mk b/repos/base/lib/mk/ld.mk index 23fed31558..70b97d0972 100644 --- a/repos/base/lib/mk/ld.mk +++ b/repos/base/lib/mk/ld.mk @@ -1,19 +1,20 @@ # # Generic ld.lib.so ABI stub library # -# This library is used to build kernel-independent dynamically linked -# executables. It does not contain any code or data but only the symbol -# information of the binary interface of the Genode API. +# The ABI of this library is used to build kernel-independent dynamically +# linked executables. The library does not contain any code or data but only +# the symbol information of the binary interface of the Genode API. # # Note that this library is not used as runtime at all. At system-integration # time, it is transparently replaced by the variant of the dynamic linker that # matches the used kernel. # - -SHARED_LIB := yes - -LD_OPT += -T$(BASE_DIR)/src/lib/ldso/linker.ld - +# By adding a LIB dependency from the kernel-specific dynamic linker, we +# let dep_lib.mk generate the rule for ld-.so into the var/libdeps +# file. The build of the ld-.so is triggered because the top-level +# Makefile manually adds the dependency 'ld.so: ld-.so' to the +# var/libdeps file for the currently selected kernel. +# LIBS += $(addprefix ld-,$(KERNEL)) # as the stub libarary is not used at runtime, disregard it as build artifact diff --git a/repos/base/lib/mk/startup.inc b/repos/base/lib/mk/startup.inc index f76e595c25..f9d1b874d4 100644 --- a/repos/base/lib/mk/startup.inc +++ b/repos/base/lib/mk/startup.inc @@ -1,5 +1,5 @@ SRC_S += crt0.s -SRC_CC += _main.cc init_main_thread.cc +SRC_CC += _main.cc REP_INC_DIR += src/include vpath %.cc $(BASE_DIR)/src/lib/startup diff --git a/repos/base/lib/symbols/ld b/repos/base/lib/symbols/ld index 5a04b7470d..5c705f5af1 100644 --- a/repos/base/lib/symbols/ld +++ b/repos/base/lib/symbols/ld @@ -43,12 +43,9 @@ _Z16main_thread_utcbv T _Z22__ldso_raise_exceptionv T _ZN5Timer10Connection11set_timeoutEN6Genode12MicrosecondsERNS1_15Timeout_handlerE T _ZN5Timer10Connection9curr_timeEv T -_ZN5Timer10ConnectionC1ERN6Genode3EnvEPKc T -_ZN5Timer10ConnectionC1ERN6Genode3EnvERNS1_10EntrypointEPKc T -_ZN5Timer10ConnectionC2ERN6Genode3EnvEPKc T -_ZN5Timer10ConnectionC2ERN6Genode3EnvERNS1_10EntrypointEPKc T +_ZN5Timer10ConnectionC1ERN6Genode3EnvERNS1_10EntrypointERKNS1_13Session_labelE T +_ZN5Timer10ConnectionC2ERN6Genode3EnvERNS1_10EntrypointERKNS1_13Session_labelE T _ZN6Genode10Entrypoint16_dispatch_signalERNS_6SignalE T -_ZN6Genode10Entrypoint16schedule_suspendEPFvvES2_ T _ZN6Genode10Entrypoint22Signal_proxy_component6signalEv T _ZN6Genode10Entrypoint25_process_incoming_signalsEv T _ZN6Genode10Entrypoint32_wait_and_dispatch_one_io_signalEb T @@ -95,9 +92,7 @@ _ZN6Genode13Shared_objectC1ERNS_3EnvERNS_9AllocatorEPKcNS0_4BindENS0_4KeepE T _ZN6Genode13Shared_objectC2ERNS_3EnvERNS_9AllocatorEPKcNS0_4BindENS0_4KeepE T _ZN6Genode13Shared_objectD1Ev T _ZN6Genode13Shared_objectD2Ev T -_ZN6Genode13Vm_connection4Vcpu3runEv T -_ZN6Genode13Vm_connection4Vcpu5pauseEv T -_ZN6Genode13Vm_connection4Vcpu5stateEv T +_ZN6Genode13Vm_connection4Vcpu11_with_stateERNS0_15Call_with_stateE T _ZN6Genode13Vm_connection4VcpuC1ERS0_RNS_9AllocatorERNS_17Vcpu_handler_baseERKNS0_11Exit_configE T _ZN6Genode13Vm_connection4VcpuC2ERS0_RNS_9AllocatorERNS_17Vcpu_handler_baseERKNS0_11Exit_configE T _ZN6Genode13Xml_generator4NodeC1ERS0_PKcRKNS1_3_FnE T @@ -124,16 +119,13 @@ _ZN6Genode14Signal_contextD0Ev T _ZN6Genode14Signal_contextD1Ev T _ZN6Genode14Signal_contextD2Ev T _ZN6Genode14cache_coherentEmm T -_ZN6Genode14env_deprecatedEv T _ZN6Genode14ipc_reply_waitERKNS_17Native_capabilityENS_18Rpc_exception_codeERNS_11Msgbuf_baseES5_ T -_ZN6Genode15Connection_baseC1Ev T -_ZN6Genode15Connection_baseC2Ev T _ZN6Genode15Signal_receiver12local_submitENS_6Signal4DataE T _ZN6Genode15Signal_receiver14pending_signalEv T _ZN6Genode15Signal_receiver15wait_for_signalEv T _ZN6Genode15Signal_receiver16block_for_signalEv T -_ZN6Genode15Signal_receiver6manageEPNS_14Signal_contextE T -_ZN6Genode15Signal_receiver8dissolveEPNS_14Signal_contextE T +_ZN6Genode15Signal_receiver6manageERNS_14Signal_contextE T +_ZN6Genode15Signal_receiver8dissolveERNS_14Signal_contextE T _ZN6Genode15Signal_receiverC1Ev T _ZN6Genode15Signal_receiverC2Ev T _ZN6Genode15Signal_receiverD1Ev T @@ -144,9 +136,9 @@ _ZN6Genode17Native_capability4_incEv T _ZN6Genode17Native_capabilityC1Ev T _ZN6Genode17Native_capabilityC2Ev T _ZN6Genode17Region_map_client13fault_handlerENS_10CapabilityINS_14Signal_contextEEE T -_ZN6Genode17Region_map_client5stateEv T -_ZN6Genode17Region_map_client6attachENS_10CapabilityINS_9DataspaceEEEmlbNS_10Region_map10Local_addrEbb T -_ZN6Genode17Region_map_client6detachENS_10Region_map10Local_addrE T +_ZN6Genode17Region_map_client5faultEv T +_ZN6Genode17Region_map_client6attachENS_10CapabilityINS_9DataspaceEEERKNS_10Region_map4AttrE T +_ZN6Genode17Region_map_client6detachEm T _ZN6Genode17Region_map_client9dataspaceEv T _ZN6Genode17Region_map_clientC1ENS_10CapabilityINS_10Region_mapEEE T _ZN6Genode17Region_map_clientC2ENS_10CapabilityINS_10Region_mapEEE T @@ -295,12 +287,6 @@ _ZN6Genode6ThreadC2EmPKcmNS0_4TypeEPNS_11Cpu_sessionENS_8Affinity8LocationE T _ZN6Genode6ThreadD0Ev T _ZN6Genode6ThreadD1Ev T _ZN6Genode6ThreadD2Ev T -_ZN6Genode7Console11_out_stringEPKc T -_ZN6Genode7Console6printfEPKcz T -_ZN6Genode7Console7vprintfEPKcP13__va_list_tag T -_ZN6Genode7Console7vprintfEPKcPc T -_ZN6Genode7Console7vprintfEPKcPv T -_ZN6Genode7Console7vprintfEPKcSt9__va_list T _ZN6Genode7Timeout14_alarm_discardEv T _ZN6Genode7Timeout17schedule_one_shotENS_12MicrosecondsERNS_15Timeout_handlerE T _ZN6Genode7Timeout17schedule_periodicENS_12MicrosecondsERNS_15Timeout_handlerE T @@ -392,10 +378,10 @@ _ZTVN6Genode5ChildE D 440 _ZTVN6Genode6OutputE D 48 _ZTVN6Genode6ThreadE D 48 _ZTVN6Genode7ConsoleE D 48 -_ZThn236_N5Timer10Connection11set_timeoutEN6Genode12MicrosecondsERNS1_15Timeout_handlerE T -_ZThn236_N5Timer10Connection9curr_timeEv T -_ZThn288_N5Timer10Connection11set_timeoutEN6Genode12MicrosecondsERNS1_15Timeout_handlerE T -_ZThn288_N5Timer10Connection9curr_timeEv T +_ZThn104_N5Timer10Connection11set_timeoutEN6Genode12MicrosecondsERNS1_15Timeout_handlerE T +_ZThn104_N5Timer10Connection9curr_timeEv T +_ZThn52_N5Timer10Connection11set_timeoutEN6Genode12MicrosecondsERNS1_15Timeout_handlerE T +_ZThn52_N5Timer10Connection9curr_timeEv T _ZThn8_N6Genode17Timeout_scheduler14handle_timeoutENS_8DurationE T _ZThn8_N6Genode17Timeout_schedulerD0Ev T _ZThn8_N6Genode17Timeout_schedulerD1Ev T @@ -411,9 +397,6 @@ _ZnwjPN6Genode9AllocatorE T _ZnwjRN6Genode9AllocatorE T _ZnwmPN6Genode9AllocatorE T _ZnwmRN6Genode9AllocatorE T -genode_argc D 4 -genode_argv D 8 -genode_envp B 8 lx_environ B 8 memcpy W memmove W diff --git a/repos/base/mk/a.mk b/repos/base/mk/a.mk new file mode 100644 index 0000000000..c106404694 --- /dev/null +++ b/repos/base/mk/a.mk @@ -0,0 +1,100 @@ +## +## Rules for building a static library archive (.lib.a) +## +## The following variables must be passed when calling this file: +## +## LIB - library name +## BASE_DIR - base directory of the build system +## VERBOSE - build verboseness modifier +## VERBOSE_DIR - verboseness modifier for changing directories +## VERBOSE_MK - verboseness of make calls +## BUILD_BASE_DIR - base of build directory tree +## LIB_CACHE_DIR - library build cache location +## INSTALL_DIR - installation directory for stripped shared objects +## DEBUG_DIR - installation directory for unstripped shared objects +## SHARED_LIBS - shared-library dependencies of the library +## ARCHIVES - archive dependencies of the library +## REP_DIR - repository where the library resides +## CONTRIB_DIR - location of ported 3rd-party source codes +## + +LIB_A := $(addsuffix .lib.a,$(LIB)) + +# +# Prevent .mk rules to be executed as default rule +# +all: + @true # prevent nothing-to-be-done message + +# +# Include common utility functions +# +include $(BASE_DIR)/mk/util.inc + +# +# Include specifics, for example platform, kernel-api etc. +# +include $(SPEC_FILES) + +ORIG_INC_DIR := $(INC_DIR) + +# +# Include library build instructions +# +# We set the 'called_from_lib_mk' variable to allow the library description file +# to respond to the build pass. +# +called_from_lib_mk = yes +include $(LIB_MK) + +# +# Include lib-import descriptions of all used libraries and the target library +# +include $(foreach LIB,$(LIBS),$(call select_from_repositories,lib/import/import-$(LIB).mk)) + +# +# Sanity check for INC_DIR overrides +# +ifneq ($(filter-out $(INC_DIR),$(ORIG_INC_DIR)),) +all: error_inc_dir_override +endif + +error_inc_dir_override: + @$(ECHO) "Error: INC_DIR overridden instead of appended" ; false + +# +# Include global definitions +# +include $(BASE_DIR)/mk/global.mk +include $(BASE_DIR)/mk/generic.mk + +# +# Trigger the creation of the .lib.a +# +LIB_TAG := $(addsuffix .lib.tag,$(LIB)) +all: $(LIB_TAG) + +# +# Trigger the build of host tools +# +# We make '$(LIB_TAG)' depend on the host tools to support building host tools +# from pseudo libraries with no actual source code. In this case '$(OBJECTS)' +# is empty. +# +$(LIB_TAG) $(OBJECTS): $(HOST_TOOLS) + +# +# Rule to build the .lib.a file +# +# Use $(OBJECTS) instead of $^ for specifying the list of objects to include +# in the archive because $^ may also contain non-object phony targets, e.g., +# used by the integration of Qt's meta-object compiler into the Genode +# build system. +# +$(LIB_A): $(OBJECTS) + $(MSG_MERGE)$(LIB_A) + $(VERBOSE)$(RM) -f $@ + $(VERBOSE)$(AR) -rcs $@ $(OBJECTS) + +$(LIB_TAG): $(CUSTOM_TARGET_DEPS) $(LIB_A) + @touch $@ diff --git a/repos/base/mk/abi.mk b/repos/base/mk/abi.mk new file mode 100644 index 0000000000..688ece9544 --- /dev/null +++ b/repos/base/mk/abi.mk @@ -0,0 +1,97 @@ +## +## Create an ABI stub named '.abi.so' +## +## Invoked from the library's build directory within the lib cache. +## The following variables must be passed when calling this file: +## +## BASE_DIR - base directory of the build system +## VERBOSE - build verboseness modifier +## LIB_CACHE_DIR - library build cache location +## LIB - library name +## SYMBOLS - path of symbols file +## SPECS - build specs (i.e., CPU architecture) +## + +# +# An ABI-stub library does not contain any code or data but only the symbol +# information of the binary interface (ABI) of the shared library. +# +# The ABI stub is linked by the users of the library (executables or shared +# objects) instead of the real library. This effectively decouples the library +# users from the concrete library instance but binds them merely to the +# library's binary interface. Note that the ABI stub is not used at runtime at +# all. At runtime, the real library that implements the ABI is loaded by the +# dynamic linker. +# +# The symbol information are incorporated into the ABI stub via an assembly +# file named 'symbols.s' that is generated from the library's symbol list. +# + +ABI_SO := $(addsuffix .abi.so,$(LIB)) +SYMBOLS := $(wildcard $(SYMBOLS)) + +ifeq ($(SYMBOLS),) +all: +else +all: $(ABI_SO) +endif + +include $(BASE_DIR)/mk/util.inc +include $(SPEC_FILES) +include $(BASE_DIR)/mk/global.mk +include $(BASE_DIR)/mk/generic.mk + +# +# Generate assembler file from symbol list +# +# For undefined symbols (type U), we create a hard dependency by referencing +# the symbols from the assembly file. The reference is created in the form of +# a '.long' value with the address of the symbol. On x86_64, this is not +# possible for PIC code. Hence, we reference the symbol via a PIC-compatible +# movq instruction instead. +# +# If we declared the symbol as '.global' without using it, the undefined symbol +# gets discarded at link time unless it is directly referenced by the target. +# This is a problem in situations where the undefined symbol is resolved by an +# archive rather than the target. I.e., when linking posix.lib.a (which +# provides 'Libc::Component::construct'), the 'construct' function is merely +# referenced by the libc.lib.so's 'Component::construct' function. But this +# reference apparently does not suffice to keep the posix.lib.a's symbol. By +# adding a hard dependency, we force the linker to resolve the symbol and don't +# drop posix.lib.a. +# +ASM_SYM_DEPENDENCY := .long \1 +ifeq ($(filter-out $(SPECS),x86_64),) +ASM_SYM_DEPENDENCY := movq \1@GOTPCREL(%rip), %rax +endif + +symbols.s: $(SYMBOLS) + $(MSG_CONVERT)$@ + $(VERBOSE)\ + sed -e "s/^\(\w\+\) D \(\w\+\)\$$/.data; .global \1; .type \1,%object; .size \1,\2; \1: .skip 1/" \ + -e "s/^\(\w\+\) V/.data; .weak \1; .type \1,%object; \1: .skip 1/" \ + -e "s/^\(\w\+\) T/.text; .global \1; .type \1,%function; \1:/" \ + -e "s/^\(\w\+\) R \(\w\+\)\$$/.section .rodata; .global \1; .type \1,%object; .size \1,\2; \1:/" \ + -e "s/^\(\w\+\) W/.text; .weak \1; .type \1,%function; \1:/" \ + -e "s/^\(\w\+\) B \(\w\+\)\$$/.bss; .global \1; .type \1,%object; .size \1,\2; \1:/" \ + -e "s/^\(\w\+\) U/.text; .global \1; $(ASM_SYM_DEPENDENCY)/" \ + $< > $@ + +# +# The '.PRECIOUS' special target prevents make to remove the intermediate +# assembler file. Otherwise make would spill the build log with messages +# like "rm libc.symbols.s". +# +.PRECIOUS: symbols.s + +ABI_SONAME := $(addsuffix .lib.so,$(LIB)) + +all: # prevent 'Nothing to be done' message + @true + +$(ABI_SO): symbols.o + $(MSG_MERGE)$(ABI_SO) + $(VERBOSE)$(LD) -o $(ABI_SO) -soname=$(ABI_SONAME) -shared --eh-frame-hdr $(LD_OPT) \ + -T $(LD_SCRIPT_SO) $< + +$(ABI_SO): $(LD_SCRIPT_SO) diff --git a/repos/base/mk/dep.inc b/repos/base/mk/dep.inc new file mode 100644 index 0000000000..f8b11e136f --- /dev/null +++ b/repos/base/mk/dep.inc @@ -0,0 +1,55 @@ +# +# Common parts of dep_prg.mk, dep_lib.mk, and dep_abi.mk +# +# The target/library description file is already included. +# Hence, the LIBS variable contains the library dependencies. +# + +.NOTPARALLEL: + +## +# Return path to symbol file for a given library name +# +_symbol_file = $(firstword $(wildcard $(addsuffix /$1,\ + $(foreach REP,$(REPOSITORIES),$(REP)/lib/symbols)))) + +include $(LIB_PROGRESS_LOG) + +# +# Categorize LIBS into ABIs and actual libraries. Dependencies of libraries +# must be recursively discovered whereas ABIs don't have any dependencies. +# + +# +# Pattern rules for generating ABI and library dependencies for var/libdeps +# + +generate_abi_dep.%: log_progress + $(VERBOSE_MK)$(MAKE) $(VERBOSE_DIR) -f $(BASE_DIR)/mk/dep_abi.mk SYMBOLS=$(call _symbol_file,$*) + +generate_lib_dep.%: log_progress + $(VERBOSE_MK)$(MAKE) $(VERBOSE_DIR) -f $(BASE_DIR)/mk/dep_lib.mk REP_DIR=$(REP_DIR) LIB=$* + +generate_missing_ports: + $(if $(DEP_MISSING_PORTS),\ + @echo "MISSING_PORTS += $(DEP_MISSING_PORTS)" >> $(LIB_DEP_FILE),\ + @true) + +generate_dep_lists: + @(echo "$(DEP_A_VAR_NAME) = $(foreach l,$(LIBS),\$${ARCHIVE_NAME($l)} \$$(DEP_A_$l))"; \ + echo "$(DEP_SO_VAR_NAME) = $(foreach l,$(LIBS),\$${SO_NAME($l)} \$$(DEP_SO_$l))"; \ + echo "") >> $(LIB_DEP_FILE) + +log_progress: + +generate: log_progress +generate: generate_missing_ports + +_unvisited_libs = $(filter-out $(LIBS_READY),$1) +_abis_to_visit = $(foreach L,$(call _unvisited_libs,$1),$(if $(call _symbol_file,$L),$L)) +_libs_to_visit = $(filter-out $(call _abis_to_visit,$1),$(call _unvisited_libs,$1)) +deps_for_libs = $(addprefix generate_abi_dep.,$(call _abis_to_visit,$1)) \ + $(addprefix generate_lib_dep.,$(call _libs_to_visit,$1)) \ + $(if $1,generate_dep_lists) + +UNSATISFIED_REQUIREMENTS = $(filter-out $(SPECS),$(REQUIRES)) diff --git a/repos/base/mk/dep_abi.mk b/repos/base/mk/dep_abi.mk new file mode 100644 index 0000000000..8ef56259b7 --- /dev/null +++ b/repos/base/mk/dep_abi.mk @@ -0,0 +1,35 @@ +# +# The following variables must be defined by the caller: +# +# SYMBOLS - path to symbols file +# LIB_PROGRESS_LOG - record of visited ABIs +# LIB_DEP_FILE - destination Makefile for ABI-creation rule +# + +override LIB := $(notdir $(SYMBOLS)) + +all: + @true + +include $(BASE_DIR)/mk/dep.inc +include $(LIB_PROGRESS_LOG) + +ifeq ($(filter $(ABIS_READY),$(LIB)),) +all: generate +endif + +log_progress: + @echo "ABIS_READY += $(LIB)" >> $(LIB_PROGRESS_LOG) + +generate: + @(echo "SO_NAME($(LIB)) := $(LIB).lib.so"; \ + echo "$(LIB).lib.a:"; \ + echo " @true"; \ + echo "$(LIB).abi.so:"; \ + echo " \$$(VERBOSE)\$$(call _prepare_lib_step,\$$@,$(LIB),)"; \ + echo " \$$(VERBOSE_MK)\$$(MAKE) \$$(VERBOSE_DIR) -C \$$(LIB_CACHE_DIR)/$(LIB) -f \$$(BASE_DIR)/mk/abi.mk \\"; \ + echo " SYMBOLS=$(SYMBOLS) \\"; \ + echo " LIB=$(LIB) \\"; \ + echo " BUILD_BASE_DIR=$(BUILD_BASE_DIR) \\"; \ + echo " SHELL=$(SHELL)"; \ + echo "") >> $(LIB_DEP_FILE) diff --git a/repos/base/mk/dep_lib.mk b/repos/base/mk/dep_lib.mk index fca6396daa..ea8fca65d6 100644 --- a/repos/base/mk/dep_lib.mk +++ b/repos/base/mk/dep_lib.mk @@ -1,73 +1,26 @@ # -# This file determines dependencies of a library from other libraries +# Determine dependencies of a library from other libraries # # The following variables must be defined by the caller: # -# VERBOSE - controls the make verboseness -# VERBOSE_DIR - verboseness of directory change messages -# VERBOSE_MK - verboseness of make calls -# REPOSITORIES - source code repositories to use -# BASE_DIR - base directory of build system repository -# TARGET_DIR - target build directory -# BUILD_BASE_DIR - build directory with build config -# LIB_CACHE_DIR - destination directory for object files -# LIB_PROGRESS_LOG - library build log file -# BUILD_LIBS - list of libraries to build (without .lib.a or .lib.so suffix) -# INSTALL_DIR - destination directory for installing shared libraries -# DEBUG_DIR - destination directory for installing unstripped shared libraries +# LIB - library name +# REPOSITORIES - repository directories to search for the library # ACCUMULATE_MISSING_PORTS = 1 -# -# Include common utility functions -# include $(BASE_DIR)/mk/util.inc -# -# Generate dependencies only for those libs that are -# not already contained in the library build log -# -include $(LIB_PROGRESS_LOG) -ifneq ($(filter $(LIB),$(LIBS_READY)),) -already_visited: +all: @true -else -all: append_lib_to_progress_log -endif - -append_lib_to_progress_log: - @echo "LIBS_READY += $(LIB)" >> $(LIB_PROGRESS_LOG) - - -LIB_MK_DIRS = $(foreach REP,$(REPOSITORIES),$(addprefix $(REP)/lib/mk/spec/, $(SPECS)) $(REP)/lib/mk) -SYMBOLS_DIRS = $(foreach REP,$(REPOSITORIES),$(addprefix $(REP)/lib/symbols/spec/,$(SPECS)) $(REP)/lib/symbols) - -# -# Of all possible file locations, use the (first) one that actually exist. -# -LIB_MK = $(firstword $(wildcard $(addsuffix /$(LIB).mk,$(LIB_MK_DIRS)))) -SYMBOLS = $(firstword $(wildcard $(addsuffix /$(LIB), $(SYMBOLS_DIRS)))) - -ifneq ($(SYMBOLS),) -SHARED_LIB := yes -endif - -# -# Sanity check to detect missing library-description file -# -ifeq ($(sort $(LIB_MK) $(SYMBOLS)),) -all: warn_missing_lib_mk -else -all: check_unsatisfied_requirements -endif - -warn_missing_lib_mk: generate_lib_rule_for_defect_library - @$(ECHO) "Library-description file $(DARK_COL)$(LIB).mk$(DEFAULT_COL) is missing" +LIB_MK := $(firstword $(wildcard $(addsuffix /$(LIB).mk,\ + $(foreach REP,$(REPOSITORIES),\ + $(addprefix $(REP)/lib/mk/spec/,$(SPECS))\ + $(REP)/lib/mk)))) # # Determine the repository base directory from the absolute pathname -# of the choosen libname.mk file. We need to specify the override +# of the chosen libname.mk file. We need to specify the override # command because REP_DIR was first set by prg.mk when building a # program target. The repository of a library could be a different # one. @@ -78,20 +31,31 @@ warn_missing_lib_mk: generate_lib_rule_for_defect_library override REP_DIR := $(firstword $(foreach REP,$(REPOSITORIES),$(findstring $(REP)/,$(LIB_MK)))) override REP_DIR := $(REP_DIR:/=) -include $(BASE_DIR)/mk/base-libs.mk include $(LIB_MK) +include $(BASE_DIR)/mk/dep.inc + +ifneq ($(UNSATISFIED_REQUIREMENTS),) +WARNING_SKIP := "Skip library $(LIB) because it requires '$(UNSATISFIED_REQUIREMENTS)'" +endif + +SYMBOLS := $(call _symbol_file,$(LIB)) + +# +# Sanity check to detect missing library-description file +# +ifeq ($(sort $(LIB_MK) $(SYMBOLS)),) +WARNING_SKIP := "Library-description file '$(LIB).mk' is missing" +endif + +ifneq ($(SYMBOLS),) +SHARED_LIB := yes +endif + ifdef SHARED_LIB BUILD_ARTIFACTS ?= $(LIB).lib.so endif -# record creation of shared library build artifact -append_artifact_to_progress_log: - @( $(foreach A,$(BUILD_ARTIFACTS),\ - echo -e "\n# Build artifact $A\n";) true \ - ) >> $(LIB_PROGRESS_LOG) -append_lib_to_progress_log: append_artifact_to_progress_log - ifdef SHARED_LIB LIBS += ldso_so_support endif @@ -111,40 +75,38 @@ DEP_SO_VAR_NAME := DEP_SO_$(LIB) endif # -# Check if the requirements of the target are satisfied +# Trigger the rule generation for the ABI of this library # -UNSATISFIED_REQUIREMENTS = $(filter-out $(SPECS),$(REQUIRES)) -ifneq ($(UNSATISFIED_REQUIREMENTS),) -check_unsatisfied_requirements: warn_unsatisfied_requirements -else -check_unsatisfied_requirements: generate_lib_rule +ifdef SHARED_LIB +ifneq ($(SYMBOLS),) +generate: generate_abi_dep.$(LIB) +endif endif -warn_unsatisfied_requirements: generate_lib_rule_for_defect_library - @$(ECHO) "Skip library $(LIB) because it requires $(DARK_COL)$(UNSATISFIED_REQUIREMENTS)$(DEFAULT_COL)" +ifeq ($(filter $(LIBS_READY),$(LIB)),) +all: $(if $(WARNING_SKIP),generate_skip,generate) +endif -generate_lib_rule_for_defect_library: +log_progress: + @echo "LIBS_READY += $(LIB)" >> $(LIB_PROGRESS_LOG) + +generate_skip: + @echo $(WARNING_SKIP) @(echo "INVALID_DEPS += $(LIB)"; \ - echo "$(LIB).lib:"; \ + echo "$(LIB).lib.a $(LIB).lib.so:"; \ echo "") >> $(LIB_DEP_FILE) -LIBS_TO_VISIT = $(filter-out $(LIBS_READY),$(LIBS)) - -generate_lib_rule: -ifneq ($(DEP_MISSING_PORTS),) - @(echo "MISSING_PORTS += $(DEP_MISSING_PORTS)"; \ - echo "") >> $(LIB_DEP_FILE) +generate: $(call deps_for_libs,$(LIBS)) +ifdef SHARED_LIB +ifeq ($(SYMBOLS),) # if no symbols exist, the shared object is the ABI + @(echo "SO_NAME($(LIB)) := $(LIB).lib.so"; \ + echo "$(LIB).abi.so: $(LIB).lib.so"; \ + echo "$(LIB).lib.a:"; \ + echo " @true"; ) >> $(LIB_DEP_FILE) endif - @for i in $(LIBS_TO_VISIT); do \ - $(MAKE) $(VERBOSE_DIR) -f $(BASE_DIR)/mk/dep_lib.mk REP_DIR=$(REP_DIR) LIB=$$i; done -ifneq ($(LIBS),) - @(echo "$(DEP_A_VAR_NAME) = $(foreach l,$(LIBS),\$${ARCHIVE_NAME($l)} \$$(DEP_A_$l))"; \ - echo "$(DEP_SO_VAR_NAME) = $(foreach l,$(LIBS),\$${SO_NAME($l)} \$$(DEP_SO_$l))"; \ - echo "") >> $(LIB_DEP_FILE) -endif - @(echo "$(LIB).lib: check_ports $(addsuffix .lib,$(LIBS))"; \ - echo " @\$$(MKDIR) -p \$$(LIB_CACHE_DIR)/$(LIB)"; \ - echo " \$$(VERBOSE_MK)\$$(MAKE) $(VERBOSE_DIR) -C \$$(LIB_CACHE_DIR)/$(LIB) -f \$$(BASE_DIR)/mk/lib.mk \\"; \ + @(echo "$(LIB).lib.so: check_ports $(if $(SYMBOLS),$(LIB).abi.so) $(addsuffix .lib.a,$(LIBS)) $(addsuffix .abi.so,$(LIBS))"; \ + echo " \$$(VERBOSE)\$$(call _prepare_lib_step,\$$@,$(LIB),$(BUILD_ARTIFACTS))"; \ + echo " \$$(VERBOSE_MK)\$$(MAKE) \$$(VERBOSE_DIR) -C \$$(LIB_CACHE_DIR)/$(LIB) -f \$$(BASE_DIR)/mk/so.mk \\"; \ echo " REP_DIR=$(REP_DIR) \\"; \ echo " LIB_MK=$(LIB_MK) \\"; \ echo " SYMBOLS=$(SYMBOLS) \\"; \ @@ -156,11 +118,22 @@ endif echo " INSTALL_DIR=\$$(INSTALL_DIR) \\"; \ echo " DEBUG_DIR=\$$(DEBUG_DIR)"; \ echo "") >> $(LIB_DEP_FILE) -ifdef SHARED_LIB - @(echo "SO_NAME($(LIB)) := $(LIB).lib.so"; \ - echo "") >> $(LIB_DEP_FILE) -else - @(echo "ARCHIVE_NAME($(LIB)) := $(LIB).lib.a"; \ +else # not SHARED_LIB + @(echo "$(LIB).lib.a: check_ports $(addsuffix .lib.a,$(LIBS)) $(addsuffix .abi.so,$(LIBS))"; \ + echo " \$$(VERBOSE)\$$(call _prepare_lib_step,\$$@,$(LIB),$(BUILD_ARTIFACTS))"; \ + echo " \$$(VERBOSE_MK)\$$(MAKE) \$$(VERBOSE_DIR) -C \$$(LIB_CACHE_DIR)/$(LIB) -f \$$(BASE_DIR)/mk/a.mk \\"; \ + echo " REP_DIR=$(REP_DIR) \\"; \ + echo " LIB_MK=$(LIB_MK) \\"; \ + echo " LIB=$(LIB) \\"; \ + echo " ARCHIVES=\"\$$(sort \$$($(DEP_A_VAR_NAME)))\" \\"; \ + echo " SHARED_LIBS=\"\$$(sort \$$($(DEP_SO_VAR_NAME)))\" \\"; \ + echo " BUILD_BASE_DIR=$(BUILD_BASE_DIR) \\"; \ + echo " SHELL=$(SHELL) \\"; \ + echo " INSTALL_DIR=\$$(INSTALL_DIR) \\"; \ + echo " DEBUG_DIR=\$$(DEBUG_DIR)"; \ + echo "$(LIB).lib.so $(LIB).abi.so:"; \ + echo " @true"; \ + echo "ARCHIVE_NAME($(LIB)) := $(LIB).lib.a"; \ echo "") >> $(LIB_DEP_FILE) endif diff --git a/repos/base/mk/dep_prg.mk b/repos/base/mk/dep_prg.mk index 6901266f6a..cb2895d09d 100644 --- a/repos/base/mk/dep_prg.mk +++ b/repos/base/mk/dep_prg.mk @@ -1,21 +1,29 @@ # -# Prevent execution of any rule contained in $(TARGET_MK) as default rule +# Determine library dependencies of a program # -all: ACCUMULATE_MISSING_PORTS = 1 -# -# Include common utility functions -# include $(BASE_DIR)/mk/util.inc +all: + @true + # # Include target build instructions to aquire library dependecies # PRG_DIR := $(dir $(TARGET_MK)) + include $(TARGET_MK) +# +# Check if the requirements of the target are satisfied +# +UNSATISFIED_REQUIREMENTS = $(filter-out $(SPECS),$(REQUIRES)) +ifneq ($(UNSATISFIED_REQUIREMENTS),) +WARNING_SKIP := "Skip library $(LIB) because it requires '$(UNSATISFIED_REQUIREMENTS)'" +endif + # # Add libgcov if coverage is requested # @@ -40,6 +48,14 @@ include $(foreach LIB,$(LIBS),$(call select_from_repositories,lib/import/import- # include $(SPEC_FILES) +# +# Evaluate library dependencies for this target +# +include $(BASE_DIR)/mk/dep.inc + +DEP_A_VAR_NAME := DEP_A_$(TARGET).prg +DEP_SO_VAR_NAME := DEP_SO_$(TARGET).prg + # # Names of build artifacts to appear in the 'progress.log' # @@ -51,37 +67,18 @@ BUILD_ARTIFACTS ?= $(TARGET) PRG_REL_DIR := $(subst $(REP_DIR)/src/,,$(PRG_DIR)) PRG_REL_DIR := $(PRG_REL_DIR:/=) -# -# Prevent generation of program rule if requirements are unsatisfied -# -UNSATISFIED_REQUIREMENTS = $(filter-out $(SPECS),$(REQUIRES)) ifneq ($(UNSATISFIED_REQUIREMENTS),) -all: - @$(ECHO) "Skip target $(PRG_REL_DIR) because it requires $(DARK_COL)$(UNSATISFIED_REQUIREMENTS)$(DEFAULT_COL)" -else -all: gen_prg_rule +WARNING_SKIP := "Skip target $(PRG_REL_DIR) because it requires '$(UNSATISFIED_REQUIREMENTS)'" endif -include $(LIB_PROGRESS_LOG) -LIBS_TO_VISIT = $(filter-out $(LIBS_READY),$(LIBS)) +all: $(if $(WARNING_SKIP),generate_skip,generate) -# -# Generate program rule -# -gen_prg_rule: append_artifact_to_progress_log -ifneq ($(LIBS),) - @for i in $(LIBS_TO_VISIT); do \ - $(MAKE) $(VERBOSE_DIR) -f $(BASE_DIR)/mk/dep_lib.mk REP_DIR=$(REP_DIR) LIB=$$i; done - @(echo "DEP_A_$(TARGET).prg = $(foreach l,$(LIBS),\$${ARCHIVE_NAME($l)} \$$(DEP_A_$l))"; \ - echo "DEP_SO_$(TARGET).prg = $(foreach l,$(LIBS),\$${SO_NAME($l)} \$$(DEP_SO_$l))"; \ - echo "") >> $(LIB_DEP_FILE) -endif -ifneq ($(DEP_MISSING_PORTS),) - @(echo "MISSING_PORTS += $(DEP_MISSING_PORTS)"; \ - echo "") >> $(LIB_DEP_FILE) -endif - @(echo "$(TARGET).prg: check_ports $(addsuffix .lib,$(LIBS))"; \ - echo " @\$$(MKDIR) -p $(PRG_REL_DIR)"; \ +generate_skip: + @echo $(WARNING_SKIP) + +generate: $(call deps_for_libs,$(LIBS)) + @(echo "$(TARGET).prg: check_ports $(addsuffix .lib.a,$(LIBS)) $(addsuffix .abi.so,$(LIBS))"; \ + echo " \$$(VERBOSE)\$$(call _prepare_prg_step,$(PRG_REL_DIR)/$(TARGET),$(BUILD_ARTIFACTS))"; \ echo " \$$(VERBOSE_MK)\$$(MAKE) $(VERBOSE_DIR) -C $(PRG_REL_DIR) -f \$$(BASE_DIR)/mk/prg.mk \\"; \ echo " REP_DIR=$(REP_DIR) \\"; \ echo " PRG_REL_DIR=$(PRG_REL_DIR) \\"; \ @@ -116,8 +113,3 @@ ifeq ($(FORCE_BUILD_LIBS),yes) @(echo ""; \ echo "all: \$$(addsuffix .lib,\$$(filter-out \$$(INVALID_DEPS), $(LIBS)))") >> $(LIB_DEP_FILE) endif - -append_artifact_to_progress_log: - @( $(foreach A,$(BUILD_ARTIFACTS),\ - echo -e "\n# Build artifact $A\n";) true \ - ) >> $(LIB_PROGRESS_LOG) diff --git a/repos/base/mk/generic.mk b/repos/base/mk/generic.mk index 599e4839a5..c8f3b19eb2 100644 --- a/repos/base/mk/generic.mk +++ b/repos/base/mk/generic.mk @@ -10,6 +10,17 @@ SRC_O += $(addprefix binary_,$(addsuffix .o,$(notdir $(SRC_BIN)))) SRC = $(sort $(SRC_C) $(SRC_CC) $(SRC_ADB) $(SRC_ADS) $(SRC_RS) $(SRC_S) $(SRC_O) $(SRC_GO)) OBJECTS = $(addsuffix .o,$(basename $(SRC))) +# +# Hook for incorporating source code generated by post-processing object +# files. The source code must be generated after building 'OBJECTS'. But +# the object file(s) resulting from the generated code must be linked. +# Hence, 'OBJECTS' is expanded after the dependency definition. +# +ifneq ($(OBJ_POSTPROC_SRC),) +$(OBJ_POSTPROC_SRC) : $(OBJECTS) +OBJECTS += $(addsuffix .o,$(basename $(OBJ_POSTPROC_SRC))) +endif + # # Create sub directories for objects files corresponding to the sub directories # of their respective source files @@ -87,7 +98,7 @@ endif # We need to override these to build the ada runtime # CUSTOM_ADA_FLAGS ?= --RTS=$(ADA_RTS) -CUSTOM_ADA_OPT ?= $(CC_ADA_OPT) -gnatef +CUSTOM_ADA_OPT ?= $(CC_ADA_OPT) -gnatef -gnatwG CUSTOM_ADA_INCLUDE ?= -I- $(INCLUDES) # @@ -133,42 +144,6 @@ binary_%.o: % $(VERBOSE)echo ".global $(symbol_name)_start, $(symbol_name)_end; .data; .align 4; $(symbol_name)_start:; .incbin \"$<\"; $(symbol_name)_end:" |\ $(AS) $(AS_OPT) -f -o $@ - -# -# Generate assembler file from symbol list -# -# For undefined symbols (type U), we create a hard dependency by referencing -# the symbols from the assembly file. The reference is created in the form of -# a '.long' value with the address of the symbol. On x86_64, this is not -# possible for PIC code. Hence, we reference the symbol via a PIC-compatible -# movq instruction instead. -# -# If we declared the symbol as '.global' without using it, the undefined symbol -# gets discarded at link time unless it is directly referenced by the target. -# This is a problem in situations where the undefined symbol is resolved by an -# archive rather than the target. I.e., when linking posix.lib.a (which -# provides 'Libc::Component::construct'), the 'construct' function is merely -# referenced by the libc.lib.so's 'Component::construct' function. But this -# reference apparently does not suffice to keep the posix.lib.a's symbol. By -# adding a hard dependency, we force the linker to resolve the symbol and don't -# drop posix.lib.a. -# -ASM_SYM_DEPENDENCY := .long \1 -ifeq ($(filter-out $(SPECS),x86_64),) -ASM_SYM_DEPENDENCY := movq \1@GOTPCREL(%rip), %rax -endif - -%.symbols.s: %.symbols - $(MSG_CONVERT)$@ - $(VERBOSE)\ - sed -e "s/^\(\w\+\) D \(\w\+\)\$$/.data; .global \1; .type \1,%object; .size \1,\2; \1: .skip 1/" \ - -e "s/^\(\w\+\) V/.data; .weak \1; .type \1,%object; \1: .skip 1/" \ - -e "s/^\(\w\+\) T/.text; .global \1; .type \1,%function; \1:/" \ - -e "s/^\(\w\+\) R \(\w\+\)\$$/.section .rodata; .global \1; .type \1,%object; .size \1,\2; \1:/" \ - -e "s/^\(\w\+\) W/.text; .weak \1; .type \1,%function; \1:/" \ - -e "s/^\(\w\+\) B \(\w\+\)\$$/.bss; .global \1; .type \1,%object; .size \1,\2; \1:/" \ - -e "s/^\(\w\+\) U/.text; .global \1; $(ASM_SYM_DEPENDENCY)/" \ - $< > $@ - # # Create local symbol links for the used shared libraries # @@ -182,8 +157,8 @@ endif # time a user of the library is linked, the ABI stub should be used instead of # the library. # -select_so = $(firstword $(wildcard $(LIB_CACHE_DIR)/$(1:.lib.so=)/$(1:.lib.so=).abi.so \ - $(LIB_CACHE_DIR)/$(1:.lib.so=)/$(1:.lib.so=).lib.so)) +select_so = $(firstword $(wildcard $(LIB_CACHE_DIR)/$(1:.lib.so=)/$(1:.lib.so=).abi.so) \ + $(LIB_CACHE_DIR)/$(1:.lib.so=)/$(1:.lib.so=).lib.so) ifneq ($(filter-out $(foreach s,$(SHARED_LIBS),$(realpath $s)), \ $(foreach s,$(SHARED_LIBS),$(call select_so,$s))),) diff --git a/repos/base/mk/global.mk b/repos/base/mk/global.mk index 75cfaff415..6d0dc55043 100644 --- a/repos/base/mk/global.mk +++ b/repos/base/mk/global.mk @@ -124,6 +124,12 @@ endif CC_OPT += -fprofile-arcs -ftest-coverage -fprofile-dir=$(PROFILE_DIR) endif +ifneq ($(findstring /depot/,$(CURDIR)),) +DEBUG_PREFIX = $(shell echo $(CURDIR) | \ + sed -e 's|/depot/.*$$|/depot/|') +CC_OPT += -fdebug-prefix-map=$(DEBUG_PREFIX)=/depot/ +endif + # # Enable the undefined behavior sanitizer if requested # @@ -195,7 +201,7 @@ CC_ADA_OPT += $(filter-out -fno-builtin-cos -fno-builtin-sin \ # We substitute '.' characters by '_' to allow a source-file-specific # C++ standard option for files with more than one dot in their name. # -CC_CXX_OPT_STD ?= -std=gnu++17 +CC_CXX_OPT_STD ?= -std=gnu++20 CC_CXX_OPT += $(lastword $(CC_CXX_OPT_STD) $(CC_CXX_OPT_STD_$(subst .,_,$*))) # @@ -211,8 +217,9 @@ CC_CXX_OPT += $(lastword $(CC_CXX_OPT_STD) $(CC_CXX_OPT_STD_$(subst .,_,$*))) # LD_OPT_GC_SECTIONS ?= -gc-sections LD_OPT_ALIGN_SANE = -z max-page-size=0x1000 +LD_OPT_NX_STACK = -z noexecstack LD_OPT_PREFIX := -Wl, -LD_OPT += $(LD_MARCH) $(LD_OPT_GC_SECTIONS) $(LD_OPT_ALIGN_SANE) +LD_OPT += $(LD_MARCH) $(LD_OPT_GC_SECTIONS) $(LD_OPT_ALIGN_SANE) $(LD_OPT_NX_STACK) CXX_LINK_OPT += $(addprefix $(LD_OPT_PREFIX),$(LD_OPT)) CXX_LINK_OPT += $(LD_OPT_NOSTDLIB) @@ -238,14 +245,9 @@ LD_SCRIPT_SO ?= $(BASE_DIR)/src/ld/genode_rel.ld AS_OPT += $(AS_MARCH) # -# Control sequences for color terminals +# Default tar options # -# To disable colored output, define these variable empty in your -# build-local 'etc/tools.conf' file. -# -BRIGHT_COL ?= \033[01;33m -DARK_COL ?= \033[00;33m -DEFAULT_COL ?= \033[0m +TAR_OPT ?= --owner=1 --group=1 --mtime=@0 ALL_INC_DIR := . ALL_INC_DIR += $(INC_DIR) @@ -267,6 +269,4 @@ MSG_CONFIG ?= @$(ECHO) " CONFIG " MSG_CLEAN ?= @$(ECHO) " CLEAN " MSG_ASSEM ?= @$(ECHO) " ASSEMBLE " MSG_INST ?= @$(ECHO) " INSTALL " -MSG_PRG ?= @$(ECHO) "$(BRIGHT_COL) Program $(DEFAULT_COL)" -MSG_LIB ?= @$(ECHO) "$(DARK_COL) Library $(DEFAULT_COL)" diff --git a/repos/base/mk/lib.mk b/repos/base/mk/lib.mk deleted file mode 100644 index 75317fb651..0000000000 --- a/repos/base/mk/lib.mk +++ /dev/null @@ -1,253 +0,0 @@ -## -## Rules for building a library target -## -## The following variables must be passed when calling this file: -## -## BASE_DIR - base directory of the build system -## REPOSITORIES - repositories providing libs and headers -## VERBOSE - build verboseness modifier -## VERBOSE_DIR - verboseness modifier for changing directories -## VERBOSE_MK - verboseness of make calls -## BUILD_BASE_DIR - base of build directory tree -## LIB_CACHE_DIR - library build cache location -## INSTALL_DIR - installation directory for stripped shared objects -## DEBUG_DIR - installation directory for unstripped shared objects -## SHARED_LIBS - shared-library dependencies of the library -## ARCHIVES - archive dependencies of the library -## REP_DIR - repository where the library resides -## CONTRIB_DIR - location of ported 3rd-party source codes -## - -include $(BASE_DIR)/mk/base-libs.mk - -# -# Prevent .mk rules to be executed as default rule -# -all: - -# -# Include common utility functions -# -include $(BASE_DIR)/mk/util.inc - -# -# Include specifics, for example platform, kernel-api etc. -# -include $(SPEC_FILES) - -# -# Include library build instructions -# -# We set the 'called_from_lib_mk' variable to allow the library description file -# to respond to the build pass. -# -BACKUP_INC_DIR := $(INC_DIR) -called_from_lib_mk = yes -include $(LIB_MK) - -# -# Sanity check for INC_DIR overrides -# -ifneq ($(filter-out $(INC_DIR),$(BACKUP_INC_DIR)),) -all: error_inc_dir_override -endif - -error_inc_dir_override: - @$(ECHO) "Error: $(LIB_MK) overrides INC_DIR instead of appending" ; false - -# -# Include lib-import descriptions of all used libraries and the target library -# -include $(foreach LIB,$(LIBS),$(call select_from_repositories,lib/import/import-$(LIB).mk)) - -# -# Include global definitions -# -include $(BASE_DIR)/mk/global.mk - -ifneq ($(SYMBOLS),) -SHARED_LIB := yes -endif - -# -# If a symbol list is provided, we create an ABI stub named '.abi.so' -# -# The ABI-stub library does not contain any code or data but only the symbol -# information of the binary interface (ABI) of the shared library. -# -# The ABI stub is linked by the users of the library (executables or shared -# objects) instead of the real library. This effectively decouples the library -# users from the concrete library instance but binds them merely to the -# library's binary interface. Note that the ABI stub is not used at runtime at -# all. At runtime, the real library that implements the ABI is loaded by the -# dynamic linker. -# -# The symbol information are incorporated into the ABI stub via an assembly -# file named '.symbols.s' that is generated from the library's symbol -# list. We create a symbolic link from the symbol file to the local directory. -# By using '.symbols' as file extension, the pattern rule '%.symbols.s: -# %.symbols' defined in 'generic.mk' is automatically applied for creating the -# assembly file from the symbols file. -# -# The '.PRECIOUS' special target prevents make to remove the intermediate -# assembler file. Otherwise make would spill the build log with messages -# like "rm libc.symbols.s". -# -ifneq ($(SYMBOLS),) -ABI_SO := $(addsuffix .abi.so,$(LIB)) -ABI_SONAME := $(addsuffix .lib.so,$(LIB)) - -$(LIB).symbols: - $(VERBOSE)ln -sf $(SYMBOLS) $@ - -.PRECIOUS: $(LIB).symbols.s -endif - -# -# Link libgcc to shared libraries -# -# For static libraries, libgcc is not needed because it will be linked -# against the final target. -# -ifdef SHARED_LIB -LIBGCC = $(shell $(CC) $(CC_MARCH) -print-libgcc-file-name) -endif - -# -# Print message for the currently built library -# -all: message - -message: - $(MSG_LIB)$(LIB) - -include $(BASE_DIR)/mk/generic.mk - -# -# Name of .lib.a or .lib.so file to create -# -# Skip the creation and installation of an .so file if there are no -# ingredients. This is the case if the library is present as ABI only. -# -ifdef SHARED_LIB - ifneq ($(sort $(OBJECTS) $(LIBS)),) - LIB_SO := $(addsuffix .lib.so,$(LIB)) - INSTALL_SO := $(INSTALL_DIR)/$(LIB_SO) - DEBUG_SO := $(DEBUG_DIR)/$(LIB_SO) - endif -else -LIB_A := $(addsuffix .lib.a,$(LIB)) -endif - -# -# Whenever an ABI is defined for a shared library, we check the consistency -# between both by invoking the 'check_abi' tool via the 'LIB_CHECKED' -# dependency. -# -ifneq ($(LIB_SO),) - ifneq ($(ABI_SO),) - LIB_CHECKED := $(addsuffix .lib.checked,$(LIB)) - endif -endif - -# -# Trigger the creation of the .lib.a or .lib.so file -# -LIB_TAG := $(addsuffix .lib.tag,$(LIB)) -all: $(LIB_TAG) - -# -# Trigger the build of host tools -# -# We make '$(LIB_TAG)' depend on the host tools to support building host tools -# from pseudo libraries with no actual source code. In this case '$(OBJECTS)' -# is empty. -# -$(LIB_TAG) $(OBJECTS): $(HOST_TOOLS) - -# -# Trigger build of additional library specific targets -# -$(LIB_TAG): $(CUSTOM_TARGET_DEPS) - -$(LIB_TAG): $(LIB_A) $(LIB_SO) $(LIB_CHECKED) $(ABI_SO) $(INSTALL_SO) $(DEBUG_SO) - @touch $@ - -# -# Rule to build the .lib.a file -# -# Use $(OBJECTS) instead of $^ for specifying the list of objects to include -# in the archive because $^ may also contain non-object phony targets, e.g., -# used by the integration of Qt's meta-object compiler into the Genode -# build system. -# -$(LIB_A): $(OBJECTS) - $(MSG_MERGE)$(LIB_A) - $(VERBOSE)$(RM) -f $@ - $(VERBOSE)$(AR) -rcs $@ $(OBJECTS) - -# -# Link ldso-support library to each shared library to provide local hook -# functions for constructors and ARM -# -ifdef SHARED_LIB -override ARCHIVES += ldso_so_support.lib.a -endif - -# -# Don't link base libraries against shared libraries except for ld.lib.so -# -ifneq ($(LIB_IS_DYNAMIC_LINKER),yes) -override ARCHIVES := $(filter-out $(BASE_LIBS:=.lib.a),$(ARCHIVES)) -endif - -# -# The 'sort' is needed to ensure the same link order regardless -# of the find order, which uses to vary among different systems. -# -STATIC_LIBS := $(sort $(foreach l,$(ARCHIVES:.lib.a=),$(LIB_CACHE_DIR)/$l/$l.lib.a)) -STATIC_LIBS_BRIEF := $(subst $(LIB_CACHE_DIR),$$libs,$(STATIC_LIBS)) - -# -# Rule to build the .lib.so file -# -# When linking the shared library, we have to link all shared sub libraries -# (LIB_SO_DEPS) to the library to store the library-dependency information in -# the generated shared object. -# - -# -# Default entry point of shared libraries -# -ENTRY_POINT ?= 0x0 - -$(LIB_SO): $(SHARED_LIBS) - -$(LIB_SO): $(STATIC_LIBS) $(OBJECTS) $(wildcard $(LD_SCRIPT_SO)) $(LIB_SO_DEPS) - $(MSG_MERGE)$(LIB_SO) - $(VERBOSE)libs=$(LIB_CACHE_DIR); $(LD) -o $(LIB_SO) -shared --eh-frame-hdr \ - $(LD_OPT) -T $(LD_SCRIPT_SO) --entry=$(ENTRY_POINT) \ - --whole-archive --start-group \ - $(SHARED_LIBS) $(STATIC_LIBS_BRIEF) $(OBJECTS) \ - --end-group --no-whole-archive \ - $(LIBGCC) - -$(ABI_SO): $(LIB).symbols.o - $(MSG_MERGE)$(ABI_SO) - $(VERBOSE)$(LD) -o $(ABI_SO) -soname=$(ABI_SONAME) -shared --eh-frame-hdr $(LD_OPT) \ - -T $(LD_SCRIPT_SO) \ - --whole-archive --start-group \ - $(LIB_SO_DEPS) $< \ - --end-group --no-whole-archive - -$(LIB_CHECKED): $(LIB_SO) $(SYMBOLS) - $(VERBOSE)$(BASE_DIR)/../../tool/check_abi $(LIB_SO) $(SYMBOLS) && touch $@ - -$(LIB_SO).stripped: $(LIB_SO) - $(VERBOSE)$(STRIP) -o $@ $< - -$(DEBUG_SO): $(LIB_SO) - $(VERBOSE)ln -sf $(CURDIR)/$< $@ - -$(INSTALL_SO): $(LIB_SO).stripped - $(VERBOSE)ln -sf $(CURDIR)/$< $@ diff --git a/repos/base/mk/prg.mk b/repos/base/mk/prg.mk index 3285274a33..73ff33b300 100644 --- a/repos/base/mk/prg.mk +++ b/repos/base/mk/prg.mk @@ -73,21 +73,17 @@ endif include $(BASE_DIR)/mk/generic.mk include $(BASE_DIR)/mk/base-libs.mk -all: message $(TARGET) +all: $(TARGET) ifneq ($(INSTALL_DIR),) ifneq ($(DEBUG_DIR),) -all: message $(INSTALL_DIR)/$(TARGET) $(DEBUG_DIR)/$(TARGET) +all: $(INSTALL_DIR)/$(TARGET) $(DEBUG_DIR)/$(TARGET) $(DEBUG_DIR)/$(TARGET).debug endif endif all: @true # prevent nothing-to-be-done message -.PHONY: message -message: - $(MSG_PRG)$(PRG_REL_DIR)/$(TARGET) - # # Enforce unconditional call of gnatmake rule when compiling Ada sources # @@ -213,14 +209,18 @@ endif # $(TARGET). # ifneq ($(OBJECTS),) -$(TARGET): $(LINK_ITEMS) $(wildcard $(LD_SCRIPTS)) $(LIB_SO_DEPS) +$(TARGET): $(LINK_ITEMS) $(wildcard $(LD_SCRIPTS)) $(MSG_LINK)$(TARGET) $(VERBOSE)libs=$(LIB_CACHE_DIR); $(LD_CMD) -o $@ STRIP_TARGET_CMD ?= $(STRIP) -o $@ $< -$(TARGET).stripped: $(TARGET) +$(TARGET).debug: $(TARGET) + $(VERBOSE)$(OBJCOPY) --only-keep-debug $< $@ + +$(TARGET).stripped: $(TARGET) $(TARGET).debug $(VERBOSE)$(STRIP_TARGET_CMD) + $(VERBOSE)$(OBJCOPY) --add-gnu-debuglink=$(TARGET).debug $@ $(INSTALL_DIR)/$(TARGET): $(TARGET).stripped $(VERBOSE)ln -sf $(CURDIR)/$< $@ @@ -230,7 +230,9 @@ ifeq ($(COVERAGE),yes) endif ifneq ($(DEBUG_DIR),) -$(DEBUG_DIR)/$(TARGET): $(TARGET) +$(DEBUG_DIR)/$(TARGET): $(TARGET).stripped + $(VERBOSE)ln -sf $(CURDIR)/$< $@ +$(DEBUG_DIR)/$(TARGET).debug: $(TARGET).debug $(VERBOSE)ln -sf $(CURDIR)/$< $@ endif @@ -238,12 +240,13 @@ else $(TARGET): $(INSTALL_DIR)/$(TARGET): $(TARGET) $(DEBUG_DIR)/$(TARGET): $(TARGET) +$(DEBUG_DIR)/$(TARGET).debug: $(TARGET) endif clean_prg_objects: $(MSG_CLEAN)$(PRG_REL_DIR) - $(VERBOSE)$(RM) -f $(OBJECTS) $(OBJECTS:.o=.d) $(TARGET) $(TARGET).stripped $(BINDER_SRC) + $(VERBOSE)$(RM) -f $(OBJECTS) $(OBJECTS:.o=.d) $(TARGET) $(TARGET).stripped $(TARGET).debug $(BINDER_SRC) $(VERBOSE)$(RM) -f *.d *.i *.ii *.s *.ali *.lib.so clean: clean_prg_objects diff --git a/repos/base/mk/so.mk b/repos/base/mk/so.mk new file mode 100644 index 0000000000..76270a4ab5 --- /dev/null +++ b/repos/base/mk/so.mk @@ -0,0 +1,179 @@ +## +## Rules for building a shared object (.lib.so) +## +## The expected variables correspond to those documented in a.mk, with +## the following addition: +## +## SYMBOLS - path of symbols file +## + +LIB_SO := $(addsuffix .lib.so,$(LIB)) + +include $(BASE_DIR)/mk/base-libs.mk + +# +# Prevent .mk rules to be executed as default rule +# +all: + @true # prevent nothing-to-be-done message + +# +# Include common utility functions +# +include $(BASE_DIR)/mk/util.inc + +# +# Include specifics, for example platform, kernel-api etc. +# +include $(SPEC_FILES) + +ORIG_INC_DIR := $(INC_DIR) + +# +# Include library build instructions +# +# We set the 'called_from_lib_mk' variable to allow the library description file +# to respond to the build pass. +# +called_from_lib_mk = yes +include $(LIB_MK) + +# +# Include lib-import descriptions of all used libraries and the target library +# +include $(foreach LIB,$(LIBS),$(call select_from_repositories,lib/import/import-$(LIB).mk)) + +# +# Sanity check for INC_DIR overrides +# +ifneq ($(filter-out $(INC_DIR),$(ORIG_INC_DIR)),) +all: error_inc_dir_override +endif + +error_inc_dir_override: + @$(ECHO) "Error: INC_DIR overridden instead of appended" ; false + +# +# Include global definitions +# +include $(BASE_DIR)/mk/global.mk +include $(BASE_DIR)/mk/generic.mk + +# +# Link libgcc to shared libraries +# +# For static libraries, libgcc is not needed because it will be linked +# against the final target. +# +LIBGCC = $(shell $(CC) $(CC_MARCH) -print-libgcc-file-name) + +# +# Name of .lib.a or .lib.so file to create +# +# Skip the creation and installation of an .so file if there are no +# ingredients. This is the case if the library is present as ABI only. +# +ifneq ($(sort $(OBJECTS) $(LIBS)),) +ABI_SO := $(wildcard $(addsuffix .abi.so,$(LIB))) +INSTALL_SO := $(INSTALL_DIR)/$(LIB_SO) +DEBUG_SO := $(DEBUG_DIR)/$(LIB_SO) +LIB_SO_DEBUG := $(LIB_SO).debug +DEBUG_SO_DEBUG := $(DEBUG_SO).debug +endif + +# +# Whenever an ABI is defined for a shared library, we check the consistency +# between both by invoking the 'check_abi' tool via the 'LIB_CHECKED' +# dependency. +# +ifneq ($(LIB_SO),) + ifneq ($(ABI_SO),) + LIB_CHECKED := $(addsuffix .lib.checked,$(LIB)) + endif +endif + +# +# Trigger the creation of the .lib.so file +# +LIB_TAG := $(addsuffix .lib.tag,$(LIB)) +all: $(LIB_TAG) + +$(LIB_TAG): + @touch $@ + +# +# Trigger the build of host tools +# +# We make '$(LIB_TAG)' depend on the host tools to support building host tools +# from pseudo libraries with no actual source code. In this case '$(OBJECTS)' +# is empty. +# +$(LIB_TAG) $(OBJECTS): $(HOST_TOOLS) + +# +# Trigger build of additional library specific targets +# +$(LIB_TAG): $(CUSTOM_TARGET_DEPS) + +# +# Don't link shared object it BUILD_ARTIFACTS are declared as empty (ld.lib.so) +# +BUILD_ARTIFACTS ?= $(LIB).lib.so + +ifneq ($(BUILD_ARTIFACTS),) +$(LIB_TAG): $(LIB_SO) $(LIB_CHECKED) $(INSTALL_SO) $(DEBUG_SO) $(DEBUG_SO_DEBUG) +endif + +# +# Link ldso-support library to each shared library to provide local hook +# functions for constructors and ARM +# +override ARCHIVES += ldso_so_support.lib.a + +# +# Don't link base libraries against shared libraries except for ld.lib.so +# +ifneq ($(LIB_IS_DYNAMIC_LINKER),yes) +override ARCHIVES := $(filter-out $(BASE_LIBS:=.lib.a),$(ARCHIVES)) +endif + +# +# The 'sort' is needed to ensure the same link order regardless +# of the find order, which uses to vary among different systems. +# +STATIC_LIBS := $(sort $(foreach l,$(ARCHIVES:.lib.a=),$(LIB_CACHE_DIR)/$l/$l.lib.a)) +STATIC_LIBS_BRIEF := $(subst $(LIB_CACHE_DIR),$$libs,$(STATIC_LIBS)) + +ENTRY_POINT ?= 0x0 + +$(LIB_SO): $(SHARED_LIBS) + +$(LIB_SO): $(STATIC_LIBS) $(OBJECTS) $(wildcard $(LD_SCRIPT_SO)) + $(MSG_MERGE)$(LIB_SO) + $(VERBOSE)libs=$(LIB_CACHE_DIR); $(LD) -o $(LIB_SO) -soname=$(LIB_SO) -shared --eh-frame-hdr \ + $(LD_OPT) -T $(LD_SCRIPT_SO) --entry=$(ENTRY_POINT) \ + --whole-archive --start-group \ + $(SHARED_LIBS) $(STATIC_LIBS_BRIEF) $(OBJECTS) \ + --end-group --no-whole-archive \ + $(LIBGCC) + +$(ABI_SO): $(LD_SCRIPT_SO) + +$(LIB_CHECKED): $(LIB_SO) $(SYMBOLS) + $(VERBOSE)$(BASE_DIR)/../../tool/check_abi $(LIB_SO) $(SYMBOLS) && touch $@ + +$(LIB_SO_DEBUG): $(LIB_SO) + $(VERBOSE)$(OBJCOPY) --only-keep-debug $< $@ + +$(LIB_SO).stripped: $(LIB_SO) $(LIB_SO_DEBUG) + $(VERBOSE)$(STRIP) -o $@ $< + $(VERBOSE)$(OBJCOPY) --add-gnu-debuglink=$(LIB_SO_DEBUG) $@ + +$(INSTALL_SO): $(LIB_SO).stripped + $(VERBOSE)ln -sf $(CURDIR)/$< $@ + +$(DEBUG_SO): $(LIB_SO).stripped + $(VERBOSE)ln -sf $(CURDIR)/$< $@ + +$(DEBUG_SO_DEBUG): $(LIB_SO_DEBUG) + $(VERBOSE)ln -sf $(CURDIR)/$< $@ diff --git a/repos/base/mk/util.inc b/repos/base/mk/util.inc index 748c2d6930..affbd4d7c4 100644 --- a/repos/base/mk/util.inc +++ b/repos/base/mk/util.inc @@ -13,13 +13,19 @@ _assert = $(if $1,$1,$(error Error: $2)) # # We must not specify an '=' here. Even though the make documentation states # that the omission of '=' should be equivalent to '=', the behaviour is not -# the same. +# the same. Note, the result of the 'eval' function is always the empty string +# and, thus, it can be placed virtually anywhere in a makefile. # define _capture -$(eval $2 += $1) -$1 +$(eval $2 += $1)$1 endef +# +# Utility to read content from a file if it exists and the given file name +# is not empty. +# +_file_content = $(if $(wildcard $1),$(shell cat $1),) + # # Lookup port directory by a given port name # @@ -29,16 +35,13 @@ endef # its contained hash number to construct the path to the corresponding # subdirectory within CONTRIB_DIR. Finally, we check if the path exists. # -# When reading the hash file in the '_hash_of_port' function, we feed stdin -# to 'cat' to prevent 'cat' from blocking if the hash file is missing. -# # As a side effect of calling 'select_from_ports' we log the used hash file # in the 'PORT_HASH_FILES' variable. This enables us incorporate the hash file # as dependency for all object files. # _lookup_port_hash_file = $(wildcard $(addsuffix /ports/$1.hash,$(REPOSITORIES))) _capture_port_hash_file = $(call _capture,$(call _lookup_port_hash_file,$1),PORT_HASH_FILES) -_hash_of_port = $(shell echo | cat $(call _capture_port_hash_file,$1)) +_hash_of_port = $(call _file_content,$(call _capture_port_hash_file,$1)) _port_dir = $(wildcard $(CONTRIB_DIR)/$1-$(call _hash_of_port,$1)) # @@ -66,3 +69,8 @@ select_from_ports = $(call _checked_port_dir,$1) else select_from_ports = $(REP_DIR) endif + +# +# Utility to check for availability of a tool +# +check_tool = $(if $(shell command -v $(1)),,$(error Need to have '$(1)' installed.)) diff --git a/repos/base/ports/grub2.hash b/repos/base/ports/grub2.hash index 9bb012cc65..1c312c0143 100644 --- a/repos/base/ports/grub2.hash +++ b/repos/base/ports/grub2.hash @@ -1 +1 @@ -f15e84afbb47b892ed26a5ae56f5bb038777a3c0 +8c6a21b5e837a9491ebcb21611f5f865411544f5 diff --git a/repos/base/ports/grub2.port b/repos/base/ports/grub2.port index 8daa867699..8624760b78 100644 --- a/repos/base/ports/grub2.port +++ b/repos/base/ports/grub2.port @@ -3,9 +3,11 @@ VERSION := git DOWNLOADS := g2fg.git URL(g2fg) := https://github.com/alex-ab/g2fg.git -REV(g2fg) := 7da0601946bd2bb75f4e9c3b56cb18e44b2997a1 +REV(g2fg) := 95c79d8ca590eefaab7297c7a631125a64973266 DIR(g2fg) := boot default: $(DOWNLOADS) $(VERBOSE)tar -C boot -xJf boot/grub2.tar.xz $(VERBOSE)unxz -kf boot/grub2-head.img.xz + $(VERBOSE)unxz -kf boot/grub2-head-big.img.xz + $(VERBOSE)unxz -kf boot/font.pf2.xz diff --git a/repos/base/recipes/api/base/content.mk b/repos/base/recipes/api/base/content.mk index 38b16ebcb6..9835b241bf 100644 --- a/repos/base/recipes/api/base/content.mk +++ b/repos/base/recipes/api/base/content.mk @@ -13,7 +13,6 @@ lib: mkdir -p lib/mk lib/symbols cp $(addprefix $(REP_DIR)/lib/mk/,$(LIB_MK_FILES)) lib/mk/ cp $(REP_DIR)/lib/symbols/ld lib/symbols/ - touch lib/mk/config.mk sed -i "/KERNEL/d" lib/mk/ld.mk SPECS := x86_32 x86_64 32bit 64bit diff --git a/repos/base/recipes/api/base/hash b/repos/base/recipes/api/base/hash index 65319582e1..38c2481b49 100644 --- a/repos/base/recipes/api/base/hash +++ b/repos/base/recipes/api/base/hash @@ -1 +1 @@ -2022-10-11 1574044ae0ee33a9ad3bdadb3c487c47d4f45bff +2024-08-28 952cb023f90e6d847b6bfc8da87d8f7ba24f842c diff --git a/repos/base/recipes/api/timer_session/hash b/repos/base/recipes/api/timer_session/hash index 6c61c2e233..6c590b6270 100644 --- a/repos/base/recipes/api/timer_session/hash +++ b/repos/base/recipes/api/timer_session/hash @@ -1 +1 @@ -2022-08-16 1f83bc046ed3bb0c4fe6915e608d566dd5483e61 +2024-08-28 24b7ee7b276c08cb3b8673b7f63a2cf4edfdcddf diff --git a/repos/base/recipes/api/vm_session/hash b/repos/base/recipes/api/vm_session/hash index 9dd4d59a07..8bec13fedf 100644 --- a/repos/base/recipes/api/vm_session/hash +++ b/repos/base/recipes/api/vm_session/hash @@ -1 +1 @@ -2021-02-22 13c382561ce8f9c708dfe787dbba8bbf422930d2 +2024-08-28 bbb0046e1da2a0749048cbc273eb656867d85c1a diff --git a/repos/base/recipes/pkg/test-alarm/README b/repos/base/recipes/pkg/test-alarm/README new file mode 100644 index 0000000000..6cf8638c7b --- /dev/null +++ b/repos/base/recipes/pkg/test-alarm/README @@ -0,0 +1 @@ +Scenario that tests 'Genode::Alarm_registry' diff --git a/repos/base/recipes/pkg/test-alarm/archives b/repos/base/recipes/pkg/test-alarm/archives new file mode 100644 index 0000000000..a39876e781 --- /dev/null +++ b/repos/base/recipes/pkg/test-alarm/archives @@ -0,0 +1,2 @@ +_/src/init +_/src/test-alarm diff --git a/repos/base/recipes/pkg/test-alarm/hash b/repos/base/recipes/pkg/test-alarm/hash new file mode 100644 index 0000000000..e014853762 --- /dev/null +++ b/repos/base/recipes/pkg/test-alarm/hash @@ -0,0 +1 @@ +2024-08-28 38800f3da875e5de6f2d561358fa8f56c85a7b3c diff --git a/repos/base/recipes/pkg/test-alarm/runtime b/repos/base/recipes/pkg/test-alarm/runtime new file mode 100644 index 0000000000..06a4794ba8 --- /dev/null +++ b/repos/base/recipes/pkg/test-alarm/runtime @@ -0,0 +1,23 @@ + + + + + [init] in range [1...3]: a1 + [init] in range [1...3]: a2 + [init] in range [1...3]: a3 + [init] in range [3...1]: a3 + [init] in range [3...1]: a4 + [init] in range [3...1]: a0 + [init] in range [3...1]: a1* + [init] soonest(5) -> 0* + [init] Test succeeded. + + + + + + + + + + diff --git a/repos/base/recipes/pkg/test-ds_ownership/hash b/repos/base/recipes/pkg/test-ds_ownership/hash index 587dda17cb..ccff0db4c7 100644 --- a/repos/base/recipes/pkg/test-ds_ownership/hash +++ b/repos/base/recipes/pkg/test-ds_ownership/hash @@ -1 +1 @@ -2022-10-11 b08e70f6de91f200618103ec75f53898c6ef60e8 +2024-08-28 1263204bd1a920d6ea1a414c0a7de506ab225d54 diff --git a/repos/base/recipes/pkg/test-ds_ownership/runtime b/repos/base/recipes/pkg/test-ds_ownership/runtime index 893bd7f1eb..850753c53f 100644 --- a/repos/base/recipes/pkg/test-ds_ownership/runtime +++ b/repos/base/recipes/pkg/test-ds_ownership/runtime @@ -1,10 +1,8 @@ - - - test succeeded - test failed - + + test succeeded + test failed diff --git a/repos/base/recipes/pkg/test-entrypoint/hash b/repos/base/recipes/pkg/test-entrypoint/hash index f392de77ae..5ef9617384 100644 --- a/repos/base/recipes/pkg/test-entrypoint/hash +++ b/repos/base/recipes/pkg/test-entrypoint/hash @@ -1 +1 @@ -2022-10-11 ad5b85ab1377744e2f747ca2eb5010a3aee87f70 +2024-08-28 916b2b926332cfcd7960395cbae045c2f79e22e1 diff --git a/repos/base/recipes/pkg/test-entrypoint/runtime b/repos/base/recipes/pkg/test-entrypoint/runtime index ec5da59e15..1435ee8261 100644 --- a/repos/base/recipes/pkg/test-entrypoint/runtime +++ b/repos/base/recipes/pkg/test-entrypoint/runtime @@ -1,9 +1,7 @@ - - - child "test-entrypoint" exited with exit value 0 - + + child "test-entrypoint" exited with exit value 0 diff --git a/repos/base/recipes/pkg/test-log/hash b/repos/base/recipes/pkg/test-log/hash index e4d25877e6..33bdefb237 100644 --- a/repos/base/recipes/pkg/test-log/hash +++ b/repos/base/recipes/pkg/test-log/hash @@ -1 +1 @@ -2022-10-11 3e1b9be9b239017a54b6b595cdec5891623ba59f +2024-08-28 e9ad6072bfb3d9b3a33bc1bc0d8d569e572a23aa diff --git a/repos/base/recipes/pkg/test-log/runtime b/repos/base/recipes/pkg/test-log/runtime index 4f5469b5b3..2ee443679c 100644 --- a/repos/base/recipes/pkg/test-log/runtime +++ b/repos/base/recipes/pkg/test-log/runtime @@ -1,8 +1,7 @@ - - - + + [init -> test-log] hex range: [0e00,1680) [init -> test-log] empty hex range: [0abc0000,0abc0000) (empty!) [init -> test-log] hex range to limit: [f8,ff] @@ -18,8 +17,7 @@ [init -> test-log] 5.....................................................................................................................................................................................................................................6 [init -> test-log] [init -> test-log] Test done. - - + diff --git a/repos/base/recipes/pkg/test-mmio/hash b/repos/base/recipes/pkg/test-mmio/hash index 63bb8c9fff..63f14e6aca 100644 --- a/repos/base/recipes/pkg/test-mmio/hash +++ b/repos/base/recipes/pkg/test-mmio/hash @@ -1 +1 @@ -2022-10-11 ee3cb10ce306e2afab97018d2bda4e33ce3f863c +2024-08-28 eb64887a9855af98fd59ca684d76a117ad6bc218 diff --git a/repos/base/recipes/pkg/test-mmio/runtime b/repos/base/recipes/pkg/test-mmio/runtime index efae66e85c..738f3d935c 100644 --- a/repos/base/recipes/pkg/test-mmio/runtime +++ b/repos/base/recipes/pkg/test-mmio/runtime @@ -2,11 +2,9 @@ - - - child "test" exited with exit value 0 - child "test" exited with exit value -1 - + + child "test" exited with exit value 0 + child "test" exited with exit value -1 diff --git a/repos/base/recipes/pkg/test-new_delete/hash b/repos/base/recipes/pkg/test-new_delete/hash index 8fdf563d97..e90d442163 100644 --- a/repos/base/recipes/pkg/test-new_delete/hash +++ b/repos/base/recipes/pkg/test-new_delete/hash @@ -1 +1 @@ -2022-10-11 dac71b5071da69f218826b2bdc5462b7cf0c28a3 +2024-08-28 2d87a4f1e768e5156bb2122e76aefe9b93250b98 diff --git a/repos/base/recipes/pkg/test-new_delete/runtime b/repos/base/recipes/pkg/test-new_delete/runtime index 1239f74724..7c230a7522 100644 --- a/repos/base/recipes/pkg/test-new_delete/runtime +++ b/repos/base/recipes/pkg/test-new_delete/runtime @@ -1,9 +1,8 @@ - - + - + [init -> test-new_delete] Allocator::alloc() [init -> test-new_delete] A [init -> test-new_delete] C @@ -55,9 +54,8 @@ [init -> test-new_delete] Allocator::free() [init -> test-new_delete] exception caught [init -> test-new_delete] Test done - + - diff --git a/repos/base/recipes/pkg/test-reconstructible/hash b/repos/base/recipes/pkg/test-reconstructible/hash index 99f66adb70..46604b10f8 100644 --- a/repos/base/recipes/pkg/test-reconstructible/hash +++ b/repos/base/recipes/pkg/test-reconstructible/hash @@ -1 +1 @@ -2022-10-11 5f899fc663f34b1c1aeeba243e54edc092aa40fa +2024-08-28 9999549086b013d745b7c29d0d73ce16a7b44460 diff --git a/repos/base/recipes/pkg/test-reconstructible/runtime b/repos/base/recipes/pkg/test-reconstructible/runtime index a07a2b865f..741b784df0 100644 --- a/repos/base/recipes/pkg/test-reconstructible/runtime +++ b/repos/base/recipes/pkg/test-reconstructible/runtime @@ -1,8 +1,7 @@ - - - + + [init -> test-reconstructible] --- Reconstructible utility test --- [init -> test-reconstructible] construct Object 1 [init -> test-reconstructible] construct Object 2 @@ -36,8 +35,7 @@ [init -> test-reconstructible] construct Throwing -> throw exception [init -> test-reconstructible] got exception, as expected [init -> test-reconstructible] --- Reconstructible utility test finished --- - - + diff --git a/repos/base/recipes/pkg/test-registry/hash b/repos/base/recipes/pkg/test-registry/hash index ce25cb14f6..9e20953106 100644 --- a/repos/base/recipes/pkg/test-registry/hash +++ b/repos/base/recipes/pkg/test-registry/hash @@ -1 +1 @@ -2022-10-11 50b25d7a4bbde78fc1722a4e822370eb49cb6b95 +2024-08-28 eb836fa23731d48906eb17a55f4493a1f1d5f31e diff --git a/repos/base/recipes/pkg/test-registry/runtime b/repos/base/recipes/pkg/test-registry/runtime index a90d5aa113..ff1b41c3da 100644 --- a/repos/base/recipes/pkg/test-registry/runtime +++ b/repos/base/recipes/pkg/test-registry/runtime @@ -1,10 +1,8 @@ - - - child "test-registry" exited with exit value 0 - Uncaught exception - + + child "test-registry" exited with exit value 0 + Uncaught exception diff --git a/repos/base/recipes/pkg/test-rm_fault/hash b/repos/base/recipes/pkg/test-rm_fault/hash index 2660982cdc..1d80f7affc 100644 --- a/repos/base/recipes/pkg/test-rm_fault/hash +++ b/repos/base/recipes/pkg/test-rm_fault/hash @@ -1 +1 @@ -2022-10-11 8882e9bea4fdc16ff4910913a79223d62aeb0cdc +2024-08-28 b338f91749569157a0ee70bdac8b63b4604a10f1 diff --git a/repos/base/recipes/pkg/test-rm_fault/runtime b/repos/base/recipes/pkg/test-rm_fault/runtime index 0c9f54c394..2de9a7d96c 100644 --- a/repos/base/recipes/pkg/test-rm_fault/runtime +++ b/repos/base/recipes/pkg/test-rm_fault/runtime @@ -1,10 +1,8 @@ - - - child "test-rm_fault" exited with exit value 0 - Error: could modify ROM - + + child "test-rm_fault" exited with exit value 0 + Error: could modify ROM diff --git a/repos/base/recipes/pkg/test-rm_fault_no_nox/hash b/repos/base/recipes/pkg/test-rm_fault_no_nox/hash index f0fed0ff13..77775062de 100644 --- a/repos/base/recipes/pkg/test-rm_fault_no_nox/hash +++ b/repos/base/recipes/pkg/test-rm_fault_no_nox/hash @@ -1 +1 @@ -2022-10-11 a2514b901565ebf0aa88a955c4431fe733964758 +2024-08-28 0c740d62b29e444a70f19786e73e919929b8a41b diff --git a/repos/base/recipes/pkg/test-rm_fault_no_nox/runtime b/repos/base/recipes/pkg/test-rm_fault_no_nox/runtime index 6d4c0e6d94..b1095502bc 100644 --- a/repos/base/recipes/pkg/test-rm_fault_no_nox/runtime +++ b/repos/base/recipes/pkg/test-rm_fault_no_nox/runtime @@ -1,9 +1,7 @@ - - - child "test-rm_fault" exited with exit value 0 - + + child "test-rm_fault" exited with exit value 0 diff --git a/repos/base/recipes/pkg/test-rm_nested/hash b/repos/base/recipes/pkg/test-rm_nested/hash index 617c2179b0..f936f1ffad 100644 --- a/repos/base/recipes/pkg/test-rm_nested/hash +++ b/repos/base/recipes/pkg/test-rm_nested/hash @@ -1 +1 @@ -2022-10-11 3a4ebd01ee612ba2e12ae8df14d6299fb4431375 +2024-08-28 dcf9171eaf3917bc7dab03d2821105a25a8d9526 diff --git a/repos/base/recipes/pkg/test-rm_nested/runtime b/repos/base/recipes/pkg/test-rm_nested/runtime index e49bc31b44..72d1e6cb44 100644 --- a/repos/base/recipes/pkg/test-rm_nested/runtime +++ b/repos/base/recipes/pkg/test-rm_nested/runtime @@ -1,10 +1,8 @@ - - - --- finished nested region map test --- - Error: - + + --- finished nested region map test --- + Error: diff --git a/repos/base/recipes/pkg/test-rm_stress/hash b/repos/base/recipes/pkg/test-rm_stress/hash index a7c6d8a6d0..0d8cc58d39 100644 --- a/repos/base/recipes/pkg/test-rm_stress/hash +++ b/repos/base/recipes/pkg/test-rm_stress/hash @@ -1 +1 @@ -2022-10-11 5ac901826381a7d6de528cd3d3520b0767385f6c +2024-08-28 20da1561fd882dbd113366082471d95b8533e310 diff --git a/repos/base/recipes/pkg/test-rm_stress/runtime b/repos/base/recipes/pkg/test-rm_stress/runtime index 4097dbb755..c295d68969 100644 --- a/repos/base/recipes/pkg/test-rm_stress/runtime +++ b/repos/base/recipes/pkg/test-rm_stress/runtime @@ -1,10 +1,8 @@ - - - child "test-rm_stress" exited with exit value 0 - child "test-rm_stress" exited with exit value -1 - + + child "test-rm_stress" exited with exit value 0 + child "test-rm_stress" exited with exit value -1 diff --git a/repos/base/recipes/pkg/test-sanitizer/hash b/repos/base/recipes/pkg/test-sanitizer/hash index 655a1c5294..2621e23b2e 100644 --- a/repos/base/recipes/pkg/test-sanitizer/hash +++ b/repos/base/recipes/pkg/test-sanitizer/hash @@ -1 +1 @@ -2022-10-11 36717c21923ac35c938ad73930f1d1576ecaf385 +2024-08-28 2179cbeaf81dd04431742572f2f685473cd84594 diff --git a/repos/base/recipes/pkg/test-sanitizer/runtime b/repos/base/recipes/pkg/test-sanitizer/runtime index 749932e527..e6938ca053 100644 --- a/repos/base/recipes/pkg/test-sanitizer/runtime +++ b/repos/base/recipes/pkg/test-sanitizer/runtime @@ -1,12 +1,10 @@ - + - - - - [init -> test-sanitizer]*runtime error: *index 2 out of bounds* - [init -> test-sanitizer]*runtime error: *store to null pointer - - + + + [init]*runtime error: *index 2 out of bounds* + [init]*runtime error: *store to null pointer + @@ -15,19 +13,6 @@ - - - - - - - - - - - - - - - + + diff --git a/repos/base/recipes/pkg/test-stack_smash/hash b/repos/base/recipes/pkg/test-stack_smash/hash index 3c46805904..aff8a56547 100644 --- a/repos/base/recipes/pkg/test-stack_smash/hash +++ b/repos/base/recipes/pkg/test-stack_smash/hash @@ -1 +1 @@ -2022-10-11 b8e011ab9a1ae92c4293ab07f9a6b7df71c6aabc +2024-08-28 e9f6ccbe39344ae7f6a9e5787397d352383d50e9 diff --git a/repos/base/recipes/pkg/test-stack_smash/runtime b/repos/base/recipes/pkg/test-stack_smash/runtime index ac5e16c3bd..1cb01c0a18 100644 --- a/repos/base/recipes/pkg/test-stack_smash/runtime +++ b/repos/base/recipes/pkg/test-stack_smash/runtime @@ -1,9 +1,7 @@ - - - Error: stack protector check failed - + + Error: stack protector check failed diff --git a/repos/base/recipes/pkg/test-synced_interface/hash b/repos/base/recipes/pkg/test-synced_interface/hash index 053c382dc6..8be6355d77 100644 --- a/repos/base/recipes/pkg/test-synced_interface/hash +++ b/repos/base/recipes/pkg/test-synced_interface/hash @@ -1 +1 @@ -2022-10-11 0a151f72dc20e2e6b8cca80b761128dee92bb7c5 +2024-08-28 9a01b6b2d0d295435aa0a02ebc7348a285eeca8d diff --git a/repos/base/recipes/pkg/test-synced_interface/runtime b/repos/base/recipes/pkg/test-synced_interface/runtime index de75881d15..302be0ddb5 100644 --- a/repos/base/recipes/pkg/test-synced_interface/runtime +++ b/repos/base/recipes/pkg/test-synced_interface/runtime @@ -1,16 +1,14 @@ - - - + + [init -> test-synced_interface] --- Synced interface test --- [init -> test-synced_interface] acquire [init -> test-synced_interface] adding 13 + 14 [init -> test-synced_interface] release [init -> test-synced_interface] result is 27 [init -> test-synced_interface] --- Synced interface test finished --- - - + diff --git a/repos/base/recipes/pkg/test-timer/hash b/repos/base/recipes/pkg/test-timer/hash index 56f8cf4688..535345160b 100644 --- a/repos/base/recipes/pkg/test-timer/hash +++ b/repos/base/recipes/pkg/test-timer/hash @@ -1 +1 @@ -2022-10-11 8070010a6f4553f3be84c5fbe0729f50e5d3fde0 +2024-08-28 ae27770a9af453d0c385aa2eedf3aeea9d017223 diff --git a/repos/base/recipes/pkg/test-timer/runtime b/repos/base/recipes/pkg/test-timer/runtime index 06fccd5560..971ce5c10f 100644 --- a/repos/base/recipes/pkg/test-timer/runtime +++ b/repos/base/recipes/pkg/test-timer/runtime @@ -2,11 +2,9 @@ - - - [init] child "client" exited with exit value 0 - Error: - + + [init] child "client" exited with exit value 0 + Error: diff --git a/repos/base/recipes/pkg/test-tls/hash b/repos/base/recipes/pkg/test-tls/hash index eb94a8999b..ff94b68744 100644 --- a/repos/base/recipes/pkg/test-tls/hash +++ b/repos/base/recipes/pkg/test-tls/hash @@ -1 +1 @@ -2022-10-11 5068ceee7e2285a398ac7b6936f6d16c8daa29ea +2024-08-28 ebeb7886af2d31d276ab768af6bd8f3220de8953 diff --git a/repos/base/recipes/pkg/test-tls/runtime b/repos/base/recipes/pkg/test-tls/runtime index 471fc010a0..286e58ce2c 100644 --- a/repos/base/recipes/pkg/test-tls/runtime +++ b/repos/base/recipes/pkg/test-tls/runtime @@ -1,16 +1,14 @@ - - - + + [init -> test-tls] main initial: x: -1, y: 0 [init -> test-tls] thread 0 initial: x: -1, y: 0 [init -> test-tls] thread 0 : x: 1, y: 2 [init -> test-tls] thread 1 initial: x: -1, y: 0 [init -> test-tls] thread 1 : x: 3, y: 4 [init -> test-tls] main : x: 5, y: 6 - - + diff --git a/repos/base/recipes/pkg/test-token/hash b/repos/base/recipes/pkg/test-token/hash index 513c91136b..71c6873ed2 100644 --- a/repos/base/recipes/pkg/test-token/hash +++ b/repos/base/recipes/pkg/test-token/hash @@ -1 +1 @@ -2022-10-11 c4e1fb742ffc41fdb81aeb2ca2638ca81459578d +2024-08-28 0f803f76ccc130569e39451c51626feec05a712b diff --git a/repos/base/recipes/pkg/test-token/runtime b/repos/base/recipes/pkg/test-token/runtime index da90071a44..e30a607928 100644 --- a/repos/base/recipes/pkg/test-token/runtime +++ b/repos/base/recipes/pkg/test-token/runtime @@ -1,9 +1,7 @@ - - - finished token test - + + finished token test diff --git a/repos/base/recipes/pkg/test-xml_generator/hash b/repos/base/recipes/pkg/test-xml_generator/hash index 01508ca781..e9aee142a4 100644 --- a/repos/base/recipes/pkg/test-xml_generator/hash +++ b/repos/base/recipes/pkg/test-xml_generator/hash @@ -1 +1 @@ -2022-10-11 f44af3d8cc1af7801408f855c1c8c168c8d84aa7 +2024-08-28 1fbbbbe8badb32ea8ec9b07cee8f8a5d95360acb diff --git a/repos/base/recipes/pkg/test-xml_generator/runtime b/repos/base/recipes/pkg/test-xml_generator/runtime index cfb2746cdd..1f04982ae6 100644 --- a/repos/base/recipes/pkg/test-xml_generator/runtime +++ b/repos/base/recipes/pkg/test-xml_generator/runtime @@ -1,8 +1,7 @@ - - - + + [init -> test-xml_generator] --- XML generator test started --- [init -> test-xml_generator] [init -> test-xml_generator] used 308 bytes, result: @@ -56,9 +55,8 @@ [init -> test-xml_generator] [init -> test-xml_generator] --- XML generator test finished ---* [init] child "test-xml_generator" exited with exit value 0 - - Error: - + + Error: diff --git a/repos/base/recipes/pkg/test-xml_node/hash b/repos/base/recipes/pkg/test-xml_node/hash index fc516acfbc..36f87174ce 100644 --- a/repos/base/recipes/pkg/test-xml_node/hash +++ b/repos/base/recipes/pkg/test-xml_node/hash @@ -1 +1 @@ -2022-10-11 682420bf32f10e223946d7713bf70255ede1d451 +2024-08-28 b48cf2518250d49a57109e7038d837ab02b94d56 diff --git a/repos/base/recipes/pkg/test-xml_node/runtime b/repos/base/recipes/pkg/test-xml_node/runtime index e526210460..11766a652d 100644 --- a/repos/base/recipes/pkg/test-xml_node/runtime +++ b/repos/base/recipes/pkg/test-xml_node/runtime @@ -1,8 +1,7 @@ - - - + + [init -> test-xml_node] --- XML-token test --- [init -> test-xml_node] token type="SINGLECHAR", len=1, content="<" [init -> test-xml_node] token type="IDENT", len=6, content="config" @@ -113,9 +112,8 @@ [init -> test-xml_node] [init -> test-xml_node] --- End of XML-parser test ---* [init] child "test-xml_node" exited with exit value 0 - - Error: - + + Error: diff --git a/repos/base/recipes/src/test-alarm/content.mk b/repos/base/recipes/src/test-alarm/content.mk new file mode 100644 index 0000000000..2d461e96a4 --- /dev/null +++ b/repos/base/recipes/src/test-alarm/content.mk @@ -0,0 +1,2 @@ +SRC_DIR = src/test/alarm src/include/base/internal +include $(GENODE_DIR)/repos/base/recipes/src/content.inc diff --git a/repos/base/recipes/src/test-alarm/hash b/repos/base/recipes/src/test-alarm/hash new file mode 100644 index 0000000000..6f3caf9123 --- /dev/null +++ b/repos/base/recipes/src/test-alarm/hash @@ -0,0 +1 @@ +2024-08-28 27a6c8bd9c14310c772eceaa6ce8545fad4161a0 diff --git a/repos/base-sel4/recipes/src/base-sel4-imx7d_sabre/used_apis b/repos/base/recipes/src/test-alarm/used_apis similarity index 100% rename from repos/base-sel4/recipes/src/base-sel4-imx7d_sabre/used_apis rename to repos/base/recipes/src/test-alarm/used_apis diff --git a/repos/base/recipes/src/test-ds_ownership/hash b/repos/base/recipes/src/test-ds_ownership/hash index cd73f3f0ac..cc6790c865 100644 --- a/repos/base/recipes/src/test-ds_ownership/hash +++ b/repos/base/recipes/src/test-ds_ownership/hash @@ -1 +1 @@ -2022-10-11 359a8ba82f0a85f6f83c2e140120e0ec2fc2ff4b +2024-08-28 81579f87117d620bded1b18b94d32f8dfcf798c0 diff --git a/repos/base/recipes/src/test-entrypoint/hash b/repos/base/recipes/src/test-entrypoint/hash index 9ea1110839..09841a8644 100644 --- a/repos/base/recipes/src/test-entrypoint/hash +++ b/repos/base/recipes/src/test-entrypoint/hash @@ -1 +1 @@ -2022-10-11 5a9a370fb5f6483aa652fd13e805f8970580d8d7 +2024-08-28 353ca16a476ea875269280a482133917404af2b4 diff --git a/repos/base/recipes/src/test-log/hash b/repos/base/recipes/src/test-log/hash index bf465ce443..58a5c77880 100644 --- a/repos/base/recipes/src/test-log/hash +++ b/repos/base/recipes/src/test-log/hash @@ -1 +1 @@ -2022-10-11 095026fa1d5dc144f0d2bd21f3b0aad4c1ddacbd +2024-08-28 5a105d705f54f092f8a5830a0ae6735ae9a4787a diff --git a/repos/base/recipes/src/test-mmio/hash b/repos/base/recipes/src/test-mmio/hash index 6247eefd30..233f312dc0 100644 --- a/repos/base/recipes/src/test-mmio/hash +++ b/repos/base/recipes/src/test-mmio/hash @@ -1 +1 @@ -2022-10-11 2fc5a59b9a18db38188c8f0b5cd140f8af25debf +2024-08-28 1e93c3437d41e6177b8063f48aad15f5ca340956 diff --git a/repos/base/recipes/src/test-new_delete/hash b/repos/base/recipes/src/test-new_delete/hash index 196fd52868..d18561c597 100644 --- a/repos/base/recipes/src/test-new_delete/hash +++ b/repos/base/recipes/src/test-new_delete/hash @@ -1 +1 @@ -2022-10-11 4b8f0df83f00b36d32640a767a861327034e51ed +2024-08-28 215be20a911ed192b38c93319396f6a5b3f7cb6d diff --git a/repos/base/recipes/src/test-reconstructible/hash b/repos/base/recipes/src/test-reconstructible/hash index 62b89f129b..f8e73fdf76 100644 --- a/repos/base/recipes/src/test-reconstructible/hash +++ b/repos/base/recipes/src/test-reconstructible/hash @@ -1 +1 @@ -2022-10-11 03229606efad94460265721c6f828fdf4f1c1e36 +2024-08-28 a27dcf2ba32e600ce9b02a18222d8286d9220b6e diff --git a/repos/base/recipes/src/test-registry/hash b/repos/base/recipes/src/test-registry/hash index dd85d8a1ff..8fa7788d32 100644 --- a/repos/base/recipes/src/test-registry/hash +++ b/repos/base/recipes/src/test-registry/hash @@ -1 +1 @@ -2022-10-11 3a9a202788b631072f5bc4a6220083ea3f0804ee +2024-08-28 34c983d620520d362a146f6c9f062885b2d98c38 diff --git a/repos/base/recipes/src/test-rm_fault/hash b/repos/base/recipes/src/test-rm_fault/hash index 8bb4d51590..0a633b7d4c 100644 --- a/repos/base/recipes/src/test-rm_fault/hash +++ b/repos/base/recipes/src/test-rm_fault/hash @@ -1 +1 @@ -2022-10-11 31d8bd8cf827651dc7996e6d3ca7b005ddc0bdcd +2024-08-28 78709e0ea496651d938423d0bb18a0254a04acaf diff --git a/repos/base/recipes/src/test-rm_nested/hash b/repos/base/recipes/src/test-rm_nested/hash index 86599133e2..cfb3987c66 100644 --- a/repos/base/recipes/src/test-rm_nested/hash +++ b/repos/base/recipes/src/test-rm_nested/hash @@ -1 +1 @@ -2022-10-11 c81db79ecd943606a3113aad3e804c715fc33a1c +2024-08-28 59c0abed548b66f8d54c74e82f1ab0ab7f0d0ee6 diff --git a/repos/base/recipes/src/test-rm_stress/hash b/repos/base/recipes/src/test-rm_stress/hash index 68e858396b..485f2fcc74 100644 --- a/repos/base/recipes/src/test-rm_stress/hash +++ b/repos/base/recipes/src/test-rm_stress/hash @@ -1 +1 @@ -2022-10-11 ef88b5f407d0b49926354c8144d2322b778dfcad +2024-08-28 3ea09d83887d1fc0e07409e68d52c99f794846f9 diff --git a/repos/base/recipes/src/test-sanitizer/hash b/repos/base/recipes/src/test-sanitizer/hash index 2423895026..52c4b35c74 100644 --- a/repos/base/recipes/src/test-sanitizer/hash +++ b/repos/base/recipes/src/test-sanitizer/hash @@ -1 +1 @@ -2022-10-11 27a1948a58c15301b3e1978f409ce9b076d704bc +2024-08-28 e4c5cc271035fd20416eca2b23005800bdbe22d5 diff --git a/repos/base/recipes/src/test-segfault/hash b/repos/base/recipes/src/test-segfault/hash index f409498935..3b07ec270f 100644 --- a/repos/base/recipes/src/test-segfault/hash +++ b/repos/base/recipes/src/test-segfault/hash @@ -1 +1 @@ -2022-10-11 29971db890cb657bb8d41bf07636ba21752ca8b3 +2024-08-28 d30834f3bb7de0b8450835323179e126c057206d diff --git a/repos/base/recipes/src/test-stack_smash/hash b/repos/base/recipes/src/test-stack_smash/hash index 8202e3d036..7d41efcd8e 100644 --- a/repos/base/recipes/src/test-stack_smash/hash +++ b/repos/base/recipes/src/test-stack_smash/hash @@ -1 +1 @@ -2022-10-11 483ee9045181e9912f60834b45436d0226763bb8 +2024-08-28 6106585c8708899bc2b5580583ae3d80a873a4bb diff --git a/repos/base/recipes/src/test-synced_interface/hash b/repos/base/recipes/src/test-synced_interface/hash index 87e2688cb7..7c3b2287eb 100644 --- a/repos/base/recipes/src/test-synced_interface/hash +++ b/repos/base/recipes/src/test-synced_interface/hash @@ -1 +1 @@ -2022-10-11 bdabeb64387faee3c5307377d72bcb99f4086f00 +2024-08-28 548d48fdd30db99f612a172dbb6733b9705de758 diff --git a/repos/base/recipes/src/test-timer/hash b/repos/base/recipes/src/test-timer/hash index 80fa15879a..6b33630d2b 100644 --- a/repos/base/recipes/src/test-timer/hash +++ b/repos/base/recipes/src/test-timer/hash @@ -1 +1 @@ -2022-10-11 18675e4c9e59c67edede9b4c0eb0eb8bd8ff56d2 +2024-08-28 e9bcac3043d0ec5b0f99cf70c79c6a4602d7b381 diff --git a/repos/base/recipes/src/test-tls/hash b/repos/base/recipes/src/test-tls/hash index 26715c617c..141411fdf8 100644 --- a/repos/base/recipes/src/test-tls/hash +++ b/repos/base/recipes/src/test-tls/hash @@ -1 +1 @@ -2022-10-11 e0674b3ea25b560f92bfe65b9ccbed95c3119665 +2024-08-28 54a1cf1254fb7f5a3e21f19a4e93aaf48244e727 diff --git a/repos/base/recipes/src/test-token/hash b/repos/base/recipes/src/test-token/hash index efd237b5be..30f6b65c29 100644 --- a/repos/base/recipes/src/test-token/hash +++ b/repos/base/recipes/src/test-token/hash @@ -1 +1 @@ -2022-10-11 6b24a7f9187ca2e87c5acffd6cd61c63bca52477 +2024-08-28 a39e757b6833857b4ec32f2060305079d6cc068f diff --git a/repos/base/recipes/src/test-xml_generator/hash b/repos/base/recipes/src/test-xml_generator/hash index 0858b2605a..1f107545ee 100644 --- a/repos/base/recipes/src/test-xml_generator/hash +++ b/repos/base/recipes/src/test-xml_generator/hash @@ -1 +1 @@ -2022-10-11 be8b5157c899db1007904028d0f77dc50acc1a7f +2024-08-28 8fded3cec4f36bfe77abbed9060c577906c8f643 diff --git a/repos/base/recipes/src/test-xml_generator/used_apis b/repos/base/recipes/src/test-xml_generator/used_apis index f72ea155b5..9fb148f247 100644 --- a/repos/base/recipes/src/test-xml_generator/used_apis +++ b/repos/base/recipes/src/test-xml_generator/used_apis @@ -1,4 +1,5 @@ base file_system_session libgcov +format os diff --git a/repos/base/recipes/src/test-xml_node/hash b/repos/base/recipes/src/test-xml_node/hash index 4dd2a34d95..2b7cd83038 100644 --- a/repos/base/recipes/src/test-xml_node/hash +++ b/repos/base/recipes/src/test-xml_node/hash @@ -1 +1 @@ -2022-10-11 53ba6ffafbcb4b78411e4117bbc3e7e3d721f20e +2024-08-28 636f2fe518818087444a67b7fea94c7daf5dd5af diff --git a/repos/base/run/log.run b/repos/base/run/log.run index 5cabc9f120..6b1f874cb5 100644 --- a/repos/base/run/log.run +++ b/repos/base/run/log.run @@ -1,4 +1,4 @@ -build "core init test/log" +build { core init lib/ld test/log } create_boot_directory @@ -20,10 +20,9 @@ install_config { } -build_boot_image "core ld.lib.so init test-log" +build_boot_image [build_artifacts] append qemu_args "-nographic " -append xen_args { sdl="0" } run_genode_until "Test done.*\n" 20 diff --git a/repos/base/run/migrate.run b/repos/base/run/migrate.run index 12534ac927..75c3afc3e7 100644 --- a/repos/base/run/migrate.run +++ b/repos/base/run/migrate.run @@ -1,4 +1,4 @@ -build "core init test/migrate timer" +build { core init lib/ld test/migrate timer } if {![have_include "power_on/qemu"]} { puts "Run script is not supported on this platform" @@ -39,13 +39,17 @@ append config { + + + + } install_config $config -build_boot_image "core ld.lib.so init test-migrate timer" +build_boot_image [build_artifacts] append qemu_args "-nographic " append qemu_args "-smp 4,cores=4,threads=1" diff --git a/repos/base/run/platform_drv.inc b/repos/base/run/platform_drv.inc deleted file mode 100644 index 3da9f74d87..0000000000 --- a/repos/base/run/platform_drv.inc +++ /dev/null @@ -1,261 +0,0 @@ -proc have_platform_drv {} { - return [expr [have_board pc]] -} - - -## -# Return name of the USB driver binary -# -proc usb_host_drv_binary { } { - if {[have_board rpi]} { return legacy_rpi_usb_host_drv } - if {[have_board imx6q_sabrelite]} { return legacy_imx6q_sabrelite_usb_host_drv } - if {[have_board pc]} { return pc_usb_host_drv } - return no_usb_drv_available -} - - -## -# Return name of the audio driver binary -# -proc audio_drv_binary { } { - if {[have_board linux]} { return linux_audio_drv } - if {[have_board pc]} { return pci_audio_drv } - return no_audio_drv_available -} - -## -# Return attributes of the audio driver's node -# -proc audio_drv_start_attr { } { - if {[have_board linux]} { return {ld="no"} } - return "" -} - -proc acpi_drv_name { } { - global use_acpica_as_acpi_drv - if {[info exists use_acpica_as_acpi_drv] && $use_acpica_as_acpi_drv} { - return acpica } - - return acpi_drv -} - -proc platform_drv_build_components {} { - set drv_build_components "" - if {[have_board pc]} { - lappend drv_build_components drivers/platform/legacy/x86 - lappend drv_build_components server/report_rom - if {[acpi_drv_name] eq "acpi_drv"} { - lappend drv_build_components drivers/acpi - } - if {[acpi_drv_name] eq "acpica"} { - lappend drv_build_components app/acpica - } - } - return $drv_build_components -} - - -proc append_platform_drv_build_components {} { - global build_components - append build_components { } [platform_drv_build_components] -} - -proc platform_drv_binary {} { - if {[have_board pc]} { return legacy_pc_platform_drv } - return no_platform_drv_available -} - -proc platform_drv_boot_modules {} { - set drv_boot_modules "" - lappend_if [have_platform_drv] drv_boot_modules [platform_drv_binary] - - if {[have_board pc]} { - lappend drv_boot_modules report_rom - lappend drv_boot_modules [acpi_drv_name] - } - - return $drv_boot_modules -} - -proc append_platform_drv_boot_modules {} { - global boot_modules - append boot_modules { } [platform_drv_boot_modules] -} - - -proc platform_drv_policy {} { - - if {![have_board pc]} { - return {} - } - - set drv_policy "" - - if {[acpi_drv_name] eq "acpica"} { - append drv_policy { - } - } - - append drv_policy { - - - - - - - - - - - - - } - - return $drv_policy -} - - -proc platform_drv_priority {} { return "" } -proc platform_drv_add_routing {} { - - if {[acpi_drv_name] eq "acpica"} { - return { - } - } - - return "" -} - - -proc platform_drv_config_config {} { - if {[acpi_drv_name] eq "acpica"} { - return { - } - } - - return {} -} - - -proc platform_drv_config {} { - set drv_config "" - - if {[have_board pc]} { - - append drv_config { - - } - - if {[acpi_drv_name] eq "acpica"} { - append drv_config { - - } - } else { - append drv_config { - } - } - - append drv_config { - - - - - - - } - - append_if [expr {[acpi_drv_name] eq "acpica"}] drv_config { - - - - - } - - append drv_config { - - - - } - - append drv_config " - " - - append drv_config { - - - - - - - - - - } - - append_if [expr {[acpi_drv_name] eq "acpica"}] drv_config { - } - - append drv_config { - - - - - - - - } - - } - - if {[have_platform_drv]} { - - append drv_config { - - - - - } - - append_if [have_board pc] drv_config { - } - - append_if [have_spec arm] drv_config { - } - - append drv_config { - - } - - append drv_config "[platform_drv_add_routing]" - - append_if [have_board pc] drv_config { - } - - append_if [expr [have_board pc]] drv_config { - } - - append_if [expr [have_board rpi] || [have_board pc]] drv_config { - } - - append drv_config { - - } - - append drv_config [platform_drv_config_config] - append drv_config [platform_drv_policy] - - append drv_config { - - } - - } - - return $drv_config -} - - -proc append_platform_drv_config {} { - global config - append config [platform_drv_config] - return $config -} diff --git a/repos/base/run/smp.run b/repos/base/run/smp.run index 99bfed3c34..ed48030ed0 100644 --- a/repos/base/run/smp.run +++ b/repos/base/run/smp.run @@ -10,7 +10,7 @@ if { [get_cmd_switch --autopilot] && [have_include "power_on/qemu"] } { exit 0 } -build "core init test/smp" +build { core init lib/ld test/smp } create_boot_directory @@ -32,7 +32,7 @@ install_config { } -build_boot_image "core ld.lib.so init test-smp" +build_boot_image [build_artifacts] if {[have_include "power_on/qemu"]} { # in general we want to have at least 2 CPUs @@ -100,8 +100,8 @@ grep_output {\[init -\> test-smp\] Affinity: Round} set rounds "10" set good_string {} for {set r 0} {$r <= $rounds} {incr r} { - append good_string {[init -> test-smp] Affinity: Round } - append good_string [format "%02d" $r] + append good_string {[init -> test-smp] Affinity: Round } + append good_string [format "%2d" $r] append good_string ":" for {set i 0} {$i < $cpus} {incr i} { append good_string " A" @@ -112,12 +112,12 @@ compare_output_to $good_string puts "Affinity test: passed" set output $original_output -grep_output {no RM attachment } -unify_output {pf_addr=0x[a-f0-9]+} "ADDR" -unify_output {pf_ip=0x[a-f0-9]+} "IP" +grep_output {Error:} +unify_output {address 0x[a-f0-9]+} "address ADDR" +unify_output {ip=0x[a-f0-9]+} "ip=IP" set good_string "" for {set r 1} {$r < $cpus} {incr r} { - append good_string {no RM attachment (READ ADDR IP from pager_object: pd='init -> test-smp' thread='tlb_thread')} + append good_string {Error: illegal READ at address ADDR by pager_object: pd='init -> test-smp' thread='tlb_thread' ip=IP} append good_string "\n" } compare_output_to $good_string diff --git a/repos/base/run/sub_rm.run b/repos/base/run/sub_rm.run index 4f6dd9528f..97abc6828c 100644 --- a/repos/base/run/sub_rm.run +++ b/repos/base/run/sub_rm.run @@ -1,4 +1,4 @@ -build "core init test/sub_rm" +build { core init lib/ld test/sub_rm } create_boot_directory @@ -30,7 +30,7 @@ append config { install_config $config -build_boot_image "core ld.lib.so init test-sub_rm" +build_boot_image [build_artifacts] append qemu_args "-nographic " diff --git a/repos/base/run/thread.run b/repos/base/run/thread.run index 7c5f9ec78f..bfd5bd603f 100644 --- a/repos/base/run/thread.run +++ b/repos/base/run/thread.run @@ -1,4 +1,4 @@ -build "core init test/thread" +build { core init lib/ld test/thread } create_boot_directory @@ -45,7 +45,7 @@ append config { install_config $config -build_boot_image "core ld.lib.so init test-thread" +build_boot_image [build_artifacts] append qemu_args "-nographic " diff --git a/repos/base/run/timeout_smp.run b/repos/base/run/timeout_smp.run index 826e8aca74..da6e556426 100644 --- a/repos/base/run/timeout_smp.run +++ b/repos/base/run/timeout_smp.run @@ -1,4 +1,4 @@ -build { core init timer test/timeout_smp } +build { core init timer lib/ld test/timeout_smp } create_boot_directory @@ -30,11 +30,14 @@ install_config { } -build_boot_image { core ld.lib.so init timer test-timeout_smp } + +build_boot_image [build_artifacts] append qemu_args " -nographic" run_genode_until "child \"test\" exited with exit value.*\n" 60 + grep_output {\[init\] child "test" exited with exit value} + compare_output_to {[init] child "test" exited with exit value 0} diff --git a/repos/base/run/timer_accuracy.run b/repos/base/run/timer_accuracy.run index 14e8c38fe3..fe536905c7 100644 --- a/repos/base/run/timer_accuracy.run +++ b/repos/base/run/timer_accuracy.run @@ -1,10 +1,7 @@ -# build program images -build { core init timer test/timer_accuracy } +build { core init timer lib/ld test/timer_accuracy } -# create directory where boot files are written to create_boot_directory -# define XML configuration for init install_config { @@ -31,12 +28,22 @@ install_config { } -# build boot files from source binaries -build_boot_image { core ld.lib.so init timer test-timer_accuracy } -# configure Qemu +build_boot_image [build_artifacts] + append qemu_args " -nographic" +if {[get_cmd_switch --autopilot] && [have_include "power_on/qemu"] && [have_spec nova]} { + # NOVA requires a CPU with invariant TSC support, which is by default not + # supported. KVM has support by explicitly enabling this feature, but by + # now the nightly test machines is not permitted to use KVM + + # append qemu_args " -accel kvm -cpu host,migratable=no,+invtsc" + + puts "Run script does not support autopilot mode on Qemu" + exit 0 +} + set err_cnt 0 set test_timeout 20 set rounds 9 diff --git a/repos/base/run/timer_rate.run b/repos/base/run/timer_rate.run index e18fbf3bd1..6be666c3a8 100644 --- a/repos/base/run/timer_rate.run +++ b/repos/base/run/timer_rate.run @@ -1,4 +1,4 @@ -build { core init timer test/timer_rate } +build { core init timer lib/ld test/timer_rate } create_boot_directory @@ -33,11 +33,14 @@ install_config { } -build_boot_image { core ld.lib.so init timer test-timer_rate } + +build_boot_image [build_artifacts] append qemu_args " -nographic" run_genode_until "child \"test\" exited with exit value.*\n" 120 + grep_output {\[init\] child "test" exited with exit value} + compare_output_to {[init] child "test" exited with exit value 0} diff --git a/repos/base/src/README b/repos/base/src/README deleted file mode 100644 index 3dbaa0f09a..0000000000 --- a/repos/base/src/README +++ /dev/null @@ -1 +0,0 @@ -This directory contains all source codes. diff --git a/repos/base/src/core/capability_space.cc b/repos/base/src/core/capability_space.cc index ba16260cdf..4f714f2d85 100644 --- a/repos/base/src/core/capability_space.cc +++ b/repos/base/src/core/capability_space.cc @@ -11,13 +11,15 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* base includes */ +/* Genode includes */ #include -#include /* base-internal includes */ #include +/* core includes */ +#include + /** * Definition of capability meta data @@ -33,7 +35,7 @@ struct Genode::Native_capability::Data : Capability_data }; -using namespace Genode; +using namespace Core; /** diff --git a/repos/base/src/core/core_log.cc b/repos/base/src/core/core_log.cc index 8df8613bd3..88a043804c 100644 --- a/repos/base/src/core/core_log.cc +++ b/repos/base/src/core/core_log.cc @@ -12,11 +12,17 @@ * under the terms of the GNU Affero General Public License version 3. */ +/* Genode includes */ +#include + +/* core includes */ #include -static Genode::Core_log_range range { 0, 0 }; + +static Core::Core_log_range range { 0, 0 }; static unsigned range_pos { 0 }; + static void out_mem(char const c) { struct Log_memory @@ -25,7 +31,7 @@ static void out_mem(char const c) char data[1]; unsigned out(char const c, unsigned cur_pos, - Genode::Core_log_range const &range) + Core::Core_log_range const &range) { pos.value = cur_pos; data[cur_pos++] = c; @@ -40,10 +46,10 @@ static void out_mem(char const c) } -void Genode::init_core_log(Core_log_range const &r) { range = r; } +void Core::init_core_log(Core_log_range const &r) { range = r; } -void Genode::Core_log::output(char const * str) +void Core::Core_log::output(char const * str) { for (unsigned i = 0; i < Genode::strlen(str); i++) { out(str[i]); diff --git a/repos/base/src/core/core_mem_alloc.cc b/repos/base/src/core/core_mem_alloc.cc index e352ab6337..cbad2f1f61 100644 --- a/repos/base/src/core/core_mem_alloc.cc +++ b/repos/base/src/core/core_mem_alloc.cc @@ -13,13 +13,12 @@ */ /* Genode includes */ -#include #include /* local includes */ #include -using namespace Genode; +using namespace Core; void * Mapped_avl_allocator::map_addr(void * addr) @@ -83,8 +82,9 @@ void Mapped_mem_allocator::free(void *addr, size_t) if (!b) return; if (!_unmap_local((addr_t)addr, (addr_t)b->map_addr, b->size())) { - Genode::error("error on unmap virt=", addr, " phys=", - Hex_range((addr_t)b->map_addr, b->size())); + error("error on unmap virt=", addr, " phys=", + Hex_range((addr_t)b->map_addr, b->size())); + /* leak physical and virtual region because of unknown usage state */ return; } diff --git a/repos/base/src/core/core_region_map.cc b/repos/base/src/core/core_region_map.cc index 8fff99e350..3a186e3946 100644 --- a/repos/base/src/core/core_region_map.cc +++ b/repos/base/src/core/core_region_map.cc @@ -18,21 +18,19 @@ #include #include -using namespace Genode; +using namespace Core; -Region_map::Local_addr -Core_region_map::attach(Dataspace_capability ds_cap, size_t, off_t, bool, - Region_map::Local_addr, bool, bool) +Region_map::Attach_result +Core_region_map::attach(Dataspace_capability ds_cap, Attr const &) { - auto lambda = [] (Dataspace_component *ds) { + return _ep.apply(ds_cap, [] (Dataspace_component *ds) -> Attach_result { if (!ds) - throw Invalid_dataspace(); + return Attach_error::INVALID_DATASPACE; - return (void *)ds->phys_addr(); - }; - return _ep.apply(ds_cap, lambda); + return Range { .start = ds->phys_addr(), .num_bytes = ds->size() }; + }); } -void Core_region_map::detach(Local_addr) { } +void Core_region_map::detach(addr_t) { } diff --git a/repos/base/src/core/core_rpc_cap_alloc.cc b/repos/base/src/core/core_rpc_cap_alloc.cc index f26ffeee7c..b6d22d2ac8 100644 --- a/repos/base/src/core/core_rpc_cap_alloc.cc +++ b/repos/base/src/core/core_rpc_cap_alloc.cc @@ -14,16 +14,22 @@ /* Genode includes */ #include -/* core-local includes */ +/* core includes */ #include #include +/* base-internal includes */ +#include + using namespace Genode; -static Rpc_cap_factory &rpc_cap_factory() +void Genode::init_rpc_cap_alloc(Parent &) { } + + +static Core::Rpc_cap_factory &rpc_cap_factory() { - static Rpc_cap_factory inst(platform().core_mem_alloc()); + static Core::Rpc_cap_factory inst(Core::platform().core_mem_alloc()); return inst; } diff --git a/repos/base/src/core/cpu_session_component.cc b/repos/base/src/core/cpu_session_component.cc index 959e1ab113..e00093ea92 100644 --- a/repos/base/src/core/cpu_session_component.cc +++ b/repos/base/src/core/cpu_session_component.cc @@ -14,7 +14,6 @@ */ /* Genode includes */ -#include #include /* core includes */ @@ -23,20 +22,16 @@ #include #include -using namespace Genode; +using namespace Core; -Thread_capability Cpu_session_component::create_thread(Capability pd_cap, - Name const &name, - Affinity::Location affinity, - Weight weight, - addr_t utcb) +Cpu_session::Create_thread_result +Cpu_session_component::create_thread(Capability pd_cap, + Name const &name, Affinity::Location affinity, + Weight weight, addr_t utcb) { - Trace::Thread_name thread_name(name.string()); - - withdraw(Ram_quota{_utcb_quota_size()}); - - Cpu_thread_component *thread = 0; + if (!try_withdraw(Ram_quota{_utcb_quota_size()})) + return Create_thread_error::OUT_OF_RAM; if (weight.value == 0) { warning("Thread ", name, ": Bad weight 0, using default weight instead."); @@ -49,43 +44,53 @@ Thread_capability Cpu_session_component::create_thread(Capability pd Mutex::Guard thread_list_lock_guard(_thread_list_lock); - /* - * Create thread associated with its protection domain - */ - auto create_thread_lambda = [&] (Pd_session_component *pd) { + Create_thread_result result = Create_thread_error::DENIED; + + _incr_weight(weight.value); + + _thread_ep.apply(pd_cap, [&] (Pd_session_component *pd) { + if (!pd) { error("create_thread: invalid PD argument"); - throw Thread_creation_failed(); + return; } Mutex::Guard slab_lock_guard(_thread_alloc_lock); - thread = new (&_thread_alloc) - Cpu_thread_component( - cap(), _thread_ep, _pager_ep, *pd, _trace_control_area, - _trace_sources, weight, _weight_to_quota(weight.value), - _thread_affinity(affinity), _label, thread_name, - _priority, utcb); - }; - try { - _incr_weight(weight.value); - _thread_ep.apply(pd_cap, create_thread_lambda); - } catch (Allocator::Out_of_memory) { + pd->with_threads([&] (Pd_session_component::Threads &pd_threads) { + pd->with_platform_pd([&] (Platform_pd &platform_pd) { + try { + Cpu_thread_component &thread = *new (&_thread_alloc) + Cpu_thread_component( + cap(), *this, _thread_ep, _pager_ep, *pd, platform_pd, + pd_threads, _trace_control_area, _trace_sources, + weight, _weight_to_quota(weight.value), + _thread_affinity(affinity), _label, name, + _priority, utcb); + + if (!thread.valid()) { /* 'Platform_thread' creation failed */ + destroy(&_thread_alloc, &thread); + result = Create_thread_error::DENIED; + return; + } + + thread.session_exception_sigh(_exception_sigh); + + _thread_list.insert(&thread); + result = thread.cap(); + } + catch (Out_of_ram) { result = Create_thread_error::OUT_OF_RAM; } + catch (Out_of_caps) { result = Create_thread_error::OUT_OF_CAPS; } + catch (...) { result = Create_thread_error::DENIED; } + }); + }); + }); + + if (result.failed()) { _decr_weight(weight.value); - throw Out_of_ram(); - } catch (Native_capability::Reference_count_overflow) { - _decr_weight(weight.value); - throw Thread_creation_failed(); - } catch (...) { - _decr_weight(weight.value); - throw; + replenish(Ram_quota{_utcb_quota_size()}); } - - thread->session_exception_sigh(_exception_sigh); - - _thread_list.insert(thread); - - return thread->cap(); + return result; } @@ -378,11 +383,11 @@ size_t Cpu_session_component::_weight_to_quota(size_t const weight) const ** Trace::Source_registry ** ****************************/ -unsigned Trace::Source::_alloc_unique_id() +Core::Trace::Source::Id Core::Trace::Source::_alloc_unique_id() { static Mutex lock; static unsigned cnt; Mutex::Guard guard(lock); - return cnt++; + return { cnt++ }; } diff --git a/repos/base/src/core/cpu_session_support.cc b/repos/base/src/core/cpu_session_support.cc index 66f6523b81..7525b58dd3 100644 --- a/repos/base/src/core/cpu_session_support.cc +++ b/repos/base/src/core/cpu_session_support.cc @@ -11,13 +11,10 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* Genode includes */ -#include - /* core includes */ #include -using namespace Genode; +using namespace Core; Dataspace_capability Cpu_thread_component::utcb() diff --git a/repos/base/src/core/cpu_thread_component.cc b/repos/base/src/core/cpu_thread_component.cc index fdd21b198d..568bc4e947 100644 --- a/repos/base/src/core/cpu_thread_component.cc +++ b/repos/base/src/core/cpu_thread_component.cc @@ -12,9 +12,9 @@ */ /* core includes */ -#include +#include -using namespace Genode; +using namespace Core; void Cpu_thread_component::_update_exception_sigh() @@ -26,6 +26,9 @@ void Cpu_thread_component::_update_exception_sigh() } +void Cpu_thread_component::destroy() { _cpu.kill_thread(cap()); } + + void Cpu_thread_component::quota(size_t quota) { _platform_thread.quota(quota); diff --git a/repos/base/src/core/dataspace_component.cc b/repos/base/src/core/dataspace_component.cc index 1ba4f5ead5..57d99fb631 100644 --- a/repos/base/src/core/dataspace_component.cc +++ b/repos/base/src/core/dataspace_component.cc @@ -15,7 +15,7 @@ #include #include -using namespace Genode; +using namespace Core; void Dataspace_component::attached_to(Rm_region ®ion) @@ -31,6 +31,7 @@ void Dataspace_component::detached_from(Rm_region ®ion) _regions.remove(®ion); } + void Dataspace_component::detach_from_rm_sessions() { _mutex.acquire(); @@ -39,17 +40,19 @@ void Dataspace_component::detach_from_rm_sessions() while (Rm_region *r = _regions.first()) { /* - * The 'detach' function calls 'Dataspace_component::detached_from' - * and thereby removes the current region from the '_regions' list. + * The 'reserve_and_flush' function calls + * 'Dataspace_component::detached_from' and thereby + * removes the current region from the '_regions' list. */ _mutex.release(); - r->rm().detach((void *)r->base()); + r->rm().reserve_and_flush(r->base()); _mutex.acquire(); } _mutex.release(); } + Dataspace_component::~Dataspace_component() { detach_from_rm_sessions(); diff --git a/repos/base/src/core/default_log.cc b/repos/base/src/core/default_log.cc index 01a52833a9..1da89e4deb 100644 --- a/repos/base/src/core/default_log.cc +++ b/repos/base/src/core/default_log.cc @@ -13,7 +13,6 @@ */ /* Genode includes */ -#include #include /* base-internal includes */ @@ -28,7 +27,7 @@ Genode::Log &Genode::Log::log() { struct Buffer { - struct Write_fn : Core_log + struct Write_fn : Core::Core_log { void operator () (char const *s) { output(s); } } function { }; diff --git a/repos/base/src/core/heartbeat.cc b/repos/base/src/core/heartbeat.cc index 146d827cf4..e696c024a3 100644 --- a/repos/base/src/core/heartbeat.cc +++ b/repos/base/src/core/heartbeat.cc @@ -19,5 +19,4 @@ void Genode::init_heartbeat_monitoring(Env &) { } -void Genode::deinit_heartbeat_monitoring() { } diff --git a/repos/base/src/core/include/account.h b/repos/base/src/core/include/account.h index fda6370ad6..81412178b8 100644 --- a/repos/base/src/core/include/account.h +++ b/repos/base/src/core/include/account.h @@ -14,15 +14,17 @@ #ifndef _CORE__INCLUDE__ACCOUNT_H_ #define _CORE__INCLUDE__ACCOUNT_H_ -#include #include #include -namespace Genode { template class Account; } +/* core includes */ +#include + +namespace Core { template class Account; } template -class Genode::Account +class Core::Account { private: @@ -85,7 +87,7 @@ class Genode::Account public: - typedef typename Quota_guard::Limit_exceeded Limit_exceeded; + using Limit_exceeded = typename Quota_guard::Limit_exceeded; class Unrelated_account : Exception { }; @@ -190,6 +192,17 @@ class Genode::Account _quota_guard.withdraw(amount); } + /** + * Withdraw quota from account + * + * \return true if withdrawal of 'amount' succeeded + */ + [[nodiscard]] bool try_withdraw(UNIT amount) + { + Mutex::Guard guard(_mutex); + return _quota_guard.try_withdraw(amount); + } + /** * Replenish quota to account * diff --git a/repos/base/src/core/include/addr_range.h b/repos/base/src/core/include/addr_range.h new file mode 100644 index 0000000000..b4ff2dd783 --- /dev/null +++ b/repos/base/src/core/include/addr_range.h @@ -0,0 +1,62 @@ +/* + * \brief Memory-address range + * \author Norman Feske + * \date 2023-06-11 + */ + +/* + * Copyright (C) 2023 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CORE__INCLUDE__ADDR_RANGE_H_ +#define _CORE__INCLUDE__ADDR_RANGE_H_ + +/* core includes */ +#include + +namespace Core { struct Addr_range; } + + +struct Core::Addr_range +{ + addr_t start; + addr_t end; /* last byte */ + + bool valid() const { return end > start; } + + Addr_range intersected(Addr_range const &other) const + { + if (!valid() || !other.valid()) + return { }; + + return { max(start, other.start), min(end, other.end) }; + } + + bool contains(addr_t at) const { return (at >= start) && (at <= end); } + + Addr_range reduced_by(addr_t offset) const + { + if (!valid() || (offset > start)) + return { }; + + return Addr_range { start - offset, end - offset }; + } + + Addr_range increased_by(addr_t offset) const + { + if (!valid() || (offset + start < offset) || (offset + end < offset)) + return { }; + + return Addr_range { start + offset, end + offset }; + } + + void print(Output &out) const + { + Genode::print(out, "[", Hex(start), ",", Hex(end), "]"); + } +}; + +#endif /* _CORE__INCLUDE__ADDR_RANGE_H_ */ diff --git a/repos/base/src/core/include/address_space.h b/repos/base/src/core/include/address_space.h index 185e9bede8..b0eaf525be 100644 --- a/repos/base/src/core/include/address_space.h +++ b/repos/base/src/core/include/address_space.h @@ -14,13 +14,17 @@ #ifndef _CORE__INCLUDE__ADDRESS_SPACE_H_ #define _CORE__INCLUDE__ADDRESS_SPACE_H_ -#include +/* Genode includes */ #include -namespace Genode { struct Address_space; } +/* core includes */ +#include -struct Genode::Address_space : private Weak_object, - public Interface +namespace Core { struct Address_space; } + + +struct Core::Address_space : private Weak_object, + public Interface { friend class Locked_ptr; diff --git a/repos/base/src/core/include/assertion.h b/repos/base/src/core/include/assertion.h index ec9ccc6e67..b14f189062 100644 --- a/repos/base/src/core/include/assertion.h +++ b/repos/base/src/core/include/assertion.h @@ -21,7 +21,7 @@ do { \ Genode::error("Unexpected call of '", __FUNCTION__, "' " \ "(", __FILE__, ":", __LINE__, ")"); \ - for (;;); throw 0UL; \ + for (;;); \ } while (false) #endif /* _CORE__INCLUDE__ASSERTION_H_ */ diff --git a/repos/base/src/core/include/boot_modules.h b/repos/base/src/core/include/boot_modules.h index 789ff630a9..5ec33fafe7 100644 --- a/repos/base/src/core/include/boot_modules.h +++ b/repos/base/src/core/include/boot_modules.h @@ -14,18 +14,22 @@ #ifndef _CORE__INCLUDE__BOOT_MODULES_H_ #define _CORE__INCLUDE__BOOT_MODULES_H_ -namespace Genode { struct Boot_modules_header; } +/* core includes */ +#include -struct Genode::Boot_modules_header +namespace Core { struct Boot_modules_header; } + + +struct Core::Boot_modules_header { long name; /* physical address of null-terminated string */ long base; /* physical address of module data */ long size; /* size of module data in bytes */ }; -extern Genode::Boot_modules_header _boot_modules_headers_begin; -extern Genode::Boot_modules_header _boot_modules_headers_end; -extern int _boot_modules_binaries_begin; -extern int _boot_modules_binaries_end; +extern Core::Boot_modules_header _boot_modules_headers_begin; +extern Core::Boot_modules_header _boot_modules_headers_end; +extern int _boot_modules_binaries_begin; +extern int _boot_modules_binaries_end; #endif /* _CORE__INCLUDE__BOOT_MODULES_H_ */ diff --git a/repos/base/src/core/include/constrained_core_ram.h b/repos/base/src/core/include/constrained_core_ram.h index 02ff3fb8ab..393ed923c3 100644 --- a/repos/base/src/core/include/constrained_core_ram.h +++ b/repos/base/src/core/include/constrained_core_ram.h @@ -15,11 +15,16 @@ #ifndef _CORE__INCLUDE__CORE_CONSTRAINED_CORE_RAM_H_ #define _CORE__INCLUDE__CORE_CONSTRAINED_CORE_RAM_H_ +/* Genode includes */ #include -namespace Genode { class Constrained_core_ram; } +/* core includes */ +#include -class Genode::Constrained_core_ram : public Allocator +namespace Core { class Constrained_core_ram; } + + +class Core::Constrained_core_ram : public Allocator { private: @@ -27,7 +32,7 @@ class Genode::Constrained_core_ram : public Allocator Cap_quota_guard &_cap_guard; Range_allocator &_core_mem; - uint64_t core_mem_allocated { 0 }; + Genode::uint64_t core_mem_allocated { 0 }; public: diff --git a/repos/base/src/core/include/core_capability_space.h b/repos/base/src/core/include/core_capability_space.h index 8bce5980ae..7185789760 100644 --- a/repos/base/src/core/include/core_capability_space.h +++ b/repos/base/src/core/include/core_capability_space.h @@ -17,10 +17,15 @@ /* base-internal includes */ #include -namespace Genode { class Cap_sel; class Pd_session; } +/* core includes */ +#include +namespace Genode { -namespace Genode { namespace Capability_space { + class Pd_session; + class Cap_sel; + + namespace Capability_space { /** * Create new RPC object capability for the specified entrypoint @@ -29,7 +34,7 @@ namespace Genode { namespace Capability_space { Pd_session const *, Rpc_obj_key); - Native_capability create_notification_cap(Genode::Cap_sel ¬ify_cap); + Native_capability create_notification_cap(Cap_sel ¬ify_cap); } } #endif /* _CORE__INCLUDE__CORE_CAPABILITY_SPACE_H_ */ diff --git a/repos/base/src/core/include/core_env.h b/repos/base/src/core/include/core_env.h index 9f7278ed9d..fef3b37bf8 100644 --- a/repos/base/src/core/include/core_env.h +++ b/repos/base/src/core/include/core_env.h @@ -17,7 +17,6 @@ /* Genode includes */ #include -#include /* base-internal includes */ #include @@ -29,14 +28,14 @@ #include #include -namespace Genode { +namespace Core { class Core_env; extern Core_env &core_env(); } -class Genode::Core_env : public Env_deprecated, Noncopyable +class Core::Core_env : public Noncopyable { private: @@ -76,29 +75,24 @@ class Genode::Core_env : public Env_deprecated, Noncopyable _region_map, *((Pager_entrypoint *)nullptr), "" /* args to native PD */, - platform_specific().core_mem_alloc()) + platform_specific().core_mem_alloc(), + *((Core::System_control *)nullptr)) { _pd_session.init_cap_and_ram_accounts(); } - ~Core_env() { parent()->exit(0); } - Rpc_entrypoint &entrypoint() { return _entrypoint; } Ram_allocator &ram_allocator() { return _synced_ram_allocator; } Region_map &local_rm() { return _region_map; } Rpc_entrypoint &signal_ep(); - /****************************** - ** Env_deprecated interface ** - ******************************/ - - Parent *parent() override { return nullptr; } - Region_map *rm_session() override { return &_region_map; } - Pd_session *pd_session() override { return &_pd_session; } - Cpu_session *cpu_session() override { ASSERT_NEVER_CALLED; } - Cpu_session_capability cpu_session_cap() override { ASSERT_NEVER_CALLED; } - Pd_session_capability pd_session_cap() override { return _pd_session.cap(); } + Parent *parent() { return nullptr; } + Region_map *rm_session() { return &_region_map; } + Pd_session *pd_session() { return &_pd_session; } + Cpu_session *cpu_session() { ASSERT_NEVER_CALLED; } + Cpu_session_capability cpu_session_cap() { ASSERT_NEVER_CALLED; } + Pd_session_capability pd_session_cap() { return _pd_session.cap(); } }; #endif /* _CORE__INCLUDE__CORE_ENV_H_ */ diff --git a/repos/base/src/core/include/core_log.h b/repos/base/src/core/include/core_log.h index b298180226..88d1b92e7b 100644 --- a/repos/base/src/core/include/core_log.h +++ b/repos/base/src/core/include/core_log.h @@ -15,9 +15,11 @@ #ifndef _CORE_LOG_H_ #define _CORE_LOG_H_ -#include +/* core includes */ +#include + +namespace Core { -namespace Genode { struct Core_log; struct Core_log_range { @@ -29,7 +31,7 @@ namespace Genode { } -struct Genode::Core_log +struct Core::Core_log { void out(char const c); diff --git a/repos/base/src/core/include/core_mem_alloc.h b/repos/base/src/core/include/core_mem_alloc.h index dcd317e75f..783772b71c 100644 --- a/repos/base/src/core/include/core_mem_alloc.h +++ b/repos/base/src/core/include/core_mem_alloc.h @@ -15,12 +15,16 @@ #ifndef _CORE__INCLUDE__CORE_MEM_ALLOC_H_ #define _CORE__INCLUDE__CORE_MEM_ALLOC_H_ +/* Genode includes */ #include #include + +/* core includes */ #include #include -namespace Genode { +namespace Core { + class Core_mem_translator; class Core_mem_allocator; @@ -39,7 +43,7 @@ namespace Genode { * Interface of an allocator that allows to return physical addresses * of its used virtual address ranges, and vice versa. */ -class Genode::Core_mem_translator : public Genode::Range_allocator +class Core::Core_mem_translator : public Range_allocator { public: @@ -62,14 +66,13 @@ class Genode::Core_mem_translator : public Genode::Range_allocator /** * Metadata for allocator blocks that stores a related address */ -struct Genode::Metadata { void * map_addr; }; +struct Core::Metadata { void * map_addr; }; /** * Page-size granular allocator that links ranges to related ones. */ -class Genode::Mapped_avl_allocator -: public Genode::Allocator_avl_tpl +class Core::Mapped_avl_allocator : public Allocator_avl_tpl { friend class Mapped_mem_allocator; @@ -99,7 +102,7 @@ class Genode::Mapped_avl_allocator * meta-data allocator for the other allocators and as back end for core's * synchronized memory allocator. */ -class Genode::Mapped_mem_allocator : public Genode::Core_mem_translator +class Core::Mapped_mem_allocator : public Core_mem_translator { private: @@ -196,7 +199,7 @@ class Genode::Mapped_mem_allocator : public Genode::Core_mem_translator * The class itself implements a ready-to-use memory allocator for * core that allows to allocate memory at page granularity only. */ -class Genode::Core_mem_allocator : public Genode::Core_mem_translator +class Core::Core_mem_allocator : public Core_mem_translator { protected: diff --git a/repos/base/src/core/include/core_region_map.h b/repos/base/src/core/include/core_region_map.h index d322a0f35d..28623cd0e0 100644 --- a/repos/base/src/core/include/core_region_map.h +++ b/repos/base/src/core/include/core_region_map.h @@ -21,10 +21,10 @@ /* core includes */ #include -namespace Genode { class Core_region_map; } +namespace Core { class Core_region_map; } -class Genode::Core_region_map : public Region_map +class Core::Core_region_map : public Region_map { private: @@ -34,18 +34,11 @@ class Genode::Core_region_map : public Region_map Core_region_map(Rpc_entrypoint &ep) : _ep(ep) { } - Local_addr attach(Dataspace_capability, size_t size = 0, - off_t offset=0, bool use_local_addr = false, - Local_addr local_addr = 0, - bool executable = false, - bool writeable = true) override; - - void detach(Local_addr) override; - - void fault_handler (Signal_context_capability) override { } - State state () override { return State(); } - - Dataspace_capability dataspace() override { return Dataspace_capability(); } + Attach_result attach(Dataspace_capability, Attr const &) override; + void detach(addr_t) override; + void fault_handler (Signal_context_capability) override { } + Fault fault() override { return { }; } + Dataspace_capability dataspace() override { return { }; } }; #endif /* _CORE__INCLUDE__CORE_REGION_MAP_H_ */ diff --git a/repos/base/src/core/include/core_service.h b/repos/base/src/core/include/core_service.h index 4f0ef1185c..7d59099cc3 100644 --- a/repos/base/src/core/include/core_service.h +++ b/repos/base/src/core/include/core_service.h @@ -16,11 +16,14 @@ #include -namespace Genode { template struct Core_service; } +/* core includes */ +#include + +namespace Core { template struct Core_service; } template -struct Genode::Core_service : Local_service +struct Core::Core_service : Local_service { Registry::Element _element; diff --git a/repos/base/src/core/include/cpu_root.h b/repos/base/src/core/include/cpu_root.h index 63241398af..9d3cb0d1d1 100644 --- a/repos/base/src/core/include/cpu_root.h +++ b/repos/base/src/core/include/cpu_root.h @@ -20,71 +20,71 @@ /* Core includes */ #include -namespace Genode { +namespace Core { class Cpu_root; } - class Cpu_root : public Root_component - { - private: - Ram_allocator &_ram_alloc; - Region_map &_local_rm; - Rpc_entrypoint &_thread_ep; - Pager_entrypoint &_pager_ep; - Trace::Source_registry &_trace_sources; +class Core::Cpu_root : public Root_component +{ + private: - protected: + Ram_allocator &_ram_alloc; + Region_map &_local_rm; + Rpc_entrypoint &_thread_ep; + Pager_entrypoint &_pager_ep; + Trace::Source_registry &_trace_sources; - Cpu_session_component *_create_session(char const *args, - Affinity const &affinity) override { + protected: - size_t ram_quota = - Arg_string::find_arg(args, "ram_quota").ulong_value(0); + Cpu_session_component *_create_session(char const *args, + Affinity const &affinity) override { - if (ram_quota < Trace::Control_area::SIZE) - throw Insufficient_ram_quota(); + size_t ram_quota = + Arg_string::find_arg(args, "ram_quota").ulong_value(0); - if (!affinity.valid()) - throw Service_denied(); + if (ram_quota < Trace::Control_area::SIZE) + throw Insufficient_ram_quota(); - return new (md_alloc()) - Cpu_session_component(*this->ep(), - session_resources_from_args(args), - session_label_from_args(args), - session_diag_from_args(args), - _ram_alloc, _local_rm, - _thread_ep, _pager_ep, _trace_sources, - args, affinity, 0); - } + if (!affinity.valid()) + throw Service_denied(); - void _upgrade_session(Cpu_session_component *cpu, const char *args) override - { - cpu->upgrade(ram_quota_from_args(args)); - cpu->upgrade(cap_quota_from_args(args)); - } + return new (md_alloc()) + Cpu_session_component(*this->ep(), + session_resources_from_args(args), + session_label_from_args(args), + session_diag_from_args(args), + _ram_alloc, _local_rm, + _thread_ep, _pager_ep, _trace_sources, + args, affinity, 0); + } - public: + void _upgrade_session(Cpu_session_component *cpu, const char *args) override + { + cpu->upgrade(ram_quota_from_args(args)); + cpu->upgrade(cap_quota_from_args(args)); + } - /** - * Constructor - * - * \param session_ep entry point for managing cpu session objects - * \param thread_ep entry point for managing threads - * \param md_alloc meta data allocator to be used by root component - */ - Cpu_root(Ram_allocator &ram_alloc, - Region_map &local_rm, - Rpc_entrypoint &session_ep, - Rpc_entrypoint &thread_ep, - Pager_entrypoint &pager_ep, - Allocator &md_alloc, - Trace::Source_registry &trace_sources) - : - Root_component(&session_ep, &md_alloc), - _ram_alloc(ram_alloc), _local_rm(local_rm), - _thread_ep(thread_ep), _pager_ep(pager_ep), - _trace_sources(trace_sources) - { } - }; -} + public: + + /** + * Constructor + * + * \param session_ep entry point for managing cpu session objects + * \param thread_ep entry point for managing threads + * \param md_alloc meta data allocator to be used by root component + */ + Cpu_root(Ram_allocator &ram_alloc, + Region_map &local_rm, + Rpc_entrypoint &session_ep, + Rpc_entrypoint &thread_ep, + Pager_entrypoint &pager_ep, + Allocator &md_alloc, + Trace::Source_registry &trace_sources) + : + Root_component(&session_ep, &md_alloc), + _ram_alloc(ram_alloc), _local_rm(local_rm), + _thread_ep(thread_ep), _pager_ep(pager_ep), + _trace_sources(trace_sources) + { } +}; #endif /* _CORE__INCLUDE__CPU_ROOT_H_ */ diff --git a/repos/base/src/core/include/cpu_session_component.h b/repos/base/src/core/include/cpu_session_component.h index 328a498911..78559171e2 100644 --- a/repos/base/src/core/include/cpu_session_component.h +++ b/repos/base/src/core/include/cpu_session_component.h @@ -32,11 +32,11 @@ #include #include -namespace Genode { class Cpu_session_component; } +namespace Core { class Cpu_session_component; } -class Genode::Cpu_session_component : public Session_object, - private List::Element +class Core::Cpu_session_component : public Session_object, + private List::Element { private: @@ -166,8 +166,8 @@ class Genode::Cpu_session_component : public Session_object, ** CPU session interface ** ***************************/ - Thread_capability create_thread(Capability, Name const &, - Affinity::Location, Weight, addr_t) override; + Create_thread_result create_thread(Capability, Name const &, + Affinity::Location, Weight, addr_t) override; void kill_thread(Thread_capability) override; void exception_sigh(Signal_context_capability) override; Affinity::Space affinity_space() const override; diff --git a/repos/base/src/core/include/cpu_thread_allocator.h b/repos/base/src/core/include/cpu_thread_allocator.h index e845d52325..4299c67db3 100644 --- a/repos/base/src/core/include/cpu_thread_allocator.h +++ b/repos/base/src/core/include/cpu_thread_allocator.h @@ -18,11 +18,14 @@ #include #include +/* core includes */ +#include + /* base-internal includes */ #include -namespace Genode -{ +namespace Core { + class Cpu_thread_component; /** @@ -31,8 +34,8 @@ namespace Genode * We take the knowledge about the used backing-store allocator (sliced * heap) into account to make sure that slab blocks fill whole pages. */ - typedef Tslab - Cpu_thread_allocator; + using Cpu_thread_allocator = + Tslab; } #endif /* _CORE__INCLUDE__CPU_THREAD_ALLOCATOR_H_ */ diff --git a/repos/base/src/core/include/cpu_thread_component.h b/repos/base/src/core/include/cpu_thread_component.h index e1b9652a5e..626f222464 100644 --- a/repos/base/src/core/include/cpu_thread_component.h +++ b/repos/base/src/core/include/cpu_thread_component.h @@ -28,16 +28,21 @@ #include #include -namespace Genode { class Cpu_thread_component; } +namespace Core { + class Cpu_session_component; + class Cpu_thread_component; +} -class Genode::Cpu_thread_component : public Rpc_object, - private List::Element, - public Trace::Source::Info_accessor +class Core::Cpu_thread_component : public Rpc_object, + private List::Element, + public Trace::Source::Info_accessor { public: - typedef Trace::Thread_name Thread_name; + using Thread_name = Trace::Thread_name; + + using Pd_threads = Pd_session_component::Threads; private: @@ -46,19 +51,13 @@ class Genode::Cpu_thread_component : public Rpc_object, Rpc_entrypoint &_ep; Pager_entrypoint &_pager_ep; + Cpu_session_component &_cpu; Region_map_component &_address_space_region_map; Cpu_session::Weight const _weight; Session_label const _session_label; Thread_name const _name; + Pd_threads::Element _pd_element; Platform_thread _platform_thread; - bool const _bound_to_pd; - - bool _bind_to_pd(Pd_session_component &pd) - { - if (!pd.bind_thread(_platform_thread)) - throw Cpu_session::Thread_creation_failed(); - return true; - } /** * Exception handler as defined by 'Cpu_session::exception_sigh' @@ -140,9 +139,12 @@ class Genode::Cpu_thread_component : public Rpc_object, * \param utcb user-local UTCB base */ Cpu_thread_component(Cpu_session_capability cpu_session_cap, + Cpu_session_component &cpu, Rpc_entrypoint &ep, Pager_entrypoint &pager_ep, Pd_session_component &pd, + Platform_pd &platform_pd, + Pd_threads &pd_threads, Trace::Control_area &trace_control_area, Trace::Source_registry &trace_sources, Cpu_session::Weight weight, @@ -153,12 +155,12 @@ class Genode::Cpu_thread_component : public Rpc_object, unsigned priority, addr_t utcb) : - _ep(ep), _pager_ep(pager_ep), + _ep(ep), _pager_ep(pager_ep), _cpu(cpu), _address_space_region_map(pd.address_space_region_map()), _weight(weight), _session_label(label), _name(name), - _platform_thread(quota, name.string(), priority, location, utcb), - _bound_to_pd(_bind_to_pd(pd)), + _pd_element(pd_threads, *this), + _platform_thread(platform_pd, quota, name.string(), priority, location, utcb), _trace_control_slot(trace_control_area), _trace_sources(trace_sources), _managed_thread_cap(_ep, *this), @@ -183,6 +185,10 @@ class Genode::Cpu_thread_component : public Rpc_object, _address_space_region_map.remove_client(_rm_client); } + bool valid() { return _platform_thread.valid(); } + + void destroy(); /* solely called by ~Pd_session_component */ + /******************************************** ** Trace::Source::Info_accessor interface ** diff --git a/repos/base/src/core/include/dataspace_component.h b/repos/base/src/core/include/dataspace_component.h index 933638716b..70cbe6c085 100644 --- a/repos/base/src/core/include/dataspace_component.h +++ b/repos/base/src/core/include/dataspace_component.h @@ -23,142 +23,159 @@ /* core includes */ #include -namespace Genode { +namespace Core { class Rm_region; + class Dataspace_component; /** * Deriving classes can own a dataspace to implement conditional behavior */ class Dataspace_owner : Interface { }; - - class Dataspace_component : public Rpc_object - { - private: - - addr_t const _phys_addr = 0; /* address of dataspace in physical memory */ - addr_t _core_local_addr = 0; /* address of core-local mapping */ - size_t const _size = 0; /* size of dataspace in bytes */ - bool const _io_mem = false; /* dataspace is I/O mem, not to be touched */ - bool const _writeable = false; /* false if dataspace is read-only */ - - /* - * Access memory cached, write-combined, or uncached respectively - */ - Cache const _cache { CACHED }; - - List _regions { }; /* regions this is attached to */ - Mutex _mutex { }; - - /* - * Holds the dataspace owner if a distinction between owner and - * others is necessary on the dataspace, otherwise it is 0. - */ - Dataspace_owner const * _owner = nullptr; - - /* - * Noncopyable - */ - Dataspace_component(Dataspace_component const &); - Dataspace_component &operator = (Dataspace_component const &); - - protected: - - bool _managed = false; /* true if this is a managed dataspace */ - - public: - - /** - * Default constructor returning an invalid dataspace - */ - Dataspace_component() { } - - /** - * Constructor for non-I/O dataspaces - * - * This constructor is used by RAM and ROM dataspaces. - */ - Dataspace_component(size_t size, addr_t core_local_addr, - Cache cache, bool writeable, - Dataspace_owner *owner) - : - _phys_addr(core_local_addr), _core_local_addr(core_local_addr), - _size(round_page(size)), _io_mem(false), - _writeable(writeable), _cache(cache), - _owner(owner), _managed(false) { } - - /** - * Constructor for dataspaces with different core-local and - * physical addresses - * - * This constructor is used by IO_MEM. Because I/O-memory areas may - * be located at addresses that are populated by data or text in - * Core's virtual address space, we need to map these areas to - * another core-local address. The local mapping in core's address - * space is needed to send a mapping to another address space. - */ - Dataspace_component(size_t size, addr_t core_local_addr, - addr_t phys_addr, Cache cache, - bool writeable, Dataspace_owner *owner) - : - _phys_addr(phys_addr), _core_local_addr(core_local_addr), - _size(size), _io_mem(true), _writeable(writeable), - _cache(cache), _owner(owner), _managed(false) { } - - /** - * Destructor - */ - ~Dataspace_component(); - - /** - * Return region map corresponding to nested dataspace - * - * \retval invalid capability if dataspace is not a nested one - */ - virtual Native_capability sub_rm() { return Dataspace_capability(); } - - addr_t core_local_addr() const { return _core_local_addr; } - bool io_mem() const { return _io_mem; } - Cache cacheability() const { return _cache; } - addr_t phys_addr() const { return _phys_addr; } - bool managed() const { return _managed; } - - /** - * Return dataspace base address to be used for map operations - * - * Depending on the used kernel, this may be a core-local address - * or a physical address. - */ - addr_t map_src_addr() const - { - return Genode::map_src_addr(_core_local_addr, _phys_addr); - } - - void assign_core_local_addr(void *addr) { _core_local_addr = (addr_t)addr; } - - void attached_to(Rm_region ®ion); - void detached_from(Rm_region ®ion); - - /** - * Detach dataspace from all rm sessions. - */ - void detach_from_rm_sessions(); - - /** - * Check if dataspace is owned by a specific owner - */ - bool owner(Dataspace_owner const &o) const { return _owner == &o; } - - List ®ions() { return _regions; } - - - /************************* - ** Dataspace interface ** - *************************/ - - size_t size() override { return _size; } - bool writeable() override { return _writeable; } - }; } + +class Core::Dataspace_component : public Rpc_object +{ + public: + + struct Attr { addr_t base; size_t size; bool writeable; }; + + private: + + addr_t const _phys_addr = 0; /* address of dataspace in physical memory */ + addr_t _core_local_addr = 0; /* address of core-local mapping */ + size_t const _size = 0; /* size of dataspace in bytes */ + bool const _io_mem = false; /* dataspace is I/O mem, not to be touched */ + bool const _writeable = false; /* false if dataspace is read-only */ + + /* + * Access memory cached, write-combined, or uncached respectively + */ + Cache const _cache { CACHED }; + + List _regions { }; /* regions this is attached to */ + Mutex _mutex { }; + + /* + * Holds the dataspace owner if a distinction between owner and + * others is necessary on the dataspace, otherwise it is 0. + */ + Dataspace_owner const * _owner = nullptr; + + /* + * Noncopyable + */ + Dataspace_component(Dataspace_component const &); + Dataspace_component &operator = (Dataspace_component const &); + + protected: + + bool _managed = false; /* true if this is a managed dataspace */ + + public: + + /** + * Default constructor returning an invalid dataspace + */ + Dataspace_component() { } + + /** + * Constructor for non-I/O dataspaces + * + * This constructor is used by RAM and ROM dataspaces. + */ + Dataspace_component(size_t size, addr_t core_local_addr, + Cache cache, bool writeable, + Dataspace_owner *owner) + : + _phys_addr(core_local_addr), _core_local_addr(core_local_addr), + _size(round_page(size)), _io_mem(false), + _writeable(writeable), _cache(cache), + _owner(owner), _managed(false) { } + + /** + * Constructor for dataspaces with different core-local and + * physical addresses + * + * This constructor is used by IO_MEM. Because I/O-memory areas may + * be located at addresses that are populated by data or text in + * Core's virtual address space, we need to map these areas to + * another core-local address. The local mapping in core's address + * space is needed to send a mapping to another address space. + */ + Dataspace_component(size_t size, addr_t core_local_addr, + addr_t phys_addr, Cache cache, + bool writeable, Dataspace_owner *owner) + : + _phys_addr(phys_addr), _core_local_addr(core_local_addr), + _size(size), _io_mem(true), _writeable(writeable), + _cache(cache), _owner(owner), _managed(false) { } + + /** + * Destructor + */ + ~Dataspace_component(); + + /** + * Return region map corresponding to nested dataspace + * + * \retval invalid capability if dataspace is not a nested one + */ + virtual Native_capability sub_rm() { return Dataspace_capability(); } + + addr_t core_local_addr() const { return _core_local_addr; } + bool io_mem() const { return _io_mem; } + Cache cacheability() const { return _cache; } + addr_t phys_addr() const { return _phys_addr; } + bool managed() const { return _managed; } + + /** + * Return dataspace base address to be used for map operations + * + * Depending on the used kernel, this may be a core-local address + * or a physical address. + */ + addr_t map_src_addr() const + { + return Core::map_src_addr(_core_local_addr, _phys_addr); + } + + Attr attr() const { return { .base = map_src_addr(), + .size = _size, + .writeable = _writeable }; } + + void assign_core_local_addr(void *addr) { _core_local_addr = (addr_t)addr; } + + void attached_to(Rm_region ®ion); + void detached_from(Rm_region ®ion); + + /** + * Detach dataspace from all rm sessions. + */ + void detach_from_rm_sessions(); + + /** + * Check if dataspace is owned by a specific owner + */ + bool owner(Dataspace_owner const &o) const { return _owner == &o; } + + List ®ions() { return _regions; } + + + /************************* + ** Dataspace interface ** + *************************/ + + size_t size() override { return _size; } + bool writeable() override { return _writeable; } + + + void print(Output &out) const + { + addr_t const base = map_src_addr(); + Genode::print(out, "[", Hex(base), ",", Hex(base + _size - 1), "]"); + } +}; + #endif /* _CORE__INCLUDE__DATASPACE_COMPONENT_H_ */ diff --git a/repos/base/src/core/include/io_mem_root.h b/repos/base/src/core/include/io_mem_root.h index ad17f12f66..4695f29578 100644 --- a/repos/base/src/core/include/io_mem_root.h +++ b/repos/base/src/core/include/io_mem_root.h @@ -16,48 +16,49 @@ #include -#include "io_mem_session_component.h" +/* core includes */ +#include -namespace Genode { +namespace Core { class Io_mem_root; } - class Io_mem_root : public Root_component - { - private: +class Core::Io_mem_root : public Root_component +{ - Range_allocator &_io_mem_alloc; /* MMIO region allocator */ - Range_allocator &_ram_alloc; /* RAM allocator */ - Rpc_entrypoint &_ds_ep; /* entry point for managing io_mem dataspaces */ + private: - protected: + Range_allocator &_io_mem_alloc; /* MMIO region allocator */ + Range_allocator &_ram_alloc; /* RAM allocator */ + Rpc_entrypoint &_ds_ep; /* entry point for managing io_mem dataspaces */ - Io_mem_session_component *_create_session(const char *args) override - { - return new (md_alloc()) - Io_mem_session_component(_io_mem_alloc, _ram_alloc, - _ds_ep, args); - } + protected: - public: + Io_mem_session_component *_create_session(const char *args) override + { + return new (md_alloc()) + Io_mem_session_component(_io_mem_alloc, _ram_alloc, + _ds_ep, args); + } - /** - * Constructor - * - * \param session_ep entry point for managing io_mem session objects - * \param ds_ep entry point for managing dataspaces - * \param io_mem_alloc platform IO_MEM allocator - * \param ram_alloc platform RAM allocator - * \param md_alloc meta-data allocator to be used by root component - */ - Io_mem_root(Rpc_entrypoint &session_ep, - Rpc_entrypoint &ds_ep, - Range_allocator &io_mem_alloc, - Range_allocator &ram_alloc, - Allocator &md_alloc) - : - Root_component(&session_ep, &md_alloc), - _io_mem_alloc(io_mem_alloc), _ram_alloc(ram_alloc), _ds_ep(ds_ep) { } - }; -} + public: + + /** + * Constructor + * + * \param session_ep entry point for managing io_mem session objects + * \param ds_ep entry point for managing dataspaces + * \param io_mem_alloc platform IO_MEM allocator + * \param ram_alloc platform RAM allocator + * \param md_alloc meta-data allocator to be used by root component + */ + Io_mem_root(Rpc_entrypoint &session_ep, + Rpc_entrypoint &ds_ep, + Range_allocator &io_mem_alloc, + Range_allocator &ram_alloc, + Allocator &md_alloc) + : + Root_component(&session_ep, &md_alloc), + _io_mem_alloc(io_mem_alloc), _ram_alloc(ram_alloc), _ds_ep(ds_ep) { } +}; #endif /* _CORE__INCLUDE__IO_MEM_ROOT_H_ */ diff --git a/repos/base/src/core/include/io_mem_session_component.h b/repos/base/src/core/include/io_mem_session_component.h index 77fb30eb9e..93a6ea08bf 100644 --- a/repos/base/src/core/include/io_mem_session_component.h +++ b/repos/base/src/core/include/io_mem_session_component.h @@ -22,128 +22,128 @@ /* core includes */ #include -namespace Genode { - - class Io_mem_session_component : public Rpc_object - { - private: - - /* - * Helper class used to pass the dataspace attributes as - * parameters from the _prepare_io_mem function to the - * constructor of Dataspace_component. - */ - struct Dataspace_attr - { - size_t size { 0 }; - addr_t core_local_addr { 0 }; - addr_t phys_addr { 0 }; - Cache cacheable { UNCACHED }; - - /** - * Base address of request used for freeing mem-ranges - */ - addr_t req_base { 0 }; - - /** - * Default constructor - * - * This constructor enables Dataspace_attr objects to be - * returned from the '_prepare_io_mem' function. - */ - Dataspace_attr() { } - - /** - * Constructor - * - * An invalid dataspace is represented by setting all - * arguments to zero. - */ - Dataspace_attr(size_t s, addr_t cla, addr_t pa, Cache c, - addr_t req_base) - : - size(s), core_local_addr(cla), phys_addr(pa), - cacheable(c), req_base(req_base) { } - }; - - struct Io_dataspace_component : Dataspace_component - { - addr_t req_base; - - /** - * Constructor - */ - Io_dataspace_component(Dataspace_attr da) - : - Dataspace_component(da.size, da.core_local_addr, - da.phys_addr, da.cacheable, - true, 0), - req_base(da.req_base) { } +namespace Core { class Io_mem_session_component; } - bool valid() { return size() != 0; } - }; +class Core::Io_mem_session_component : public Rpc_object +{ + private: - Range_allocator &_io_mem_alloc; - Io_dataspace_component _ds; - Rpc_entrypoint &_ds_ep; - Io_mem_dataspace_capability _ds_cap { }; - Cache _cacheable { UNCACHED }; - - Dataspace_attr _prepare_io_mem(const char *args, Range_allocator &ram_alloc); - - - /******************************************** - ** Platform-implemented support functions ** - ********************************************/ - - /* FIXME Could this be merged with Dataspace::unmap() and friends? */ + /* + * Helper class used to pass the dataspace attributes as + * parameters from the _prepare_io_mem function to the + * constructor of Dataspace_component. + */ + struct Dataspace_attr + { + size_t size { 0 }; + addr_t core_local_addr { 0 }; + addr_t phys_addr { 0 }; + Cache cacheable { UNCACHED }; /** - * Map region locally and return local base address - * - * Both parameters - base and size - must be page-aligned. + * Base address of request used for freeing mem-ranges */ - addr_t _map_local(addr_t base, size_t size); + addr_t req_base { 0 }; /** - * Unmap Core-local mapping of region + * Default constructor * - * Both parameters - base and size - must be page-aligned. + * This constructor enables Dataspace_attr objects to be + * returned from the '_prepare_io_mem' function. */ - void _unmap_local(addr_t base, size_t size); - - public: + Dataspace_attr() { } /** * Constructor * - * \param io_mem_alloc MMIO region allocator - * \param ram_alloc RAM allocator that will be checked for - * region collisions - * \param ds_ep entry point to manage the dataspace - * corresponding the io_mem session - * \param args session construction arguments, in - * particular MMIO region base, size and - * caching demands + * An invalid dataspace is represented by setting all + * arguments to zero. */ - Io_mem_session_component(Range_allocator &io_mem_alloc, - Range_allocator &ram_alloc, - Rpc_entrypoint &ds_ep, - const char *args); + Dataspace_attr(size_t s, addr_t cla, addr_t pa, Cache c, + addr_t req_base) + : + size(s), core_local_addr(cla), phys_addr(pa), + cacheable(c), req_base(req_base) { } + }; + + struct Io_dataspace_component : Dataspace_component + { + addr_t req_base; /** - * Destructor + * Constructor */ - ~Io_mem_session_component(); + Io_dataspace_component(Dataspace_attr da) + : + Dataspace_component(da.size, da.core_local_addr, + da.phys_addr, da.cacheable, + true, 0), + req_base(da.req_base) { } - /****************************** - ** Io-mem session interface ** - ******************************/ + bool valid() { return size() != 0; } + }; - Io_mem_dataspace_capability dataspace() override { return _ds_cap; } - }; -} + Range_allocator &_io_mem_alloc; + Io_dataspace_component _ds; + Rpc_entrypoint &_ds_ep; + Io_mem_dataspace_capability _ds_cap { }; + Cache _cacheable { UNCACHED }; + + Dataspace_attr _prepare_io_mem(const char *args, Range_allocator &ram_alloc); + + + /******************************************** + ** Platform-implemented support functions ** + ********************************************/ + + /* FIXME Could this be merged with Dataspace::unmap() and friends? */ + + /** + * Map region locally and return local base address + * + * Both parameters - base and size - must be page-aligned. + */ + addr_t _map_local(addr_t base, size_t size); + + /** + * Unmap Core-local mapping of region + * + * Both parameters - base and size - must be page-aligned. + */ + void _unmap_local(addr_t virt_base, size_t size, addr_t phys_base); + + public: + + /** + * Constructor + * + * \param io_mem_alloc MMIO region allocator + * \param ram_alloc RAM allocator that will be checked for + * region collisions + * \param ds_ep entry point to manage the dataspace + * corresponding the io_mem session + * \param args session construction arguments, in + * particular MMIO region base, size and + * caching demands + */ + Io_mem_session_component(Range_allocator &io_mem_alloc, + Range_allocator &ram_alloc, + Rpc_entrypoint &ds_ep, + const char *args); + + /** + * Destructor + */ + ~Io_mem_session_component(); + + + /****************************** + ** Io-mem session interface ** + ******************************/ + + Io_mem_dataspace_capability dataspace() override { return _ds_cap; } +}; #endif /* _CORE__INCLUDE__IO_MEM_SESSION_COMPONENT_H_ */ diff --git a/repos/base/src/core/include/io_port_root.h b/repos/base/src/core/include/io_port_root.h index b9ae0de144..76eae53aa3 100644 --- a/repos/base/src/core/include/io_port_root.h +++ b/repos/base/src/core/include/io_port_root.h @@ -16,56 +16,61 @@ #include -#include "io_port_session_component.h" +/* core includes */ +#include -namespace Genode { - - struct Io_port_handler - { - private: - - enum { STACK_SIZE = 4096 }; - Rpc_entrypoint _ep; - - public: - - Io_port_handler(Pd_session &pd_session) : - _ep(&pd_session, STACK_SIZE, "ioport", Affinity::Location()) - { } - - Rpc_entrypoint &entrypoint() { return _ep; } - }; - - class Io_port_root : private Io_port_handler, - public Root_component - { - - private: - - Range_allocator &_io_port_alloc; /* I/O port allocator */ - - protected: - - Io_port_session_component *_create_session(const char *args) override { - return new (md_alloc()) Io_port_session_component(_io_port_alloc, args); } - - public: - - /** - * Constructor - * - * \param cap_session capability allocator - * \param io_port_alloc platform IO_PORT allocator - * \param md_alloc meta-data allocator to be used by root component - */ - Io_port_root(Pd_session &pd_session, - Range_allocator &io_port_alloc, - Allocator &md_alloc) - : - Io_port_handler(pd_session), - Root_component(&entrypoint(), &md_alloc), - _io_port_alloc(io_port_alloc) { } - }; +namespace Core { + class Io_port_handler; + class Io_port_root; } + +class Core::Io_port_handler +{ + private: + + enum { STACK_SIZE = 4096 }; + Rpc_entrypoint _ep; + + public: + + Io_port_handler(Pd_session &pd_session) : + _ep(&pd_session, STACK_SIZE, "ioport", Affinity::Location()) + { } + + Rpc_entrypoint &entrypoint() { return _ep; } +}; + + +class Core::Io_port_root : private Io_port_handler, + public Root_component +{ + + private: + + Range_allocator &_io_port_alloc; /* I/O port allocator */ + + protected: + + Io_port_session_component *_create_session(const char *args) override { + return new (md_alloc()) Io_port_session_component(_io_port_alloc, args); } + + public: + + /** + * Constructor + * + * \param cap_session capability allocator + * \param io_port_alloc platform IO_PORT allocator + * \param md_alloc meta-data allocator to be used by root component + */ + Io_port_root(Pd_session &pd_session, + Range_allocator &io_port_alloc, + Allocator &md_alloc) + : + Io_port_handler(pd_session), + Root_component(&entrypoint(), &md_alloc), + _io_port_alloc(io_port_alloc) { } +}; + #endif /* _CORE__INCLUDE__IO_PORT_ROOT_H_ */ diff --git a/repos/base/src/core/include/io_port_session_component.h b/repos/base/src/core/include/io_port_session_component.h index f2679cb591..b87ccc17d3 100644 --- a/repos/base/src/core/include/io_port_session_component.h +++ b/repos/base/src/core/include/io_port_session_component.h @@ -3,7 +3,7 @@ * \author Christian Helmuth * \date 2007-04-17 * - * We assume Core is running on IOPL3. + * We assume core is running on IOPL3. */ /* @@ -24,53 +24,53 @@ /* core includes */ #include -namespace Genode { - - class Io_port_session_component : public Rpc_object - { - private: - - Range_allocator &_io_port_alloc; - unsigned short _base = 0; - unsigned short _size = 0; - - /** - * Check if access exceeds range - */ - bool _in_bounds(unsigned short address, unsigned width) { - return (address >= _base) && (address + width <= _base + _size); } - - public: - - /** - * Constructor - * - * \param io_port_alloc IO_PORT region allocator - * \param args session construction arguments, in - * particular port base and size - * \throw Service_denied - */ - Io_port_session_component(Range_allocator &io_port_alloc, - const char *args); - - /** - * Destructor - */ - ~Io_port_session_component(); +namespace Core { class Io_port_session_component; } - /******************************* - ** Io-port session interface ** - *******************************/ +class Core::Io_port_session_component : public Rpc_object +{ + private: - unsigned char inb(unsigned short) override; - unsigned short inw(unsigned short) override; - unsigned inl(unsigned short) override; + Range_allocator &_io_port_alloc; + unsigned short _base = 0; + unsigned short _size = 0; - void outb(unsigned short, unsigned char) override; - void outw(unsigned short, unsigned short) override; - void outl(unsigned short, unsigned) override; - }; -} + /** + * Check if access exceeds range + */ + bool _in_bounds(unsigned short address, unsigned width) { + return (address >= _base) && (address + width <= _base + _size); } + + public: + + /** + * Constructor + * + * \param io_port_alloc IO_PORT region allocator + * \param args session construction arguments, in + * particular port base and size + * \throw Service_denied + */ + Io_port_session_component(Range_allocator &io_port_alloc, + const char *args); + + /** + * Destructor + */ + ~Io_port_session_component(); + + + /******************************* + ** Io-port session interface ** + *******************************/ + + unsigned char inb(unsigned short) override; + unsigned short inw(unsigned short) override; + unsigned inl(unsigned short) override; + + void outb(unsigned short, unsigned char) override; + void outw(unsigned short, unsigned short) override; + void outl(unsigned short, unsigned) override; +}; #endif /* _CORE__INCLUDE__IO_PORT_SESSION_COMPONENT_H_ */ diff --git a/repos/base/src/core/include/irq_args.h b/repos/base/src/core/include/irq_args.h index 8f26cd46e5..4630097971 100644 --- a/repos/base/src/core/include/irq_args.h +++ b/repos/base/src/core/include/irq_args.h @@ -14,18 +14,22 @@ #ifndef _CORE__INCLUDE__IRQ_ARGS_H_ #define _CORE__INCLUDE__IRQ_ARGS_H_ -#include #include #include -namespace Genode { class Irq_args; } +/* core includes */ +#include -class Genode::Irq_args +namespace Core { class Irq_args; } + + +class Core::Irq_args { private: Irq_session::Trigger _irq_trigger { Irq_session::TRIGGER_UNCHANGED }; Irq_session::Polarity _irq_polarity { Irq_session::POLARITY_UNCHANGED }; + Irq_session::Type _irq_type { Irq_session::TYPE_LEGACY }; long const _irq_number; @@ -35,8 +39,9 @@ class Genode::Irq_args : _irq_number(Arg_string::find_arg(args, "irq_number").long_value(-1)) { - long irq_trg = Arg_string::find_arg(args, "irq_trigger").long_value(-1); - long irq_pol = Arg_string::find_arg(args, "irq_polarity").long_value(-1); + long irq_trg = Arg_string::find_arg(args, "irq_trigger").long_value(-1); + long irq_pol = Arg_string::find_arg(args, "irq_polarity").long_value(-1); + long irq_type = Arg_string::find_arg(args, "irq_type").long_value(-1); switch (irq_trg) { case -1: @@ -71,11 +76,29 @@ class Genode::Irq_args _irq_number); throw Service_denied(); } + + switch (irq_type) { + case -1: + case Irq_session::TYPE_LEGACY: + _irq_type = Irq_session::TYPE_LEGACY; + break; + case Irq_session::TYPE_MSI: + _irq_type = Irq_session::TYPE_MSI; + break; + case Irq_session::TYPE_MSIX: + _irq_type = Irq_session::TYPE_MSIX; + break; + default: + error("invalid type ", irq_type, " specified for IRQ ", + _irq_number); + throw Service_denied(); + } } long irq_number() const { return _irq_number; } Irq_session::Trigger trigger() const { return _irq_trigger; } Irq_session::Polarity polarity() const { return _irq_polarity; } + Irq_session::Type type() const { return _irq_type; } }; #endif /* _CORE__INCLUDE__IRQ_ARGS_H_ */ diff --git a/repos/base/src/core/include/irq_object.h b/repos/base/src/core/include/irq_object.h index 998e03c267..87a5147f63 100644 --- a/repos/base/src/core/include/irq_object.h +++ b/repos/base/src/core/include/irq_object.h @@ -16,10 +16,14 @@ #include -namespace Genode { class Irq_object; } +/* core includes */ +#include -class Genode::Irq_object : public Thread { +namespace Core { class Irq_object; } + +class Core::Irq_object : public Thread +{ private: Signal_context_capability _sig_cap { }; @@ -39,7 +43,7 @@ class Genode::Irq_object : public Thread { void sigh(Signal_context_capability cap) { _sig_cap = cap; } void ack_irq() { _sync_ack.wakeup(); } - void start() override; + Start_result start() override; }; #endif /* _CORE__INCLUDE__IRQ_OBJECT_H_ */ diff --git a/repos/base/src/core/include/irq_root.h b/repos/base/src/core/include/irq_root.h index 9a8815122b..6db7b8510c 100644 --- a/repos/base/src/core/include/irq_root.h +++ b/repos/base/src/core/include/irq_root.h @@ -16,11 +16,14 @@ #define _CORE__INCLUDE__IRQ_ROOT_H_ #include + +/* core includes */ #include -namespace Genode { class Irq_root; } +namespace Core { class Irq_root; } -class Genode::Irq_root : public Root_component + +class Core::Irq_root : public Root_component { private: diff --git a/repos/base/src/core/include/irq_session_component.h b/repos/base/src/core/include/irq_session_component.h index 085825f03c..4c049268e7 100644 --- a/repos/base/src/core/include/irq_session_component.h +++ b/repos/base/src/core/include/irq_session_component.h @@ -20,12 +20,14 @@ #include #include +/* core includes */ #include -namespace Genode { class Irq_session_component; } +namespace Core { class Irq_session_component; } -class Genode::Irq_session_component : public Rpc_object, - private List::Element + +class Core::Irq_session_component : public Rpc_object, + private List::Element { private: diff --git a/repos/base/src/core/include/log2_range.h b/repos/base/src/core/include/log2_range.h new file mode 100644 index 0000000000..cb77ba9442 --- /dev/null +++ b/repos/base/src/core/include/log2_range.h @@ -0,0 +1,136 @@ +/* + * \brief Utility for dealing with log2 alignment constraints + * \author Norman Feske + * \date 2023-06-11 + */ + +/* + * Copyright (C) 2023 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CORE__INCLUDE__LOG2_RANGE_H_ +#define _CORE__INCLUDE__LOG2_RANGE_H_ + +/* core includes */ +#include +#include + +namespace Core { struct Log2_range; } + + +struct Core::Log2_range +{ + Addr hotspot { 0 }; + Addr base { 0 }; + Log2 size { 0 }; + + bool valid() const { return size.log2 >= get_page_size_log2(); } + + static constexpr Log2 UNCONSTRAINED = { uint8_t(~0) }; + + /** + * Default constructor, constructs invalid range + */ + Log2_range() { } + + /** + * Constructor, hotspot area spans the maximum address-space size + */ + Log2_range(Addr hotspot) : hotspot(hotspot), size(UNCONSTRAINED) { } + + /** + * Constrain range to specified region + */ + Log2_range constrained(Addr_range region) const + { + addr_t const upper_bound = (size.log2 == UNCONSTRAINED.log2) + ? ~0UL : (base.value + (1UL << size.log2) - 1); + + /* + * Find flexpage around hotspot that lies within the specified region. + * + * Start with a 'size' of one less than the minimal page size. + * If the specified constraint conflicts with the existing range, + * the loop breaks at the first iteration and we can check for this + * condition after the loop. + */ + Log2_range result { hotspot }; + result.size = { get_page_size_log2() - 1 }; + + for (uint8_t try_size_log2 = get_page_size_log2(); + try_size_log2 < sizeof(addr_t)*8 ; try_size_log2++) { + + addr_t const fpage_mask = ~((1UL << try_size_log2) - 1); + addr_t const try_base = hotspot.value & fpage_mask; + + /* check lower bound of existing range */ + if (try_base < base.value) + break; + + /* check against upper bound of existing range */ + if (try_base + (1UL << try_size_log2) - 1 > upper_bound) + break; + + /* check against lower bound of region */ + if (try_base < region.start) + break; + + /* check against upper bound of region */ + if (try_base + (1UL << try_size_log2) - 1 > region.end) + break; + + /* flexpage is compatible with the range, use it */ + result.size = { try_size_log2 }; + result.base = { try_base }; + } + + return result.valid() ? result : Log2_range { }; + } + + /** + * Constrain range around hotspot to specified log2 size + */ + Log2_range constrained(Log2 value) const + { + Log2_range result = *this; + + if (value.log2 >= size.log2) + return result; + + result.base = { hotspot.value & ~((1UL << value.log2) - 1) }; + result.size = value; + return result; + } + + /** + * Determine common log2 size compatible with both ranges + */ + static Log2 common_log2(Log2_range const &r1, Log2_range const &r2) + { + /* + * We have to make sure that the offset of hotspot + * relative to the flexpage base is the same for both ranges. + * This condition is met by the flexpage size equal to the number + * of common least-significant bits of both offsets. + */ + size_t const diff = (r1.hotspot.value - r1.base.value) + ^ (r2.hotspot.value - r2.base.value); + + /* + * Find highest clear bit in 'diff', starting from the least + * significant candidate. We can skip all bits lower then + * 'get_page_size_log2()' because they are not relevant as + * flexpage size (and are always zero). + */ + uint8_t n = get_page_size_log2(); + size_t const min_size_log2 = min(r1.size.log2, r2.size.log2); + for (; n < min_size_log2 && !(diff & (1UL << n)); n++); + + return Log2 { n }; + } +}; + +#endif /* _CORE__INCLUDE__LOG2_RANGE_H_ */ diff --git a/repos/base/src/core/include/log_root.h b/repos/base/src/core/include/log_root.h index 085c6053f9..9731f9df19 100644 --- a/repos/base/src/core/include/log_root.h +++ b/repos/base/src/core/include/log_root.h @@ -17,35 +17,36 @@ #include #include -#include "log_session_component.h" +/* core includes */ +#include -namespace Genode { +namespace Core { class Log_root; } - class Log_root : public Root_component - { - protected: - /** - * Root component interface - */ - Log_session_component *_create_session(const char *args) override - { - return new (md_alloc()) Log_session_component(label_from_args(args)); - } +class Core::Log_root : public Root_component +{ + protected: - public: + /** + * Root component interface + */ + Log_session_component *_create_session(const char *args) override + { + return new (md_alloc()) Log_session_component(label_from_args(args)); + } - /** - * Constructor - * - * \param session_ep entry point for managing cpu session objects - * \param md_alloc meta-data allocator to be used by root component - */ - Log_root(Rpc_entrypoint &session_ep, Allocator &md_alloc) - : - Root_component(&session_ep, &md_alloc) - { } - }; -} + public: + + /** + * Constructor + * + * \param session_ep entry point for managing cpu session objects + * \param md_alloc meta-data allocator to be used by root component + */ + Log_root(Rpc_entrypoint &session_ep, Allocator &md_alloc) + : + Root_component(&session_ep, &md_alloc) + { } +}; #endif /* _CORE__INCLUDE__LOG_ROOT_H_ */ diff --git a/repos/base/src/core/include/log_session_component.h b/repos/base/src/core/include/log_session_component.h index 2271d37ab2..d0ad7ba09d 100644 --- a/repos/base/src/core/include/log_session_component.h +++ b/repos/base/src/core/include/log_session_component.h @@ -14,64 +14,57 @@ #ifndef _CORE__INCLUDE__LOG_SESSION_COMPONENT_H_ #define _CORE__INCLUDE__LOG_SESSION_COMPONENT_H_ -#include -#include #include #include #include -namespace Genode { +/* core includes */ +#include - class Log_session_component : public Rpc_object - { - private: +namespace Core { class Log_session_component; } - Session_label const _label; - static Session_label _expand_label(Session_label const &label) - { - if (label == "init -> unlabeled") - return ""; - else - return Session_label("[", label, "] "); +class Core::Log_session_component : public Rpc_object +{ + private: + + Session_label const _label; + + public: + + /** + * Constructor + */ + Log_session_component(Session_label const &label) + : _label("[", label, "] ") { } + + + /***************** + ** Log session ** + *****************/ + + void write(String const &string_buf) override + { + if (!(string_buf.valid_string())) { + error("corrupted string"); + return; } - public: + char const * const string = string_buf.string(); + size_t const len = Genode::strlen(string); - /** - * Constructor - */ - Log_session_component(Session_label const &label) - : _label(_expand_label(label)) { } - - - /***************** - ** Log session ** - *****************/ - - void write(String const &string_buf) override - { - if (!(string_buf.valid_string())) { - error("corrupted string"); - return; + unsigned from_i = 0; + for (unsigned i = 0; i < len; i++) { + if (string[i] == '\n') { + log(_label, Cstring(string + from_i, i - from_i)); + from_i = i + 1; } - - char const * const string = string_buf.string(); - size_t const len = strlen(string); - - unsigned from_i = 0; - for (unsigned i = 0; i < len; i++) { - if (string[i] == '\n') { - log(_label, Cstring(string + from_i, i - from_i)); - from_i = i + 1; - } - } - - /* if last character of string was not a line break, add one */ - if (from_i < len) - log(_label, Cstring(string + from_i)); } - }; -} + + /* if last character of string was not a line break, add one */ + if (from_i < len) + log(_label, Cstring(string + from_i)); + } +}; #endif /* _CORE__INCLUDE__LOG_SESSION_COMPONENT_H_ */ diff --git a/repos/base/src/core/include/mapping.h b/repos/base/src/core/include/mapping.h index 2de2dae558..7a7f8590f2 100644 --- a/repos/base/src/core/include/mapping.h +++ b/repos/base/src/core/include/mapping.h @@ -14,12 +14,13 @@ #ifndef _CORE__INCLUDE__MAPPING_H_ #define _CORE__INCLUDE__MAPPING_H_ -#include +/* core includes */ +#include -namespace Genode { struct Mapping; } +namespace Core { struct Mapping; } -struct Genode::Mapping +struct Core::Mapping { addr_t dst_addr; addr_t src_addr; diff --git a/repos/base/src/core/include/native_cpu_component.h b/repos/base/src/core/include/native_cpu_component.h index b90cc39663..9df72b4eef 100644 --- a/repos/base/src/core/include/native_cpu_component.h +++ b/repos/base/src/core/include/native_cpu_component.h @@ -19,17 +19,17 @@ /* Genode includes */ #include -/* core-local includes */ +/* core includes */ #include -namespace Genode { +namespace Core { class Cpu_session_component; class Native_cpu_component; } -struct Genode::Native_cpu_component +struct Core::Native_cpu_component { Native_cpu_component(Cpu_session_component &, char const *) { } diff --git a/repos/base/src/core/include/native_pd_component.h b/repos/base/src/core/include/native_pd_component.h index 6a1d1ec2e5..9e8a6ba858 100644 --- a/repos/base/src/core/include/native_pd_component.h +++ b/repos/base/src/core/include/native_pd_component.h @@ -19,17 +19,17 @@ /* Genode includes */ #include -/* core-local includes */ +/* core includes */ #include -namespace Genode { +namespace Core { class Pd_session_component; class Native_pd_component; } -struct Genode::Native_pd_component +struct Core::Native_pd_component { Native_pd_component(Pd_session_component &, char const *) { } diff --git a/repos/base/src/core/include/pager.h b/repos/base/src/core/include/pager.h index 259c2cea14..925c099d38 100644 --- a/repos/base/src/core/include/pager.h +++ b/repos/base/src/core/include/pager.h @@ -24,13 +24,11 @@ #include #include -/* core-local includes */ +/* core includes */ #include #include -namespace Genode { - - typedef Cpu_session::Thread_creation_failed Invalid_thread; +namespace Core { /** * Special server object for paging @@ -46,11 +44,13 @@ namespace Genode { */ class Pager_entrypoint; + using Pager_capability = Capability; + enum { PAGER_EP_STACK_SIZE = sizeof(addr_t) * 2048 }; } -class Genode::Pager_object : public Object_pool::Entry +class Core::Pager_object : public Object_pool::Entry { protected: @@ -82,8 +82,6 @@ class Genode::Pager_object : public Object_pool::Entry * Constructor * * \param location affinity of paged thread to physical CPU - * - * \throw Invalid_thread */ Pager_object(Cpu_session_capability cpu_sesion, Thread_capability thread, @@ -99,6 +97,8 @@ class Genode::Pager_object : public Object_pool::Entry unsigned long badge() const { return _badge; } + enum class Pager_result { STOP, CONTINUE }; + /** * Interface to be implemented by a derived class * @@ -106,7 +106,7 @@ class Genode::Pager_object : public Object_pool::Entry * * Returns !0 on error and pagefault will not be answered. */ - virtual int pager(Ipc_pager &ps) = 0; + virtual Pager_result pager(Ipc_pager &ps) = 0; /** * Wake up the faulter @@ -162,8 +162,8 @@ class Genode::Pager_object : public Object_pool::Entry }; -class Genode::Pager_entrypoint : public Object_pool, - public Thread +class Core::Pager_entrypoint : public Object_pool, + public Thread { private: diff --git a/repos/base/src/core/include/pager_object_exception_state.h b/repos/base/src/core/include/pager_object_exception_state.h index 50ef55a7f7..b817059658 100644 --- a/repos/base/src/core/include/pager_object_exception_state.h +++ b/repos/base/src/core/include/pager_object_exception_state.h @@ -16,6 +16,9 @@ #include -namespace Genode { typedef Thread_state Pager_object_exception_state; } +/* core includes */ +#include + +namespace Core { using Pager_object_exception_state = Thread_state; } #endif /* _CORE__INCLUDE__PAGER_OBJECT_EXCEPTION_STATE_H_ */ diff --git a/repos/base/src/core/include/pd_root.h b/repos/base/src/core/include/pd_root.h index 5e92307a05..547c4035ff 100644 --- a/repos/base/src/core/include/pd_root.h +++ b/repos/base/src/core/include/pd_root.h @@ -20,12 +20,10 @@ /* Core */ #include -namespace Genode { - class Pd_root; -} +namespace Core { class Pd_root; } -class Genode::Pd_root : public Genode::Root_component +class Core::Pd_root : public Root_component { private: @@ -35,6 +33,7 @@ class Genode::Pd_root : public Genode::Root_component(&ep, &md_alloc), _ep(ep), _signal_ep(signal_ep), _pager_ep(pager_ep), - _phys_alloc(phys_alloc), _local_rm(local_rm), _core_mem(core_mem) + _phys_alloc(phys_alloc), _local_rm(local_rm), _core_mem(core_mem), + _system_control(system_control) { } }; diff --git a/repos/base/src/core/include/pd_session_component.h b/repos/base/src/core/include/pd_session_component.h index 1b84ba015a..a897de79e0 100644 --- a/repos/base/src/core/include/pd_session_component.h +++ b/repos/base/src/core/include/pd_session_component.h @@ -17,7 +17,6 @@ #define _CORE__INCLUDE__PD_SESSION_COMPONENT_H_ /* Genode includes */ -#include #include #include #include @@ -31,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -38,21 +38,27 @@ #include #include -namespace Genode { class Pd_session_component; } +namespace Core { + class Pd_session_component; + class Cpu_thread_component; +} -class Genode::Pd_session_component : public Session_object +class Core::Pd_session_component : public Session_object { public: enum class Managing_system { DENIED, PERMITTED }; + using Threads = Registry; + private: Constructible > _cap_account { }; Constructible > _ram_account { }; Rpc_entrypoint &_ep; + Core::System_control &_system_control; Constrained_ram_allocator _constrained_md_ram_alloc; Constrained_core_ram _constrained_core_ram_alloc; Sliced_heap _sliced_heap; @@ -70,6 +76,8 @@ class Genode::Pd_session_component : public Session_object Managing_system _managing_system; + Threads _threads { }; + friend class Native_pd_component; @@ -114,8 +122,8 @@ class Genode::Pd_session_component : public Session_object public: - typedef Ram_dataspace_factory::Phys_range Phys_range; - typedef Ram_dataspace_factory::Virt_range Virt_range; + using Phys_range = Ram_dataspace_factory::Phys_range; + using Virt_range = Ram_dataspace_factory::Virt_range; /** * Constructor @@ -132,10 +140,12 @@ class Genode::Pd_session_component : public Session_object Region_map &local_rm, Pager_entrypoint &pager_ep, char const *args, - Range_allocator &core_mem) + Range_allocator &core_mem, + Core::System_control &system_control) : Session_object(ep, resources, label, diag), _ep(ep), + _system_control(system_control), _constrained_md_ram_alloc(*this, _ram_quota_guard(), _cap_quota_guard()), _constrained_core_ram_alloc(_ram_quota_guard(), _cap_quota_guard(), core_mem), _sliced_heap(_constrained_md_ram_alloc, local_rm), @@ -156,6 +166,8 @@ class Genode::Pd_session_component : public Session_object } } + ~Pd_session_component(); + /** * Initialize cap and RAM accounts without providing a reference account * @@ -168,20 +180,16 @@ class Genode::Pd_session_component : public Session_object _ram_account.construct(_ram_quota_guard(), _label); } - /** - * Associate thread with PD - * - * \return true on success - * - * This function may fail for platform-specific reasons such as a - * limit on the number of threads per protection domain or a limited - * thread ID namespace. - */ - bool bind_thread(Platform_thread &thread) + void with_platform_pd(auto const &fn) { - return _pd->bind_thread(thread); + if (_pd.constructed()) + fn(*_pd); + else + error("unexpected call for 'with_platform_pd'"); } + void with_threads(auto const &fn) { fn(_threads); } + Region_map_component &address_space_region_map() { return _address_space; @@ -195,24 +203,30 @@ class Genode::Pd_session_component : public Session_object bool assign_pci(addr_t, uint16_t) override; - void map(addr_t, addr_t) override; + Map_result map(Pd_session::Virt_range) override; /**************** ** Signalling ** ****************/ - Signal_source_capability alloc_signal_source() override + Signal_source_result signal_source() override { - _consume_cap(SIG_SOURCE_CAP); + try { _consume_cap(SIG_SOURCE_CAP); } + catch (Out_of_caps) { + return Signal_source_error::OUT_OF_CAPS; } + + Signal_source_result result = Capability(); + try { return _signal_broker.alloc_signal_source(); } - catch (Genode::Allocator::Out_of_memory) { - _released_cap_silent(); - throw Out_of_ram(); - } + catch (Out_of_ram) { result = Signal_source_error::OUT_OF_RAM; } + catch (Out_of_caps) { result = Signal_source_error::OUT_OF_CAPS; } + + _released_cap_silent(); + return result; } - void free_signal_source(Signal_source_capability sig_rec_cap) override + void free_signal_source(Capability sig_rec_cap) override { if (sig_rec_cap.valid()) { _signal_broker.free_signal_source(sig_rec_cap); @@ -220,21 +234,24 @@ class Genode::Pd_session_component : public Session_object } } - Signal_context_capability - alloc_context(Signal_source_capability sig_rec_cap, unsigned long imprint) override + Alloc_context_result + alloc_context(Capability sig_rec_cap, Imprint imprint) override { - Cap_quota_guard::Reservation cap_costs(_cap_quota_guard(), Cap_quota{1}); try { - /* may throw 'Out_of_ram' or 'Invalid_signal_source' */ + Cap_quota_guard::Reservation cap_costs(_cap_quota_guard(), Cap_quota{1}); + + /* may throw 'Out_of_ram', 'Out_of_caps', or 'Invalid_signal_source' */ Signal_context_capability cap = - _signal_broker.alloc_context(sig_rec_cap, imprint); + _signal_broker.alloc_context(sig_rec_cap, imprint.value); cap_costs.acknowledge(); diag("consumed signal-context cap (", _cap_account, ")"); return cap; } catch (Signal_broker::Invalid_signal_source) { - throw Pd_session::Invalid_signal_source(); } + return Alloc_context_error::INVALID_SIGNAL_SOURCE; } + catch (Out_of_ram) { return Alloc_context_error::OUT_OF_RAM; } + catch (Out_of_caps) { return Alloc_context_error::OUT_OF_CAPS; } } void free_context(Signal_context_capability cap) override @@ -251,14 +268,19 @@ class Genode::Pd_session_component : public Session_object ** RPC capability allocation ** *******************************/ - Native_capability alloc_rpc_cap(Native_capability ep) override + Alloc_rpc_cap_result alloc_rpc_cap(Native_capability ep) override { /* may throw 'Out_of_caps' */ - _consume_cap(RPC_CAP); + try { _consume_cap(RPC_CAP); } + catch (Out_of_caps) { + return Alloc_rpc_cap_error::OUT_OF_CAPS; } /* may throw 'Out_of_ram' */ - try { return _rpc_cap_factory.alloc(ep); } - catch (...) { _released_cap_silent(); throw; } + try { + return _rpc_cap_factory.alloc(ep); } + catch (...) { + _released_cap_silent(); + return Alloc_rpc_cap_error::OUT_OF_RAM; } } void free_rpc_cap(Native_capability cap) override @@ -286,10 +308,10 @@ class Genode::Pd_session_component : public Session_object ** Capability and RAM trading and accounting ** ***********************************************/ - void ref_account(Capability) override; + Ref_account_result ref_account(Capability) override; - void transfer_quota(Capability, Cap_quota) override; - void transfer_quota(Capability, Ram_quota) override; + Transfer_cap_quota_result transfer_quota(Capability, Cap_quota) override; + Transfer_ram_quota_result transfer_quota(Capability, Ram_quota) override; Cap_quota cap_quota() const override { @@ -330,11 +352,17 @@ class Genode::Pd_session_component : public Session_object Capability native_pd() override { return _native_pd.cap(); } - /******************************* - ** Managing system interface ** - *******************************/ + /****************************** + ** System control interface ** + ******************************/ - Managing_system_state managing_system(Managing_system_state const &) override; + Capability system_control_cap(Affinity::Location const location) override + { + if (_managing_system == Managing_system::PERMITTED) + return _system_control.control_cap(location); + + return { }; + } /******************************************* diff --git a/repos/base/src/core/include/platform_generic.h b/repos/base/src/core/include/platform_generic.h index c394c83a77..da3bbfe6c1 100644 --- a/repos/base/src/core/include/platform_generic.h +++ b/repos/base/src/core/include/platform_generic.h @@ -22,89 +22,9 @@ /* core includes */ #include -namespace Genode { - - /** - * Generic platform interface - */ - class Platform_generic - { - public: - - virtual ~Platform_generic() { } - - /** - * Allocator of core-local mapped virtual memory - */ - virtual Range_allocator &core_mem_alloc() = 0; - - /** - * Allocator of physical memory - */ - virtual Range_allocator &ram_alloc() = 0; - - /** - * Allocator of free address ranges within core - */ - virtual Range_allocator ®ion_alloc() = 0; - - /** - * I/O memory allocator - */ - virtual Range_allocator &io_mem_alloc() = 0; - - /** - * I/O port allocator - */ - virtual Range_allocator &io_port_alloc() = 0; - - /** - * IRQ allocator - */ - virtual Range_allocator &irq_alloc() = 0; - - /** - * Virtual memory configuration accessors - */ - virtual addr_t vm_start() const = 0; - virtual size_t vm_size() const = 0; - - /** - * ROM modules - */ - virtual Rom_fs &rom_fs() = 0; - - /** - * Wait for exit condition - */ - virtual void wait_for_exit() = 0; - - /** - * Return true if platform supports direct unmap (no mapping db) - */ - virtual bool supports_direct_unmap() const { return false; } - - /** - * Return number of physical CPUs present in the platform - * - * The default implementation returns a single CPU. - */ - virtual Affinity::Space affinity_space() const - { - return Affinity::Space(1); - } - - /** - * Return system-wide maximum number of capabilities - */ - virtual size_t max_caps() const = 0; - - /** - * Return true if the core component relies on a 'Platform_pd' object - */ - virtual bool core_needs_platform_pd() const { return true; } - }; +namespace Core { + class Platform_generic; /** * Request pointer to static generic platform interface of core @@ -121,4 +41,84 @@ namespace Genode { extern Platform &platform_specific(); } + +class Core::Platform_generic +{ + public: + + virtual ~Platform_generic() { } + + /** + * Allocator of core-local mapped virtual memory + */ + virtual Range_allocator &core_mem_alloc() = 0; + + /** + * Allocator of physical memory + */ + virtual Range_allocator &ram_alloc() = 0; + + /** + * Allocator of free address ranges within core + */ + virtual Range_allocator ®ion_alloc() = 0; + + /** + * I/O memory allocator + */ + virtual Range_allocator &io_mem_alloc() = 0; + + /** + * I/O port allocator + */ + virtual Range_allocator &io_port_alloc() = 0; + + /** + * IRQ allocator + */ + virtual Range_allocator &irq_alloc() = 0; + + /** + * Virtual memory configuration accessors + */ + virtual addr_t vm_start() const = 0; + virtual size_t vm_size() const = 0; + + /** + * ROM modules + */ + virtual Rom_fs &rom_fs() = 0; + + /** + * Wait for exit condition + */ + virtual void wait_for_exit() = 0; + + /** + * Return true if platform supports direct unmap (no mapping db) + */ + virtual bool supports_direct_unmap() const { return false; } + + /** + * Return number of physical CPUs present in the platform + * + * The default implementation returns a single CPU. + */ + virtual Affinity::Space affinity_space() const + { + return Affinity::Space(1); + } + + /** + * Return system-wide maximum number of capabilities + */ + virtual size_t max_caps() const = 0; + + /** + * Return true if the core component relies on a 'Platform_pd' object + */ + virtual bool core_needs_platform_pd() const { return true; } +}; + + #endif /* _CORE__INCLUDE__PLATFORM_GENERIC_H_ */ diff --git a/repos/base/src/core/include/platform_services.h b/repos/base/src/core/include/platform_services.h index 4cb70bed37..5193f7f892 100644 --- a/repos/base/src/core/include/platform_services.h +++ b/repos/base/src/core/include/platform_services.h @@ -14,15 +14,18 @@ #ifndef _CORE__INCLUDE__PLATFORM_SERVICES_H_ #define _CORE__INCLUDE__PLATFORM_SERVICES_H_ +/* core includes */ #include #include namespace Genode { - class Rpc_entrypoint; class Sliced_heap; +} +namespace Core { + /** * Register platform-specific services at entrypoint, and service * registry diff --git a/repos/base/src/core/include/ram_dataspace_factory.h b/repos/base/src/core/include/ram_dataspace_factory.h index 747372b01b..c00a2858fb 100644 --- a/repos/base/src/core/include/ram_dataspace_factory.h +++ b/repos/base/src/core/include/ram_dataspace_factory.h @@ -24,15 +24,15 @@ /* core includes */ #include -namespace Genode { class Ram_dataspace_factory; } +namespace Core { class Ram_dataspace_factory; } -class Genode::Ram_dataspace_factory : public Ram_allocator, - public Dataspace_owner +class Core::Ram_dataspace_factory : public Ram_allocator, + public Dataspace_owner { public: - typedef Range_allocator::Range Phys_range; + using Phys_range = Range_allocator::Range; static Phys_range any_phys_range() { return { 0UL, ~0UL }; } diff --git a/repos/base/src/core/include/region_map_component.h b/repos/base/src/core/include/region_map_component.h index 203aae0fd6..d92e786a1d 100644 --- a/repos/base/src/core/include/region_map_component.h +++ b/repos/base/src/core/include/region_map_component.h @@ -16,7 +16,6 @@ #define _CORE__INCLUDE__REGION_MAP_COMPONENT_H_ /* Genode includes */ -#include #include #include #include @@ -34,32 +33,41 @@ #include #include #include +#include #include /* base-internal includes */ #include -namespace Genode { - - class Cpu_thread_component; - class Dataspace_component; - class Region_map_component; - class Region_map_detach; - class Rm_client; - class Rm_region; - class Rm_faulter; - class Rm_session_component; +namespace Core { + struct Region_map_detach; + class Rm_region; + struct Fault; + class Cpu_thread_component; + class Dataspace_component; + class Region_map_component; + class Rm_client; + class Rm_faulter; + class Rm_session_component; } -class Genode::Region_map_detach : Genode::Interface + +struct Core::Region_map_detach : Interface { - public: + virtual void detach_at(addr_t) = 0; - virtual void detach(Region_map::Local_addr) = 0; - virtual void unmap_region(addr_t base, size_t size) = 0; + /** + * Unmap memory area from all address spaces referencing it + * + * \param base base address of region to unmap + * \param size size of region to unmap in bytes + */ + virtual void unmap_region(addr_t base, size_t size) = 0; + virtual void reserve_and_flush(addr_t) = 0; }; + /** * Representation of a single entry of a region map * @@ -69,7 +77,7 @@ class Genode::Region_map_detach : Genode::Interface * organized in a linked list. The head of the list is a member of the * 'Dataspace_component'. */ -class Genode::Rm_region : public List::Element +class Core::Rm_region : public List::Element { public: @@ -79,13 +87,20 @@ class Genode::Rm_region : public List::Element size_t size; bool write; bool exec; - off_t off; + addr_t off; bool dma; + + void print(Output &out) const + { + Genode::print(out, "[", Hex(base), ",", Hex(base + size - 1), " " + "(r", write ? "w" : "-", exec ? "x" : "-", ") " + "offset: ", Hex(off), dma ? " DMA" : ""); + } }; private: - Dataspace_component &_dsc; + Dataspace_component *_dsc; Region_map_detach &_rm; Attr const _attr; @@ -94,17 +109,94 @@ class Genode::Rm_region : public List::Element Rm_region(Dataspace_component &dsc, Region_map_detach &rm, Attr attr) : - _dsc(dsc), _rm(rm), _attr(attr) + _dsc(&dsc), _rm(rm), _attr(attr) { } - addr_t base() const { return _attr.base; } - size_t size() const { return _attr.size; } - bool write() const { return _attr.write; } - bool executable() const { return _attr.exec; } - off_t offset() const { return _attr.off; } - bool dma() const { return _attr.dma; } - Dataspace_component &dataspace() const { return _dsc; } - Region_map_detach &rm() const { return _rm; } + addr_t base() const { return _attr.base; } + size_t size() const { return _attr.size; } + bool write() const { return _attr.write; } + bool executable() const { return _attr.exec; } + addr_t offset() const { return _attr.off; } + bool dma() const { return _attr.dma; } + Region_map_detach &rm() const { return _rm; } + + void mark_as_reserved() { _dsc = nullptr; } + bool reserved() const { return !_dsc; } + + Addr_range range() const { return { .start = _attr.base, + .end = _attr.base + _attr.size - 1 }; } + + void with_dataspace(auto const &fn) const + { + if (!_dsc) { + Genode::error(__func__, ": invalid dataspace"); + return; + } + + fn(*_dsc); + } + + void print(Output &out) const { Genode::print(out, _attr); } +}; + + +struct Core::Fault +{ + Addr hotspot; /* page-fault address */ + Access access; /* reason for the fault, used to detect violations */ + Rwx rwx; /* mapping rights, downgraded by 'within_' methods */ + Addr_range bounds; /* limits of the fault's coordinate system */ + + bool write_access() const { return access == Access::WRITE; } + bool exec_access() const { return access == Access::EXEC; } + + /** + * Translate fault information to region-relative coordinates + */ + Fault within_region(Rm_region const ®ion) const + { + return Fault { + .hotspot = hotspot.reduced_by(region.base()), + .access = access, + .rwx = { .w = rwx.w && region.write(), + .x = rwx.x && region.executable() }, + .bounds = bounds.intersected(region.range()) + .reduced_by(region.base()) + }; + } + + /** + * Translate fault information to coordinates within a sub region map + */ + Fault within_sub_region_map(addr_t offset, size_t region_map_size) const + { + return { + .hotspot = hotspot.increased_by(offset), + .access = access, + .rwx = rwx, + .bounds = bounds.intersected({ 0, region_map_size }) + .increased_by(offset) + }; + }; + + /** + * Translate fault information to physical coordinates for memory mapping + */ + Fault within_ram(addr_t offset, Dataspace_component::Attr dataspace) const + { + return { + .hotspot = hotspot.increased_by(offset) + .increased_by(dataspace.base), + .access = access, + .rwx = { .w = rwx.w && dataspace.writeable, + .x = rwx.x }, + .bounds = bounds.increased_by(offset) + .intersected({ 0, dataspace.size }) + .increased_by(dataspace.base) + }; + }; + + void print(Output &out) const { Genode::print(out, access, " at address ", hotspot); } }; @@ -120,14 +212,14 @@ class Genode::Rm_region : public List::Element * be able to handle faults by arbitrary clients (not only its own * clients), it maintains the list head of faulters. */ -class Genode::Rm_faulter : Fifo::Element, Interface +class Core::Rm_faulter : Fifo::Element, Interface { private: Pager_object &_pager_object; Mutex _mutex { }; Weak_ptr _faulting_region_map { }; - Region_map::State _fault_state { }; + Region_map::Fault _fault { }; friend class Fifo; @@ -145,8 +237,7 @@ class Genode::Rm_faulter : Fifo::Element, Interface /** * Assign fault state */ - void fault(Region_map_component &faulting_region_map, - Region_map::State fault_state); + void fault(Region_map_component &faulting_region_map, Region_map::Fault); /** * Disassociate faulter from the faulted region map @@ -160,12 +251,12 @@ class Genode::Rm_faulter : Fifo::Element, Interface * Return true if page fault occurred in specified address range */ bool fault_in_addr_range(addr_t addr, size_t size) { - return (_fault_state.addr >= addr) && (_fault_state.addr <= addr + size - 1); } + return (_fault.addr >= addr) && (_fault.addr <= addr + size - 1); } /** * Return fault state as exported via the region-map interface */ - Region_map::State fault_state() { return _fault_state; } + Region_map::Fault fault() { return _fault; } /** * Wake up faulter by answering the pending page fault @@ -180,8 +271,8 @@ class Genode::Rm_faulter : Fifo::Element, Interface * A region map can be used as address space for any number of threads. This * class represents the thread's role as member of this address space. */ -class Genode::Rm_client : public Pager_object, public Rm_faulter, - private List::Element +class Core::Rm_client : public Pager_object, public Rm_faulter, + private List::Element { private: @@ -210,7 +301,7 @@ class Genode::Rm_client : public Pager_object, public Rm_faulter, Rm_faulter(static_cast(*this)), _region_map(rm) { } - int pager(Ipc_pager &pager) override; + Pager_result pager(Ipc_pager &pager) override; /** * Return region map that the RM client is member of @@ -219,11 +310,16 @@ class Genode::Rm_client : public Pager_object, public Rm_faulter, }; -class Genode::Region_map_component : private Weak_object, - public Rpc_object, - private List::Element, - public Region_map_detach +class Core::Region_map_component : private Weak_object, + public Rpc_object, + private List::Element, + public Region_map_detach { + public: + + enum class With_mapping_result { RESOLVED, RECURSION_LIMIT, NO_REGION, + REFLECTED, WRITE_VIOLATION, EXEC_VIOLATION }; + private: friend class List; @@ -236,8 +332,7 @@ class Genode::Region_map_component : private Weak_object, Allocator &_md_alloc; - Signal_transmitter _fault_notifier { }; /* notification mechanism for - region-manager faults */ + Signal_context_capability _fault_sigh { }; Address_space *_address_space { nullptr }; @@ -297,8 +392,7 @@ class Genode::Region_map_component : private Weak_object, * Dimension slab allocator for regions such that backing store is * allocated at the granularity of pages. */ - typedef Tslab - Ref_slab; + using Ref_slab = Tslab; Allocator_avl_tpl _map; /* region map for attach, detach, pagefaults */ @@ -306,53 +400,98 @@ class Genode::Region_map_component : private Weak_object, the region map and wait for fault resolution */ List _clients { }; /* list of RM clients using this region map */ - Mutex _mutex { }; /* mutex for map and list */ + Mutex mutable _mutex { }; /* mutex for map and list */ Pager_entrypoint &_pager_ep; Rm_dataspace_component _ds; /* dataspace representation of region map */ Dataspace_capability _ds_cap; - template - auto _apply_to_dataspace(addr_t addr, F const &f, addr_t offset, - unsigned level, addr_t dst_region_size) - -> typename Trait::Functor::Return_type + struct Recursion_limit { unsigned value; }; + + /** + * Resolve region at a given fault address + * + * /param resolved_fn functor called with the resolved region and the + * region-relative fault information + * + * Called recursively when resolving a page fault in nested region maps. + */ + With_mapping_result _with_region_at_fault(Recursion_limit const recursion_limit, + Core::Fault const &fault, + auto const &resolved_fn, + auto const &reflect_fn) { - using Functor = Trait::Functor; - using Return_type = typename Functor::Return_type; + using Result = With_mapping_result; + + if (recursion_limit.value == 0) + return Result::RECURSION_LIMIT; Mutex::Guard lock_guard(_mutex); - /* skip further lookup when reaching the recursion limit */ - if (!level) return f(this, nullptr, 0, 0, dst_region_size); - /* lookup region and dataspace */ - Rm_region *region = _map.metadata((void*)addr); - Dataspace_component *dsc = region ? ®ion->dataspace() - : nullptr; + Rm_region const * const region_ptr = _map.metadata((void*)fault.hotspot.value); - if (region && dst_region_size > region->size()) - dst_region_size = region->size(); - - - /* calculate offset in dataspace */ - addr_t ds_offset = region ? (addr - region->base() - + region->offset()) : 0; - - /* check for nested dataspace */ - Native_capability cap = dsc ? dsc->sub_rm() - : Native_capability(); - - if (!cap.valid()) return f(this, region, ds_offset, offset, dst_region_size); - - /* in case of a nested dataspace perform a recursive lookup */ - auto lambda = [&] (Region_map_component *rmc) -> Return_type + auto reflect_fault = [&] (Result result) { - return (!rmc) ? f(nullptr, nullptr, ds_offset, offset, dst_region_size) - : rmc->_apply_to_dataspace(ds_offset, f, - offset+region->base(), - --level, - dst_region_size); + if (!_fault_sigh.valid()) + return result; /* not reflected to user land */ + + reflect_fn(*this, fault); + return Result::REFLECTED; /* omit diagnostics */ }; - return _session_ep.apply(cap, lambda); + + if (!region_ptr || region_ptr->reserved()) + return reflect_fault(Result::NO_REGION); + + Rm_region const ®ion = *region_ptr; + + /* fault information relative to 'region' */ + Core::Fault const relative_fault = fault.within_region(region); + + Result result = Result::NO_REGION; + + region.with_dataspace([&] (Dataspace_component &dataspace) { + + Native_capability managed_ds_cap = dataspace.sub_rm(); + + /* region refers to a regular dataspace */ + if (!managed_ds_cap.valid()) { + + bool const writeable = relative_fault.rwx.w + && dataspace.writeable(); + + bool const write_violation = relative_fault.write_access() + && !writeable; + + bool const exec_violation = relative_fault.exec_access() + && !relative_fault.rwx.x; + + if (write_violation) { + result = reflect_fault(Result::WRITE_VIOLATION); + return; + } + + if (exec_violation) { + result = reflect_fault(Result::EXEC_VIOLATION); + return; + } + + result = resolved_fn(region, relative_fault); + return; + } + + /* traverse into managed dataspace */ + Core::Fault const sub_region_map_relative_fault = + relative_fault.within_sub_region_map(region.offset(), + dataspace.size()); + + _session_ep.apply(managed_ds_cap, [&] (Region_map_component *rmc_ptr) { + if (rmc_ptr) + result = rmc_ptr->_with_region_at_fault({ recursion_limit.value - 1 }, + sub_region_map_relative_fault, + resolved_fn, reflect_fn); }); + }); + + return result; } /* @@ -362,27 +501,34 @@ class Genode::Region_map_component : private Weak_object, struct Attach_attr { - size_t size; - off_t offset; - bool use_local_addr; - addr_t local_addr; - bool executable; - bool writeable; - bool dma; + Attr attr; + bool dma; }; - Local_addr _attach(Dataspace_capability, Attach_attr); + Attach_result _attach(Dataspace_capability, Attach_attr); + + void _with_region(addr_t at, auto const &fn) + { + /* read meta data for address */ + Rm_region * const region_ptr = _map.metadata((void *)at); + + if (!region_ptr) { + if (_diag.enabled) + warning("_with_region: no attachment at ", (void *)at); + return; + } + + if ((region_ptr->base() != static_cast(at)) && _diag.enabled) + warning("_with_region: ", reinterpret_cast(at), " is not " + "the beginning of the region ", Hex(region_ptr->base())); + + fn(*region_ptr); + } + + void _reserve_and_flush_unsynchronized(Rm_region &); public: - /* - * Unmaps a memory area from all address spaces referencing it. - * - * \param base base address of region to unmap - * \param size size of region to unmap - */ - void unmap_region(addr_t base, size_t size) override; - /** * Constructor * @@ -408,8 +554,6 @@ class Genode::Region_map_component : private Weak_object, void address_space(Address_space *space) { _address_space = space; } Address_space *address_space() { return _address_space; } - class Fault_area; - /** * Register fault * @@ -417,11 +561,9 @@ class Genode::Region_map_component : private Weak_object, * for resolution. * * \param faulter faulting region-manager client - * \param pf_addr page-fault address - * \param pf_type type of page fault (read/write/execute) + * \param fault fault information */ - void fault(Rm_faulter &faulter, addr_t pf_addr, - Region_map::State::Fault_type pf_type); + void fault(Rm_faulter &faulter, Fault); /** * Dissolve faulter from region map @@ -434,18 +576,63 @@ class Genode::Region_map_component : private Weak_object, Rm_dataspace_component &dataspace_component() { return _ds; } /** - * Apply a function to dataspace attached at a given address + * Call 'apply_fn' with resolved mapping information for given fault * - * /param addr address where the dataspace is attached - * /param f functor or lambda to apply + * /param apply_fn functor called with a 'Mapping' that is suitable + * for resolving given the 'fault' + * /param reflect_fn functor called to reflect a missing mapping + * to user space if a fault handler is registered */ - template - auto apply_to_dataspace(addr_t addr, F f) - -> typename Trait::Functor::Return_type + With_mapping_result with_mapping_for_fault(Core::Fault const &fault, + auto const &apply_fn, + auto const &reflect_fn) { - enum { RECURSION_LIMIT = 5 }; + return _with_region_at_fault(Recursion_limit { 5 }, fault, + [&] (Rm_region const ®ion, Core::Fault const ®ion_relative_fault) + { + With_mapping_result result = With_mapping_result::NO_REGION; + region.with_dataspace([&] (Dataspace_component &dataspace) { + Core::Fault const ram_relative_fault = + region_relative_fault.within_ram(region.offset(), dataspace.attr()); - return _apply_to_dataspace(addr, f, 0, RECURSION_LIMIT, ~0UL); + Log2_range src_range { ram_relative_fault.hotspot }; + Log2_range dst_range { fault.hotspot }; + + src_range = src_range.constrained(ram_relative_fault.bounds); + + Log2 const common_size = Log2_range::common_log2(dst_range, + src_range); + Log2 const map_size = kernel_constrained_map_size(common_size); + + src_range = src_range.constrained(map_size); + dst_range = dst_range.constrained(map_size); + + if (!src_range.valid() || !dst_range.valid()) { + error("invalid mapping"); + return; + } + + Mapping const mapping { + .dst_addr = dst_range.base.value, + .src_addr = src_range.base.value, + .size_log2 = map_size.log2, + .cached = dataspace.cacheability() == CACHED, + .io_mem = dataspace.io_mem(), + .dma_buffer = region.dma(), + .write_combined = dataspace.cacheability() == WRITE_COMBINED, + .writeable = ram_relative_fault.rwx.w, + .executable = ram_relative_fault.rwx.x + }; + + apply_fn(mapping); + + result = With_mapping_result::RESOLVED; + }); + + return result; + }, + reflect_fn + ); } /** @@ -456,30 +643,28 @@ class Genode::Region_map_component : private Weak_object, void add_client(Rm_client &); void remove_client(Rm_client &); - /** - * Create mapping item to be placed into the page table - */ - static Mapping create_map_item(Region_map_component *region_map, - Rm_region ®ion, - addr_t ds_offset, - addr_t region_offset, - Dataspace_component &dsc, - addr_t, addr_t); - using Attach_dma_result = Pd_session::Attach_dma_result; Attach_dma_result attach_dma(Dataspace_capability, addr_t); + /********************************* + ** Region_map_detach interface ** + *********************************/ + + void unmap_region (addr_t, size_t) override; + void detach_at (addr_t) override; + void reserve_and_flush (addr_t) override; + + /************************** ** Region map interface ** **************************/ - Local_addr attach (Dataspace_capability, size_t, off_t, - bool, Local_addr, bool, bool) override; - void detach (Local_addr) override; - void fault_handler (Signal_context_capability handler) override; - State state () override; + Attach_result attach (Dataspace_capability, Attr const &) override; + void detach (addr_t at) override { detach_at(at); } + void fault_handler (Signal_context_capability) override; + Fault fault () override; Dataspace_capability dataspace () override { return _ds_cap; } }; diff --git a/repos/base/src/core/include/rm_root.h b/repos/base/src/core/include/rm_root.h index 263564cc71..ec30be460d 100644 --- a/repos/base/src/core/include/rm_root.h +++ b/repos/base/src/core/include/rm_root.h @@ -17,14 +17,14 @@ /* Genode includes */ #include -/* core-local includes */ +/* core includes */ #include #include -namespace Genode { class Rm_root; } +namespace Core { class Rm_root; } -class Genode::Rm_root : public Root_component +class Core::Rm_root : public Root_component { private: diff --git a/repos/base/src/core/include/rm_session_component.h b/repos/base/src/core/include/rm_session_component.h index f90f3c4d7e..2621ab0c45 100644 --- a/repos/base/src/core/include/rm_session_component.h +++ b/repos/base/src/core/include/rm_session_component.h @@ -22,10 +22,10 @@ /* core includes */ #include -namespace Genode { class Rm_session_component; } +namespace Core { class Rm_session_component; } -class Genode::Rm_session_component : public Session_object +class Core::Rm_session_component : public Session_object { private: @@ -72,7 +72,7 @@ class Genode::Rm_session_component : public Session_object ** Rm_session interface ** **************************/ - Capability create(size_t size) override + Create_result create(size_t size) override { Mutex::Guard guard(_region_maps_lock); @@ -86,7 +86,8 @@ class Genode::Rm_session_component : public Session_object return rm->cap(); } - catch (Allocator::Out_of_memory) { throw Out_of_ram(); } + catch (Out_of_ram) { return Create_error::OUT_OF_RAM; } + catch (Out_of_caps) { return Create_error::OUT_OF_CAPS; } } void destroy(Capability cap) override diff --git a/repos/base/src/core/include/rom_fs.h b/repos/base/src/core/include/rom_fs.h index 00bcc17691..cdfaf6a619 100644 --- a/repos/base/src/core/include/rom_fs.h +++ b/repos/base/src/core/include/rom_fs.h @@ -15,47 +15,46 @@ #ifndef _CORE__INCLUDE__ROM_FS_H_ #define _CORE__INCLUDE__ROM_FS_H_ -#include -#include +/* Genode includes */ +#include -namespace Genode { +/* core includes */ +#include + +namespace Core { + + using Rom_name = String<64>; struct Rom_module; struct Rom_fs; } -struct Genode::Rom_module : Genode::Avl_string_base +struct Core::Rom_module : Dictionary::Element { addr_t const addr = 0; size_t const size = 0; - Rom_module() : Avl_string_base(nullptr) { } - - Rom_module(addr_t const addr, size_t const size, char const * const name) - : Avl_string_base(name), addr(addr), size(size) { } + Rom_module(Dictionary &dict, Rom_name const &name, + addr_t addr, size_t size) + : + Dictionary::Element(dict, name), + addr(addr), size(size) + { } bool valid() const { return size ? true : false; } - void print(Genode::Output & out) const { - Genode::print(out, Hex_range(addr, size), " ", name()); } + void print(Output &out) const { + Genode::print(out, Hex_range(addr, size), " ", name); } }; -struct Genode::Rom_fs : Genode::Avl_tree +struct Core::Rom_fs : Dictionary { - Rom_module const * find(char const * const name) const + void print(Output & out) const { - return first() ? (Rom_module const *)first()->find_by_name(name) - : nullptr; - } - - void print(Genode::Output & out) const - { - if (!first()) Genode::print(out, "No modules in Rom_fs\n"); - Genode::print(out, "ROM modules:\n"); - for_each([&] (Avl_string_base const & rom) { - Genode::print(out, " ROM: ", *static_cast(&rom), "\n"); }); + for_each([&] (Rom_module const &rom) { + Genode::print(out, " ROM: ", rom, "\n"); }); } }; diff --git a/repos/base/src/core/include/rom_root.h b/repos/base/src/core/include/rom_root.h index 2195a2f12a..879c919c8b 100644 --- a/repos/base/src/core/include/rom_root.h +++ b/repos/base/src/core/include/rom_root.h @@ -15,41 +15,42 @@ #define _CORE__INCLUDE__ROM_ROOT_H_ #include -#include "rom_session_component.h" -namespace Genode { +/* Genode includes */ +#include - class Rom_root : public Root_component - { +namespace Core { class Rom_root; } - private: - Rom_fs &_rom_fs; /* rom file system */ - Rpc_entrypoint &_ds_ep; /* entry point for managing rom dataspaces */ +class Core::Rom_root : public Root_component +{ + private: - protected: + Rom_fs &_rom_fs; /* rom file system */ + Rpc_entrypoint &_ds_ep; /* entry point for managing rom dataspaces */ - Rom_session_component *_create_session(const char *args) override { - return new (md_alloc()) Rom_session_component(_rom_fs, _ds_ep, args); } + protected: - public: + Rom_session_component *_create_session(const char *args) override { + return new (md_alloc()) Rom_session_component(_rom_fs, _ds_ep, args); } - /** - * Constructor - * - * \param session_ep entry point for managing ram session objects - * \param ds_ep entry point for managing dataspaces - * \param rom_fs platform ROM file system - * \param md_alloc meta-data allocator to be used by root component - */ - Rom_root(Rpc_entrypoint &session_ep, - Rpc_entrypoint &ds_ep, - Rom_fs &rom_fs, - Allocator &md_alloc) - : - Root_component(&session_ep, &md_alloc), - _rom_fs(rom_fs), _ds_ep(ds_ep) { } - }; -} + public: + + /** + * Constructor + * + * \param session_ep entry point for managing ram session objects + * \param ds_ep entry point for managing dataspaces + * \param rom_fs platform ROM file system + * \param md_alloc meta-data allocator to be used by root component + */ + Rom_root(Rpc_entrypoint &session_ep, + Rpc_entrypoint &ds_ep, + Rom_fs &rom_fs, + Allocator &md_alloc) + : + Root_component(&session_ep, &md_alloc), + _rom_fs(rom_fs), _ds_ep(ds_ep) { } +}; #endif /* _CORE__INCLUDE__ROM_ROOT_H_ */ diff --git a/repos/base/src/core/include/rom_session_component.h b/repos/base/src/core/include/rom_session_component.h index c584701f5f..9544605c4d 100644 --- a/repos/base/src/core/include/rom_session_component.h +++ b/repos/base/src/core/include/rom_session_component.h @@ -14,69 +14,69 @@ #ifndef _CORE__INCLUDE__ROM_SESSION_COMPONENT_H_ #define _CORE__INCLUDE__ROM_SESSION_COMPONENT_H_ -#include #include #include #include #include -namespace Genode { +/* core includes */ +#include - class Rom_session_component : public Rpc_object - { - private: - - Rom_module const * const _rom_module = nullptr; - Dataspace_component _ds; - Rpc_entrypoint &_ds_ep; - Rom_dataspace_capability _ds_cap; - - Rom_module const &_find_rom(Rom_fs &rom_fs, const char *args) - { - /* extract label */ - Session_label const label = label_from_args(args); - - /* find ROM module for trailing label element */ - Rom_module const * rom = rom_fs.find(label.last_element().string()); - if (rom) - return *rom; - - throw Service_denied(); - } - - /* - * Noncopyable - */ - Rom_session_component(Rom_session_component const &); - Rom_session_component &operator = (Rom_session_component const &); - - public: - - /** - * Constructor - * - * \param rom_fs ROM filesystem - * \param ds_ep entry point to manage the dataspace - * corresponding the rom session - * \param args session-construction arguments - */ - Rom_session_component(Rom_fs &rom_fs, - Rpc_entrypoint &ds_ep, - const char *args); - - /** - * Destructor - */ - ~Rom_session_component(); +namespace Core { class Rom_session_component; } - /*************************** - ** Rom session interface ** - ***************************/ +class Core::Rom_session_component : public Rpc_object +{ + private: - Rom_dataspace_capability dataspace() override { return _ds_cap; } - void sigh(Signal_context_capability) override { } - }; -} + Rom_module const * const _rom_module = nullptr; + Dataspace_component _ds; + Rpc_entrypoint &_ds_ep; + Rom_dataspace_capability _ds_cap; + + Rom_module const &_find_rom(Rom_fs &rom_fs, const char *args) + { + return rom_fs.with_element(label_from_args(args).last_element(), + + [&] (Rom_module const &rom) -> Rom_module const & { + return rom; }, + + [&] () -> Rom_module const & { + throw Service_denied(); }); + } + + /* + * Noncopyable + */ + Rom_session_component(Rom_session_component const &); + Rom_session_component &operator = (Rom_session_component const &); + + public: + + /** + * Constructor + * + * \param rom_fs ROM filesystem + * \param ds_ep entry point to manage the dataspace + * corresponding the rom session + * \param args session-construction arguments + */ + Rom_session_component(Rom_fs &rom_fs, + Rpc_entrypoint &ds_ep, + const char *args); + + /** + * Destructor + */ + ~Rom_session_component(); + + + /*************************** + ** Rom session interface ** + ***************************/ + + Rom_dataspace_capability dataspace() override { return _ds_cap; } + void sigh(Signal_context_capability) override { } +}; #endif /* _CORE__INCLUDE__ROM_SESSION_COMPONENT_H_ */ diff --git a/repos/base/src/core/include/rpc_cap_factory.h b/repos/base/src/core/include/rpc_cap_factory.h index 348bd7d54a..5cf81a215b 100644 --- a/repos/base/src/core/include/rpc_cap_factory.h +++ b/repos/base/src/core/include/rpc_cap_factory.h @@ -18,9 +18,13 @@ #include #include -namespace Genode { class Rpc_cap_factory; } +/* core includes */ +#include -class Genode::Rpc_cap_factory +namespace Core { class Rpc_cap_factory; } + + +class Core::Rpc_cap_factory { private: diff --git a/repos/base/src/core/include/signal_broker.h b/repos/base/src/core/include/signal_broker.h index a16e372e33..26d36cb60a 100644 --- a/repos/base/src/core/include/signal_broker.h +++ b/repos/base/src/core/include/signal_broker.h @@ -14,23 +14,24 @@ #ifndef _CORE__INCLUDE__SIGNAL_BROKER_H_ #define _CORE__INCLUDE__SIGNAL_BROKER_H_ +/* core includes */ #include -#include #include #include -namespace Genode { class Signal_broker; } +namespace Core { class Signal_broker; } -class Genode::Signal_broker + +class Core::Signal_broker { private: - Allocator &_md_alloc; - Rpc_entrypoint &_source_ep; - Rpc_entrypoint &_context_ep; - Signal_source_component _source; - Signal_source_capability _source_cap; - Signal_context_slab _contexts_slab { _md_alloc }; + Allocator &_md_alloc; + Rpc_entrypoint &_source_ep; + Rpc_entrypoint &_context_ep; + Signal_source_component _source; + Capability _source_cap; + Signal_context_slab _contexts_slab { _md_alloc }; Signal_delivery_proxy_component _delivery_proxy { _source_ep }; public: @@ -58,12 +59,12 @@ class Genode::Signal_broker free_context(r->cap()); } - Signal_source_capability alloc_signal_source() { return _source_cap; } + Capability alloc_signal_source() { return _source_cap; } - void free_signal_source(Signal_source_capability) { } + void free_signal_source(Capability) { } Signal_context_capability - alloc_context(Signal_source_capability, unsigned long imprint) + alloc_context(Capability, unsigned long imprint) { /* * XXX For now, we ignore the signal-source argument as we diff --git a/repos/base/src/core/include/signal_context_slab.h b/repos/base/src/core/include/signal_context_slab.h index e66b48bf7e..fd733fa4bb 100644 --- a/repos/base/src/core/include/signal_context_slab.h +++ b/repos/base/src/core/include/signal_context_slab.h @@ -17,10 +17,11 @@ /* Genode includes */ #include -/* core-local includes */ +/* core includes */ +#include #include -namespace Genode { struct Signal_context_slab; } +namespace Core { struct Signal_context_slab; } /** @@ -32,7 +33,7 @@ namespace Genode { struct Signal_context_slab; } * uses the PD session itself as backing store (which would be in the middle of * construction). */ -struct Genode::Signal_context_slab : Slab +struct Core::Signal_context_slab : Slab { static constexpr size_t SBS = 960*sizeof(long); uint8_t _initial_sb[SBS]; diff --git a/repos/base/src/core/include/signal_delivery_proxy.h b/repos/base/src/core/include/signal_delivery_proxy.h index 46b4a3c021..b648f3843f 100644 --- a/repos/base/src/core/include/signal_delivery_proxy.h +++ b/repos/base/src/core/include/signal_delivery_proxy.h @@ -14,84 +14,91 @@ #ifndef _CORE__INCLUDE__SIGNAL_DELIVERY_PROXY_H_ #define _CORE__INCLUDE__SIGNAL_DELIVERY_PROXY_H_ -namespace Genode { +/* core includes */ +#include - struct Signal_delivery_proxy : Interface - { - GENODE_RPC(Rpc_deliver, void, _deliver_from_ep, Signal_context_capability, unsigned); - GENODE_RPC(Rpc_release, void, _release_from_ep, Genode::addr_t); - GENODE_RPC_INTERFACE(Rpc_deliver, Rpc_release); - }; - - struct Signal_delivery_proxy_component - : - Rpc_object - { - Rpc_entrypoint &_ep; - - Capability _proxy_cap; - - /** - * Constructor - * - * \param ep entrypoint to be used as a proxy for delivering signals - * as IPC-reply messages. - */ - Signal_delivery_proxy_component(Rpc_entrypoint &ep) - : _ep(ep), _proxy_cap(_ep.manage(this)) { } - - ~Signal_delivery_proxy_component() - { - if (_proxy_cap.valid()) - _ep.dissolve(this); - } - - /** - * Signal_delivery_proxy RPC interface - * - * This method is executed in the context of the 'ep'. Hence, it - * can produce legitimate IPC reply messages to 'Signal_source' - * clients. - */ - void _deliver_from_ep(Signal_context_capability cap, unsigned cnt) - { - _ep.apply(cap, [&] (Signal_context_component *context) { - if (context) - context->source().submit(*context, cnt); - else - warning("invalid signal-context capability"); - }); - } - - void _release_from_ep(addr_t const context_addr) - { - Signal_context_component * context = reinterpret_cast(context_addr); - if (context) - context->source().release(*context); - } - - /** - * Deliver signal via the proxy mechanism - * - * Since this method perform an RPC call to the 'ep' specified at the - * constructor, is must never be called from this ep. - * - * Called from threads other than 'ep'. - */ - void submit(Signal_context_capability cap, unsigned cnt) { - _proxy_cap.call(cap, cnt); } - - /** - * Deliver signal via the proxy mechanism - * - * Since this method perform an RPC call to the 'ep' specified at the - * constructor, is must never be called from this ep. - * - * Called from threads other than 'ep'. - */ - void release(Signal_context_component &context) { - _proxy_cap.call(reinterpret_cast(&context)); } - }; +namespace Core { + struct Signal_delivery_proxy; + struct Signal_delivery_proxy_component; } + +struct Core::Signal_delivery_proxy : Interface +{ + GENODE_RPC(Rpc_deliver, void, _deliver_from_ep, Signal_context_capability, unsigned); + GENODE_RPC(Rpc_release, void, _release_from_ep, addr_t); + GENODE_RPC_INTERFACE(Rpc_deliver, Rpc_release); +}; + + +struct Core::Signal_delivery_proxy_component +: + Rpc_object +{ + Rpc_entrypoint &_ep; + + Capability _proxy_cap; + + /** + * Constructor + * + * \param ep entrypoint to be used as a proxy for delivering signals + * as IPC-reply messages. + */ + Signal_delivery_proxy_component(Rpc_entrypoint &ep) + : _ep(ep), _proxy_cap(_ep.manage(this)) { } + + ~Signal_delivery_proxy_component() + { + if (_proxy_cap.valid()) + _ep.dissolve(this); + } + + /** + * Signal_delivery_proxy RPC interface + * + * This method is executed in the context of the 'ep'. Hence, it + * can produce legitimate IPC reply messages to 'Signal_source' + * clients. + */ + void _deliver_from_ep(Signal_context_capability cap, unsigned cnt) + { + _ep.apply(cap, [&] (Signal_context_component *context) { + if (context) + context->source().submit(*context, cnt); + else + warning("invalid signal-context capability"); + }); + } + + void _release_from_ep(addr_t const context_addr) + { + Signal_context_component * context = reinterpret_cast(context_addr); + if (context) + context->source().release(*context); + } + + /** + * Deliver signal via the proxy mechanism + * + * Since this method perform an RPC call to the 'ep' specified at the + * constructor, is must never be called from this ep. + * + * Called from threads other than 'ep'. + */ + void submit(Signal_context_capability cap, unsigned cnt) { + _proxy_cap.call(cap, cnt); } + + /** + * Deliver signal via the proxy mechanism + * + * Since this method perform an RPC call to the 'ep' specified at the + * constructor, is must never be called from this ep. + * + * Called from threads other than 'ep'. + */ + void release(Signal_context_component &context) { + _proxy_cap.call(reinterpret_cast(&context)); } +}; + #endif /* _CORE__INCLUDE__SIGNLA_DELIVERY_PROXY_H_ */ diff --git a/repos/base/src/core/include/signal_source_component.h b/repos/base/src/core/include/signal_source_component.h index bd03fcaeb5..817d86dc05 100644 --- a/repos/base/src/core/include/signal_source_component.h +++ b/repos/base/src/core/include/signal_source_component.h @@ -21,19 +21,22 @@ #include #include -namespace Genode { +/* core includes */ +#include + +namespace Core { class Signal_context_component; class Signal_source_component; - typedef Fifo Signal_queue; + using Signal_queue = Fifo; struct Signal_context_slab; } -class Genode::Signal_context_component : public Rpc_object, - private Signal_queue::Element +class Core::Signal_context_component : public Rpc_object, + private Signal_queue::Element { private: @@ -75,7 +78,7 @@ class Genode::Signal_context_component : public Rpc_object, }; -class Genode::Signal_source_component : public Signal_source_rpc_object +class Core::Signal_source_component : public Signal_source_rpc_object { private: @@ -105,7 +108,7 @@ class Genode::Signal_source_component : public Signal_source_rpc_object }; -Genode::Signal_context_component::~Signal_context_component() +Core::Signal_context_component::~Signal_context_component() { if (enqueued()) _source.release(*this); diff --git a/repos/base/src/core/include/signal_transmitter.h b/repos/base/src/core/include/signal_transmitter.h index b06a6f4072..a3e4711180 100644 --- a/repos/base/src/core/include/signal_transmitter.h +++ b/repos/base/src/core/include/signal_transmitter.h @@ -14,9 +14,14 @@ #ifndef _CORE__INCLUDE__SIGNAL_TRANSMITTER_H_ #define _CORE__INCLUDE__SIGNAL_TRANSMITTER_H_ -namespace Genode { +/* core includes */ +#include + +namespace Genode { class Rpc_entrypoint; } + + +namespace Core { - class Rpc_entrypoint; /* * Initialize the emission of signals originating from the component diff --git a/repos/base/src/core/include/synced_ram_allocator.h b/repos/base/src/core/include/synced_ram_allocator.h index a7cd605fc6..6b94e1dde6 100644 --- a/repos/base/src/core/include/synced_ram_allocator.h +++ b/repos/base/src/core/include/synced_ram_allocator.h @@ -18,10 +18,13 @@ #include #include -namespace Genode { class Synced_ram_allocator; } +/* core includes */ +#include + +namespace Core { class Synced_ram_allocator; } -class Genode::Synced_ram_allocator : public Ram_allocator +class Core::Synced_ram_allocator : public Ram_allocator { private: diff --git a/repos/base/src/core/include/synced_range_allocator.h b/repos/base/src/core/include/synced_range_allocator.h index f1c34215d9..1ca37e1f0d 100644 --- a/repos/base/src/core/include/synced_range_allocator.h +++ b/repos/base/src/core/include/synced_range_allocator.h @@ -18,7 +18,10 @@ #include #include -namespace Genode { +/* core includes */ +#include + +namespace Core { class Mapped_mem_allocator; template class Synced_range_allocator; } @@ -33,7 +36,7 @@ namespace Genode { * \param ALLOC class implementing the 'Range_allocator' interface */ template -class Genode::Synced_range_allocator : public Range_allocator +class Core::Synced_range_allocator : public Range_allocator { private: @@ -48,12 +51,10 @@ class Genode::Synced_range_allocator : public Range_allocator using Guard = typename Synced_interface::Guard; - template - Synced_range_allocator(Mutex &mutex, ARGS &&... args) + Synced_range_allocator(Mutex &mutex, auto &&... args) : _mutex(mutex), _alloc(args...), _synced_object(_mutex, &_alloc) { } - template - Synced_range_allocator(ARGS &&... args) + Synced_range_allocator(auto &&... args) : _alloc(args...), _synced_object(_mutex, &_alloc) { } Guard operator () () { return _synced_object(); } diff --git a/repos/base/src/core/include/system_control.h b/repos/base/src/core/include/system_control.h new file mode 100644 index 0000000000..f5fa0b5bcb --- /dev/null +++ b/repos/base/src/core/include/system_control.h @@ -0,0 +1,36 @@ +/* + * \brief Interface to get access to privileged system control capability + * \author Alexander Boettcher + * \date 2023-09-25 + */ + +/* + * Copyright (C) 2023 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CORE__INCLUDE__SYSTEM_CONTROL_H_ +#define _CORE__INCLUDE__SYSTEM_CONTROL_H_ + + +#include + + +namespace Core { + + class System_control; + + System_control & init_system_control(Allocator &, Rpc_entrypoint &); +} + + +class Core::System_control : Interface +{ + public: + + virtual Capability control_cap(Affinity::Location) const = 0; +}; + +#endif /* _CORE__INCLUDE__SYSTEM_CONTROL_H_ */ diff --git a/repos/base/src/core/include/trace/policy_registry.h b/repos/base/src/core/include/trace/policy_registry.h index 53ab02192b..6c9882bbe7 100644 --- a/repos/base/src/core/include/trace/policy_registry.h +++ b/repos/base/src/core/include/trace/policy_registry.h @@ -18,17 +18,20 @@ #include #include -namespace Genode { namespace Trace { +/* core includes */ +#include + +namespace Core { namespace Trace { class Policy_owner; class Policy; class Policy_registry; } } -class Genode::Trace::Policy_owner : Interface { }; +class Core::Trace::Policy_owner : Interface { }; -class Genode::Trace::Policy : public Genode::List::Element +class Core::Trace::Policy : public List::Element { friend class Policy_registry; @@ -38,7 +41,7 @@ class Genode::Trace::Policy : public Genode::List::Elemen Allocator &_md_alloc; Policy_id const _id; Dataspace_capability _ds; - size_t const _size; + Policy_size const _size; /** * Constructor @@ -46,7 +49,7 @@ class Genode::Trace::Policy : public Genode::List::Elemen * \param md_alloc allocator that holds the 'Policy' object */ Policy(Policy_owner const &owner, Policy_id const id, - Allocator &md_alloc, Dataspace_capability ds, size_t size) + Allocator &md_alloc, Dataspace_capability ds, Policy_size size) : _owner(owner), _md_alloc(md_alloc), _id(id), _ds(ds), _size(size) { } @@ -63,14 +66,14 @@ class Genode::Trace::Policy : public Genode::List::Elemen public: Dataspace_capability dataspace() const { return _ds; } - size_t size() const { return _size; } + Policy_size size() const { return _size; } }; /** * Global policy registry */ -class Genode::Trace::Policy_registry +class Core::Trace::Policy_registry { private: @@ -78,13 +81,12 @@ class Genode::Trace::Policy_registry Mutex _mutex { }; List _policies { }; - Policy &_unsynchronized_lookup(Policy_owner const &owner, Policy_id id) + void _with_policy_unsynchronized(Policy_owner const &owner, + Policy_id const id, auto const &fn) { for (Policy *p = _policies.first(); p; p = p->next()) if (p->owned_by(owner) && p->has_id(id)) - return *p; - - throw Nonexistent_policy(); + fn(*p); } Policy *_any_policy_owned_by(Policy_owner const &owner) @@ -107,7 +109,7 @@ class Genode::Trace::Policy_registry } void insert(Policy_owner const &owner, Policy_id const id, - Allocator &md_alloc, Dataspace_capability ds, size_t size) + Allocator &md_alloc, Dataspace_capability ds, Policy_size size) { Mutex::Guard guard(_mutex); @@ -140,18 +142,22 @@ class Genode::Trace::Policy_registry } } - Dataspace_capability dataspace(Policy_owner &owner, Policy_id id) + void with_dataspace(Policy_owner &owner, Policy_id id, auto const &fn) { Mutex::Guard guard(_mutex); - return _unsynchronized_lookup(owner, id).dataspace(); + _with_policy_unsynchronized(owner, id, [&] (Policy &p) { + fn(p.dataspace()); }); } - size_t size(Policy_owner &owner, Policy_id id) + Policy_size size(Policy_owner &owner, Policy_id id) { Mutex::Guard guard(_mutex); - return _unsynchronized_lookup(owner, id).size(); + Policy_size result { 0 }; + _with_policy_unsynchronized(owner, id, [&] (Policy const &p) { + result = p.size(); }); + return result; } }; diff --git a/repos/base/src/core/include/trace/root.h b/repos/base/src/core/include/trace/root.h index 57bb453bba..5818bbae11 100644 --- a/repos/base/src/core/include/trace/root.h +++ b/repos/base/src/core/include/trace/root.h @@ -20,10 +20,10 @@ /* core-internal includes */ #include -namespace Genode { namespace Trace { class Root; } } +namespace Core { namespace Trace { class Root; } } -class Genode::Trace::Root : public Genode::Root_component +class Core::Trace::Root : public Root_component { private: @@ -38,10 +38,9 @@ class Genode::Trace::Root : public Genode::Root_component { size_t ram_quota = Arg_string::find_arg(args, "ram_quota").ulong_value(0); size_t arg_buffer_size = Arg_string::find_arg(args, "arg_buffer_size").ulong_value(0); - unsigned parent_levels = (unsigned)Arg_string::find_arg(args, "parent_levels").ulong_value(0); if (arg_buffer_size > ram_quota) - throw Service_denied(); + throw Insufficient_ram_quota(); return new (md_alloc()) Session_component(*this->ep(), @@ -49,7 +48,7 @@ class Genode::Trace::Root : public Genode::Root_component session_label_from_args(args), session_diag_from_args(args), _ram, _local_rm, - arg_buffer_size, parent_levels, + arg_buffer_size, _sources, _policies); } diff --git a/repos/base/src/core/include/trace/session_component.h b/repos/base/src/core/include/trace/session_component.h index dbdafbb847..0aa7301773 100644 --- a/repos/base/src/core/include/trace/session_component.h +++ b/repos/base/src/core/include/trace/session_component.h @@ -21,17 +21,16 @@ #include #include -/* core-local includes */ +/* core includes */ #include #include -namespace Genode { namespace Trace { class Session_component; } } +namespace Core { namespace Trace { class Session_component; } } -class Genode::Trace::Session_component +class Core::Trace::Session_component : - public Session_object, + public Session_object, public Trace::Policy_owner { private: @@ -47,6 +46,17 @@ class Genode::Trace::Session_component unsigned _policy_cnt { 0 }; Attached_ram_dataspace _argument_buffer; + /* + * Whenever a trace session is deliberately labeled as empty by the + * top-level init instance, the session is granted global reach. + * Otherwise, the label is taken a prefix filter for the visibility + * of trace subjects within the session. + */ + Filter _filter() const + { + return (_label == "init -> ") ? Filter("") : Filter(_label); + } + public: /** @@ -59,7 +69,6 @@ class Genode::Trace::Session_component Ram_allocator &ram, Region_map &local_rm, size_t arg_buffer_size, - unsigned parent_levels, Source_registry &sources, Policy_registry &policies); @@ -71,17 +80,16 @@ class Genode::Trace::Session_component ***********************/ Dataspace_capability dataspace(); - size_t subjects(); - size_t subject_infos(); - - Policy_id alloc_policy(size_t) override; - Dataspace_capability policy(Policy_id) override; - void unload_policy(Policy_id) override; - void trace(Subject_id, Policy_id, size_t) override; - void pause(Subject_id) override; - void resume(Subject_id) override; - Dataspace_capability buffer(Subject_id) override; - void free(Subject_id) override; + Subjects_rpc_result subjects(); + Infos_rpc_result subject_infos(); + Alloc_policy_rpc_result alloc_policy(Policy_size); + Dataspace_capability policy(Policy_id); + void unload_policy(Policy_id); + Trace_rpc_result trace(Subject_id, Policy_id, Buffer_size); + void pause(Subject_id); + void resume(Subject_id); + Dataspace_capability buffer(Subject_id); + void free(Subject_id); }; #endif /* _CORE__INCLUDE__TRACE__SESSION_COMPONENT_H_ */ diff --git a/repos/base/src/core/include/trace/source_registry.h b/repos/base/src/core/include/trace/source_registry.h index 900b9e16c1..124f3cccd6 100644 --- a/repos/base/src/core/include/trace/source_registry.h +++ b/repos/base/src/core/include/trace/source_registry.h @@ -14,8 +14,8 @@ #ifndef _CORE__INCLUDE__TRACE__SOURCE_REGISTRY_H_ #define _CORE__INCLUDE__TRACE__SOURCE_REGISTRY_H_ +/* Genode includes */ #include -#include #include #include #include @@ -23,7 +23,15 @@ /* base-internal include */ #include -namespace Genode { namespace Trace { +/* core-internal includes */ +#include + +namespace Core { namespace Trace { + + using namespace Genode::Trace; + + using Filter = String; + class Source; class Source_owner; class Source_registry; @@ -35,7 +43,7 @@ namespace Genode { namespace Trace { } } -struct Genode::Trace::Source_owner { }; +struct Core::Trace::Source_owner { }; /** @@ -43,10 +51,9 @@ struct Genode::Trace::Source_owner { }; * * There is one instance per thread. */ -class Genode::Trace::Source +class Core::Trace::Source : - public Genode::Weak_object, - public Genode::List::Element + public Weak_object, public List::Element { public: @@ -66,16 +73,18 @@ class Genode::Trace::Source virtual Info trace_source_info() const = 0; }; + struct Id { unsigned value; }; + private: - unsigned const _unique_id; + Id const _unique_id; Info_accessor const &_info; Control &_control; Dataspace_capability _policy { }; Dataspace_capability _buffer { }; Source_owner const *_owner_ptr = nullptr; - static unsigned _alloc_unique_id(); + static Id _alloc_unique_id(); /* * Noncopyable @@ -139,7 +148,7 @@ class Genode::Trace::Source Dataspace_capability buffer() const { return _buffer; } Dataspace_capability policy() const { return _policy; } - unsigned unique_id() const { return _unique_id; } + Id id() const { return _unique_id; } }; @@ -148,7 +157,7 @@ class Genode::Trace::Source * * There is a single instance within core. */ -class Genode::Trace::Source_registry +class Core::Trace::Source_registry { private: @@ -179,16 +188,11 @@ class Genode::Trace::Source_registry ** Interface used by TRACE service ** *************************************/ - template - void export_sources(TEST &test, INSERT &insert) + void for_each_source(auto const &fn) { for (Source *s = _entries.first(); s; s = s->next()) - if (!test(s->unique_id())) { - Source::Info const info = s->info(); - insert(s->unique_id(), s->weak_ptr(), info.label, info.name); - } + fn(*s); } - }; #endif /* _CORE__INCLUDE__TRACE__SOURCE_REGISTRY_H_ */ diff --git a/repos/base/src/core/include/trace/subject_registry.h b/repos/base/src/core/include/trace/subject_registry.h index 374aa5d05d..7c934ce85b 100644 --- a/repos/base/src/core/include/trace/subject_registry.h +++ b/repos/base/src/core/include/trace/subject_registry.h @@ -21,20 +21,23 @@ /* Genode includes */ #include -#include #include #include #include #include #include -/* core includes */ -#include - /* base-internal include */ #include -namespace Genode { namespace Trace { +/* core includes */ +#include +#include + +namespace Core { namespace Trace { + + using namespace Genode::Trace; + class Subject; class Subject_registry; } } @@ -43,10 +46,10 @@ namespace Genode { namespace Trace { /** * Subject of tracing data */ -class Genode::Trace::Subject +class Core::Trace::Subject : - public Genode::List::Element, - public Genode::Trace::Source_owner + public List::Element, + public Source_owner { private: @@ -96,29 +99,21 @@ class Genode::Trace::Subject /** * Clone dataspace into newly allocated dataspace */ - bool setup(Ram_allocator &ram, Region_map &local_rm, + void setup(Ram_allocator &ram, Region_map &local_rm, Dataspace_capability &from_ds, size_t size) { - if (!from_ds.valid()) - return false; - if (_size) flush(); + _ds = ram.alloc(size); /* may throw */ _ram_ptr = &ram; _size = size; - _ds = ram.alloc(_size); /* copy content */ - void *src = local_rm.attach(from_ds), - *dst = local_rm.attach(_ds); + Attached_dataspace from { local_rm, from_ds }, + to { local_rm, _ds }; - memcpy(dst, src, _size); - - local_rm.detach(src); - local_rm.detach(dst); - - return true; + Genode::memcpy(to.local_addr(), from.local_addr(), _size); } /** @@ -139,14 +134,13 @@ class Genode::Trace::Subject friend class Subject_registry; Subject_id const _id; - unsigned const _source_id; + Source::Id const _source_id; Weak_ptr _source; Session_label const _label; Thread_name const _name; Ram_dataspace _buffer { }; Ram_dataspace _policy { }; Policy_id _policy_id { }; - size_t _allocated_memory { 0 }; Subject_info::State _state() { @@ -169,25 +163,12 @@ class Genode::Trace::Subject return Subject_info::UNATTACHED; } - void _traceable_or_throw() - { - switch(_state()) { - case Subject_info::DEAD : throw Source_is_dead(); - case Subject_info::FOREIGN : throw Traced_by_other_session(); - case Subject_info::ERROR : throw Source_is_dead(); - case Subject_info::INVALID : throw Nonexistent_subject(); - case Subject_info::UNATTACHED : return; - case Subject_info::ATTACHED : return; - case Subject_info::TRACED : return; - } - } - public: /** * Constructor, called from 'Subject_registry' only */ - Subject(Subject_id id, unsigned source_id, Weak_ptr &source, + Subject(Subject_id id, Source::Id source_id, Weak_ptr &source, Session_label const &label, Thread_name const &name) : _id(id), _source_id(source_id), _source(source), @@ -197,15 +178,7 @@ class Genode::Trace::Subject /** * Destructor, releases ownership of associated source */ - ~Subject() - { - Locked_ptr source(_source); - - if (source.valid()) { - source->disable(); - source->release_ownership(*this); - } - } + ~Subject() { release(); } /** * Return registry-local ID @@ -215,49 +188,60 @@ class Genode::Trace::Subject /** * Test if subject belongs to the specified unique source ID */ - bool has_source_id(unsigned id) const { return id == _source_id; } + bool has_source_id(Source::Id id) const { return id.value == _source_id.value; } - size_t allocated_memory() const { return _allocated_memory; } - void reset_allocated_memory() { _allocated_memory = 0; } + enum class Trace_result { OK, OUT_OF_RAM, OUT_OF_CAPS, FOREIGN, + SOURCE_IS_DEAD, INVALID_SUBJECT }; /** * Start tracing * * \param size trace buffer size - * - * \throw Out_of_ram - * \throw Out_of_caps - * \throw Already_traced - * \throw Source_is_dead - * \throw Traced_by_other_session */ - void trace(Policy_id policy_id, Dataspace_capability policy_ds, - size_t policy_size, Ram_allocator &ram, - Region_map &local_rm, size_t size) + Trace_result trace(Policy_id policy_id, Dataspace_capability policy_ds, + Policy_size policy_size, Ram_allocator &ram, + Region_map &local_rm, Buffer_size size) { - /* check state and throw error in case subject is not traceable */ - _traceable_or_throw(); + /* check state and return error if subject is not traceable */ + switch(_state()) { + case Subject_info::DEAD: return Trace_result::SOURCE_IS_DEAD; + case Subject_info::ERROR: return Trace_result::SOURCE_IS_DEAD; + case Subject_info::FOREIGN: return Trace_result::FOREIGN; + case Subject_info::INVALID: return Trace_result::INVALID_SUBJECT; + case Subject_info::UNATTACHED: + case Subject_info::ATTACHED: + case Subject_info::TRACED: break; + } - _buffer.setup(ram, size); - if(!_policy.setup(ram, local_rm, policy_ds, policy_size)) - throw Already_traced(); + try { + _buffer.setup(ram, size.num_bytes); + } + catch (Out_of_ram) { return Trace_result::OUT_OF_RAM; } + catch (Out_of_caps) { return Trace_result::OUT_OF_CAPS; } + + try { + _policy.setup(ram, local_rm, policy_ds, policy_size.num_bytes); + } + catch (Out_of_ram) { _buffer.flush(); return Trace_result::OUT_OF_RAM; } + catch (Out_of_caps) { _buffer.flush(); return Trace_result::OUT_OF_CAPS; } /* inform trace source about the new buffer */ Locked_ptr source(_source); - if (!source->try_acquire(*this)) - throw Traced_by_other_session(); + if (!source->try_acquire(*this)) { + _policy.flush(); + _buffer.flush(); + return Trace_result::FOREIGN; + } _policy_id = policy_id; - _allocated_memory = policy_size + size; - source->trace(_policy.dataspace(), _buffer.dataspace()); + return Trace_result::OK; } void pause() { - /* inform trace source about the new buffer */ Locked_ptr source(_source); if (source.valid()) @@ -266,18 +250,13 @@ class Genode::Trace::Subject /** * Resume tracing of paused source - * - * \throw Source_is_dead */ void resume() { - /* inform trace source about the new buffer */ Locked_ptr source(_source); - if (!source.valid()) - throw Source_is_dead(); - - source->enable(); + if (source.valid()) + source->enable(); } Subject_info info() @@ -301,16 +280,19 @@ class Genode::Trace::Subject Dataspace_capability buffer() const { return _buffer.dataspace(); } - size_t release() + void release() { - /* inform trace source about the new buffer */ Locked_ptr source(_source); /* source vanished */ if (!source.valid()) - return 0; + return; - return _buffer.flush() + _policy.flush(); + source->disable(); + source->release_ownership(*this); + + _buffer.flush(); + _policy.flush(); } }; @@ -320,108 +302,47 @@ class Genode::Trace::Subject * * There exists one instance for each TRACE session. */ -class Genode::Trace::Subject_registry +class Core::Trace::Subject_registry { private: - typedef List Subjects; + using Subjects = List; Allocator &_md_alloc; Source_registry &_sources; + Filter const _filter; unsigned _id_cnt { 0 }; Mutex _mutex { }; Subjects _entries { }; - /** - * Functor for testing the existance of subjects for a given source - * - * This functor is invoked by 'Source_registry::export'. - */ - struct Tester - { - Subjects &subjects; - - Tester(Subjects &subjects) : subjects(subjects) { } - - bool operator () (unsigned source_id) - { - for (Subject *s = subjects.first(); s; s = s->next()) - if (s->has_source_id(source_id)) - return true; - return false; - } - } _tester { _entries }; - - /** - * Functor for inserting new subjects into the registry - * - * This functor is invoked by 'Source_registry::export'. - */ - struct Inserter - { - Subject_registry ®istry; - - Inserter(Subject_registry ®istry) : registry(registry) { } - - void operator () (unsigned source_id, Weak_ptr source, - Session_label const &label, Thread_name const &name) - { - Subject *subject = new (®istry._md_alloc) - Subject(Subject_id(++registry._id_cnt), source_id, source, label, name); - - registry._entries.insert(subject); - } - } _inserter { *this }; - /** * Destroy subject, and release policy and trace buffers - * - * \return RAM resources released during destruction */ - size_t _unsynchronized_destroy(Subject &s) + void _unsynchronized_destroy(Subject &s) { _entries.remove(&s); - - size_t const released_ram = s.release(); - + s.release(); destroy(&_md_alloc, &s); - - return released_ram; }; /** * Obtain subject from given session-local ID - * - * \throw Nonexistent_subject */ - Subject &_unsynchronized_lookup_by_id(Subject_id id) + void _with_subject_unsynchronized(Subject_id id, auto const &fn) { - for (Subject *s = _entries.first(); s; s = s->next()) - if (s->id() == id) - return *s; - - throw Nonexistent_subject(); + Subject *ptr = _entries.first(); + for (; ptr && (ptr->id().id != id.id); ptr = ptr->next()); + if (ptr) + fn(*ptr); } public: - /** - * Constructor - * - * \param md_alloc meta-data allocator used for allocating 'Subject' - * objects. - * \param ram allocator used for the allocation of trace - * buffers and policy dataspaces. - */ - Subject_registry(Allocator &md_alloc, - Source_registry &sources) + Subject_registry(Allocator &md_alloc, Source_registry &sources, Filter const &filter) : - _md_alloc(md_alloc), _sources(sources) + _md_alloc(md_alloc), _sources(sources), _filter(filter) { } - /** - * Destructor - */ ~Subject_registry() { Mutex::Guard guard(_mutex); @@ -437,13 +358,38 @@ class Genode::Trace::Subject_registry { Mutex::Guard guard(_mutex); - _sources.export_sources(_tester, _inserter); + auto already_known = [&] (Source::Id const unique_id) + { + for (Subject *s = _entries.first(); s; s = s->next()) + if (s->has_source_id(unique_id)) + return true; + return false; + }; + + auto filter_matches = [&] (Session_label const &label) + { + return strcmp(_filter.string(), label.string(), _filter.length() - 1) == 0; + }; + + _sources.for_each_source([&] (Source &source) { + + Source::Info const info = source.info(); + + if (!filter_matches(info.label) || already_known(source.id())) + return; + + Weak_ptr source_ptr = source.weak_ptr(); + + _entries.insert(new (_md_alloc) + Subject(Subject_id(++_id_cnt), source.id(), + source_ptr, info.label, info.name)); + }); } /** * Retrieve existing subject IDs */ - size_t subjects(Subject_id *dst, size_t dst_len) + unsigned subjects(Subject_id *dst, size_t dst_len) { Mutex::Guard guard(_mutex); @@ -456,40 +402,48 @@ class Genode::Trace::Subject_registry /** * Retrieve Subject_infos batched */ - size_t subjects(Subject_info * const dst, Subject_id * ids, size_t const len) + unsigned subjects(Subject_info * const dst, Subject_id * ids, size_t const len) { Mutex::Guard guard(_mutex); + auto filtered = [&] (Session_label const &label) -> Session_label + { + return (label.length() <= _filter.length() || !_filter.length()) + ? Session_label("") /* this cannot happen */ + : Session_label(label.string() + _filter.length() - 1); + }; + unsigned i = 0; for (Subject *s = _entries.first(); s && i < len; s = s->next()) { - ids[i] = s->id(); - dst[i++] = s->info(); - } + ids[i] = s->id(); + Subject_info const info = s->info(); + + /* strip filter prefix from reported trace-subject label */ + dst[i++] = { + filtered(info.session_label()), info.thread_name(), info.state(), + info.policy_id(), info.execution_time(), info.affinity() + }; + } return i; } /** * Remove subject and release resources - * - * \return RAM resources released as a side effect for removing the - * subject (i.e., if the subject held a trace buffer or - * policy dataspace). The value does not account for - * memory allocated from the metadata allocator. */ - size_t release(Subject_id subject_id) + void release(Subject_id subject_id) { Mutex::Guard guard(_mutex); - Subject &subject = _unsynchronized_lookup_by_id(subject_id); - return _unsynchronized_destroy(subject); + _with_subject_unsynchronized(subject_id, [&] (Subject &subject) { + _unsynchronized_destroy(subject); }); } - Subject &lookup_by_id(Subject_id id) + void with_subject(Subject_id id, auto const &fn) { Mutex::Guard guard(_mutex); - return _unsynchronized_lookup_by_id(id); + return _with_subject_unsynchronized(id, fn); } }; diff --git a/repos/base/src/core/include/types.h b/repos/base/src/core/include/types.h new file mode 100644 index 0000000000..465d60d0de --- /dev/null +++ b/repos/base/src/core/include/types.h @@ -0,0 +1,74 @@ +/* + * \brief Core namespace declaration and basic types + * \author Norman Feske + * \date 2023-03-01 + */ + +/* + * Copyright (C) 2023 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CORE__INCLUDE__TYPES_H_ +#define _CORE__INCLUDE__TYPES_H_ + +#include +#include +#include +#include + +namespace Core { + + using namespace Genode; + + struct Log2 { uint8_t log2; }; + + enum class Access { READ, WRITE, EXEC }; + + struct Addr + { + addr_t value; + + Addr reduced_by(addr_t offset) const + { + return { (value >= offset) ? (value - offset) : 0 }; + } + + Addr increased_by(addr_t offset) const + { + return { (value + offset >= offset) ? (value + offset) : 0 }; + } + + void print(Output &out) const { Genode::print(out, Hex(value)); } + }; + + struct Rwx + { + bool w, x; + + static constexpr bool r = true; + + static constexpr Rwx rwx() { return { true, true }; } + + void print(Output &out) const + { + Genode::print(out, "(r", w ? "w" : "-", x ? "x" : "-", ")"); + } + }; +} + +namespace Genode { + + static inline void print(Output &out, Core::Access access) + { + switch (access) { + case Core::Access::READ: print(out, "READ"); break; + case Core::Access::WRITE: print(out, "WRITE"); break; + case Core::Access::EXEC: print(out, "EXEC"); break; + } + } +} + +#endif /* _CORE__INCLUDE__TYPES_H_ */ diff --git a/repos/base/src/core/include/vm_root.h b/repos/base/src/core/include/vm_root.h index 46bf5c67bd..ac559725b4 100644 --- a/repos/base/src/core/include/vm_root.h +++ b/repos/base/src/core/include/vm_root.h @@ -21,9 +21,10 @@ /* core includes */ #include -namespace Genode { class Vm_root; } +namespace Core { class Vm_root; } -class Genode::Vm_root : public Root_component + +class Core::Vm_root : public Root_component { private: diff --git a/repos/base/src/core/io_mem_session_component.cc b/repos/base/src/core/io_mem_session_component.cc index 334d6e40e7..ab680b4f8c 100644 --- a/repos/base/src/core/io_mem_session_component.cc +++ b/repos/base/src/core/io_mem_session_component.cc @@ -11,15 +11,16 @@ * under the terms of the GNU Affero General Public License version 3. */ -#include +/* Genode includes */ #include #include + +/* core includes */ +#include #include #include -#include -#include "util.h" -using namespace Genode; +using namespace Core; Io_mem_session_component::Dataspace_attr @@ -47,8 +48,28 @@ Io_mem_session_component::_prepare_io_mem(const char *args, return Dataspace_attr(); } + /** + * _Unfortunate_ workaround for Intel PCH GPIO device. + * + * The ported i2c_hid driver contains driver code for the "Intel + * Tigerlake/Alderlake PCH pinctrl/GPIO" device. Unfortunately, acpica + * driver also accesses the same device on Lid open/close via ACPI AML code + * of the DSDT table to read out the state of a GPIO pin connected to the + * notebook lid. This would fail as I/O memory is handed out only once and + * cannot be shared. The workaround disables the region check for the + * specified GPIO I/O memory regions and provides both drivers shared + * access to the regions. + * + * This is a preliminary workaround. A general solution should separate the + * GPIO driver into a component (e.g., platform driver) that regulates + * accesses by i2c_hid and acpica. + */ + bool skip_iomem_check = (req_base == 0xfd6d0000ull && req_size == 4096) || + (req_base == 0xfd6a0000ull && req_size == 4096) || + (req_base == 0xfd6e0000ull && req_size == 4096); + /* allocate region */ - if (_io_mem_alloc.alloc_addr(req_size, req_base).failed()) { + if (!skip_iomem_check && _io_mem_alloc.alloc_addr(req_size, req_base).failed()) { error("I/O memory ", Hex_range(req_base, req_size), " not available"); return Dataspace_attr(); } @@ -82,11 +103,14 @@ Io_mem_session_component::Io_mem_session_component(Range_allocator &io_mem_alloc Io_mem_session_component::~Io_mem_session_component() { + /* remove all users of the to be destroyed io mem dataspace */ + _ds.detach_from_rm_sessions(); + /* dissolve IO_MEM dataspace from service entry point */ _ds_ep.dissolve(&_ds); /* flush local mapping of IO_MEM */ - _unmap_local(_ds.core_local_addr(), _ds.size()); + _unmap_local(_ds.core_local_addr(), _ds.size(), _ds.phys_addr()); /* * The Dataspace will remove itself from all RM sessions when its diff --git a/repos/base/src/core/main.cc b/repos/base/src/core/main.cc index 5455baac83..861a424847 100644 --- a/repos/base/src/core/main.cc +++ b/repos/base/src/core/main.cc @@ -5,18 +5,17 @@ */ /* - * Copyright (C) 2006-2017 Genode Labs GmbH + * Copyright (C) 2006-2023 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. */ /* Genode includes */ -#include #include #include #include -#include +#include #include #include #include @@ -30,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -40,14 +40,14 @@ #include #include -using namespace Genode; +using namespace Core; /*************************************** ** Core environment/platform support ** ***************************************/ -Core_env &Genode::core_env() +Core_env &Core::core_env() { /* * Make sure to initialize the platform before constructing the core @@ -75,21 +75,25 @@ Core_env &Genode::core_env() } -Env_deprecated *Genode::env_deprecated() { - return &core_env(); } - - -Platform &Genode::platform_specific() +Core::Platform &Core::platform_specific() { static Platform _platform; return _platform; } -Platform_generic &Genode::platform() { return platform_specific(); } +Platform_generic &Core::platform() { return platform_specific(); } -Thread_capability Genode::main_thread_cap() { return Thread_capability(); } +struct Genode::Platform { }; + + +Genode::Platform &Genode::init_platform() +{ + core_env(); + static Genode::Platform platform { }; + return platform; +} /** @@ -117,6 +121,8 @@ class Core_child : public Child_policy Cap_quota const _cap_quota; Ram_quota const _ram_quota; + Id_space _server_ids { }; + Child _child; public: @@ -179,6 +185,8 @@ class Core_child : public Child_policy Pd_session_capability ref_pd_cap() const override { return _core_pd_cap; } size_t session_alloc_batch_size() const override { return 128; } + + Id_space &server_id_space() override { return _server_ids; } }; @@ -187,25 +195,22 @@ class Core_child : public Child_policy ****************/ /* - * In contrast to the 'Platform_env' used by non-core components, core disables - * the signal thread but overriding 'Genode::init_signal_thread' with a dummy. - * Within core, the signal thread is not needed as core is never supposed to - * receive any signals. Otherwise, the signal thread would be the only - * non-entrypoint thread within core, which would be a problem on NOVA where - * the creation of regular threads within core is unsupported. + * In contrast to non-core components, core disables the signal thread by + * overriding 'Genode::init_signal_thread' with a dummy. Within core, the + * signal thread is not needed as core is never supposed to receive any + * signals. */ void Genode::init_signal_thread(Env &) { } -void Genode::destroy_signal_thread() { } /******************* ** Trace support ** *******************/ -Trace::Source_registry &Trace::sources() +Core::Trace::Source_registry &Core::Trace::sources() { - static Trace::Source_registry inst; + static Source_registry inst; return inst; } @@ -220,16 +225,16 @@ namespace Genode { } -int main() +void Genode::bootstrap_component(Genode::Platform &) { - /** - * Disable tracing within core because it is currently not fully implemented. - */ + init_exception_handling(*core_env().pd_session(), core_env().local_rm()); + + /* disable tracing within core because it is not fully implemented */ inhibit_tracing = true; log("Genode ", Genode::version_string); - static Trace::Policy_registry trace_policies; + static Core::Trace::Policy_registry trace_policies; static Rpc_entrypoint &ep = core_env().entrypoint(); static Ram_allocator &core_ram_alloc = core_env().ram_allocator(); @@ -252,21 +257,27 @@ int main() static Pager_entrypoint pager_ep(rpc_cap_factory); + using Trace_root = Core::Trace::Root; + using Trace_session_component = Core::Trace::Session_component; + + static Core::System_control &system_control = init_system_control(sliced_heap, ep); + static Rom_root rom_root (ep, ep, platform().rom_fs(), sliced_heap); static Rm_root rm_root (ep, sliced_heap, core_ram_alloc, local_rm, pager_ep); static Cpu_root cpu_root (core_ram_alloc, local_rm, ep, ep, pager_ep, - sliced_heap, Trace::sources()); + sliced_heap, Core::Trace::sources()); static Pd_root pd_root (ep, core_env().signal_ep(), pager_ep, platform().ram_alloc(), local_rm, sliced_heap, - platform_specific().core_mem_alloc()); + platform_specific().core_mem_alloc(), + system_control); static Log_root log_root (ep, sliced_heap); static Io_mem_root io_mem_root (ep, ep, platform().io_mem_alloc(), platform().ram_alloc(), sliced_heap); static Irq_root irq_root (*core_env().pd_session(), platform().irq_alloc(), sliced_heap); - static Trace::Root trace_root (core_ram_alloc, local_rm, ep, sliced_heap, - Trace::sources(), trace_policies); + static Trace_root trace_root (core_ram_alloc, local_rm, ep, sliced_heap, + Core::Trace::sources(), trace_policies); static Core_service rom_service (services, rom_root); static Core_service rm_service (services, rm_root); @@ -275,10 +286,10 @@ int main() static Core_service log_service (services, log_root); static Core_service io_mem_service (services, io_mem_root); static Core_service irq_service (services, irq_root); - static Core_service trace_service (services, trace_root); + static Core_service trace_service (services, trace_root); /* make platform-specific services known to service pool */ - platform_add_local_services(ep, sliced_heap, services, Trace::sources()); + platform_add_local_services(ep, sliced_heap, services, Core::Trace::sources()); size_t const avail_ram_quota = core_pd.avail_ram().value; size_t const avail_cap_quota = core_pd.avail_caps().value; @@ -288,12 +299,12 @@ int main() if (avail_ram_quota < preserved_ram_quota) { error("core preservation exceeds platform RAM limit"); - return -1; + return; } if (avail_cap_quota < preserved_cap_quota) { error("core preservation exceeds platform cap quota limit"); - return -1; + return; } Ram_quota const init_ram_quota { avail_ram_quota - preserved_ram_quota }; @@ -302,10 +313,10 @@ int main() /* CPU session representing core */ static Cpu_session_component core_cpu(ep, - Session::Resources{{Cpu_connection::RAM_QUOTA}, + Session::Resources{{Cpu_session::RAM_QUOTA}, {Cpu_session::CAP_QUOTA}}, "core", Session::Diag{false}, - core_ram_alloc, local_rm, ep, pager_ep, Trace::sources(), "", + core_ram_alloc, local_rm, ep, pager_ep, Core::Trace::sources(), "", Affinity::unrestricted(), Cpu_session::QUOTA_LIMIT); Cpu_session_capability core_cpu_cap = core_cpu.cap(); @@ -320,5 +331,4 @@ int main() platform().wait_for_exit(); init.destruct(); - return 0; } diff --git a/repos/base/src/core/pager_ep.cc b/repos/base/src/core/pager_ep.cc index aae61f8522..0555ab4213 100644 --- a/repos/base/src/core/pager_ep.cc +++ b/repos/base/src/core/pager_ep.cc @@ -12,10 +12,10 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* Core includes */ +/* core includes */ #include -using namespace Genode; +using namespace Core; void Pager_entrypoint::entry() @@ -39,11 +39,8 @@ void Pager_entrypoint::entry() obj->submit_exception_signal(); } else { /* send reply if page-fault handling succeeded */ - reply_pending = !obj->pager(_pager); - if (!reply_pending) - warning("page-fault, ", *obj, - " ip=", Hex(_pager.fault_ip()), - " pf-addr=", Hex(_pager.fault_addr())); + using Result = Pager_object::Pager_result; + reply_pending = (obj->pager(_pager) == Result::CONTINUE); } } else { diff --git a/repos/base/src/core/pager_object.cc b/repos/base/src/core/pager_object.cc index 4806347e35..d26dc758d2 100644 --- a/repos/base/src/core/pager_object.cc +++ b/repos/base/src/core/pager_object.cc @@ -11,13 +11,10 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* Genode includes */ -#include - /* core includes */ #include -using namespace Genode; +using namespace Core; void Pager_object::wake_up() diff --git a/repos/base/src/core/pd_session_component.cc b/repos/base/src/core/pd_session_component.cc index acc607aed4..ad9a88649a 100644 --- a/repos/base/src/core/pd_session_component.cc +++ b/repos/base/src/core/pd_session_component.cc @@ -11,13 +11,11 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* Genode includes */ -#include - /* core includes */ #include +#include -using namespace Genode; +using namespace Core; Ram_allocator::Alloc_result @@ -102,78 +100,88 @@ size_t Pd_session_component::dataspace_size(Ram_dataspace_capability ds_cap) con } -void Pd_session_component::ref_account(Capability pd_cap) +Pd_session::Ref_account_result Pd_session_component::ref_account(Capability pd_cap) { /* the reference account can be defined only once */ if (_cap_account.constructed()) - return; + return Ref_account_result::OK; if (this->cap() == pd_cap) - return; + return Ref_account_result::OK; + + Ref_account_result result = Ref_account_result::INVALID_SESSION; _ep.apply(pd_cap, [&] (Pd_session_component *pd) { - if (!pd || !pd->_ram_account.constructed()) { - error("invalid PD session specified as ref account"); - throw Invalid_session(); - } + if (!pd || !pd->_ram_account.constructed()) + return; _cap_account.construct(_cap_quota_guard(), _label, *pd->_cap_account); _ram_account.construct(_ram_quota_guard(), _label, *pd->_ram_account); + + result = Ref_account_result::OK; }); + return result; } -void Pd_session_component::transfer_quota(Capability pd_cap, - Cap_quota amount) +Pd_session::Transfer_cap_quota_result +Pd_session_component::transfer_quota(Capability pd_cap, Cap_quota amount) { if (!_cap_account.constructed()) - throw Undefined_ref_account(); + return Transfer_cap_quota_result::NO_REF_ACCOUNT; if (this->cap() == pd_cap) - return; + return Transfer_cap_quota_result::OK; + + Transfer_cap_quota_result result = Transfer_cap_quota_result::INVALID_SESSION; _ep.apply(pd_cap, [&] (Pd_session_component *pd) { if (!pd || !pd->_cap_account.constructed()) - throw Invalid_session(); + return; try { _cap_account->transfer_quota(*pd->_cap_account, amount); diag("transferred ", amount, " caps " "to '", pd->_cap_account->label(), "' (", _cap_account, ")"); + result = Transfer_cap_quota_result::OK; } - catch (Account::Unrelated_account) { - warning("attempt to transfer cap quota to unrelated PD session"); - throw Invalid_session(); } + catch (Account::Unrelated_account) { } catch (Account::Limit_exceeded) { - throw Out_of_caps(); } + result = Transfer_cap_quota_result::OUT_OF_CAPS; + } }); + return result; } -void Pd_session_component::transfer_quota(Capability pd_cap, - Ram_quota amount) +Pd_session::Transfer_ram_quota_result +Pd_session_component::transfer_quota(Capability pd_cap, Ram_quota amount) { if (!_ram_account.constructed()) - throw Undefined_ref_account(); + return Transfer_ram_quota_result::NO_REF_ACCOUNT; if (this->cap() == pd_cap) - return; + return Transfer_ram_quota_result::OK; + + Transfer_ram_quota_result result = Transfer_ram_quota_result::INVALID_SESSION; _ep.apply(pd_cap, [&] (Pd_session_component *pd) { if (!pd || !pd->_ram_account.constructed()) - throw Invalid_session(); + return; try { - _ram_account->transfer_quota(*pd->_ram_account, amount); } - catch (Account::Unrelated_account) { - warning("attempt to transfer RAM quota to unrelated PD session"); - throw Invalid_session(); } + _ram_account->transfer_quota(*pd->_ram_account, amount); + result = Transfer_ram_quota_result::OK; + } + catch (Account::Unrelated_account) { } catch (Account::Limit_exceeded) { - throw Out_of_ram(); } + result = Transfer_ram_quota_result::OUT_OF_RAM; + } }); + return result; } @@ -200,3 +208,15 @@ Pd_session_component::attach_dma(Dataspace_capability ds_cap, addr_t at) return _address_space.attach_dma(ds_cap, at); } + + +Pd_session_component::~Pd_session_component() +{ + /* + * As `Platform_thread` objects point to their corresponding `Platform_pd` + * objects, we need to destroy the threads when the `Platform_pd` ceases to + * exist. + */ + _threads.for_each([&] (Cpu_thread_component &thread) { + thread.destroy(); }); +} diff --git a/repos/base/src/core/pd_session_support.cc b/repos/base/src/core/pd_session_support.cc index e314181595..561566c060 100644 --- a/repos/base/src/core/pd_session_support.cc +++ b/repos/base/src/core/pd_session_support.cc @@ -13,15 +13,34 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* core-local includes */ +/* core includes */ #include -using namespace Genode; +using namespace Core; + bool Pd_session_component::assign_pci(addr_t, uint16_t) { return true; } -void Pd_session_component::map(addr_t, addr_t) { } -using State = Genode::Pd_session::Managing_system_state; +Pd_session::Map_result Pd_session_component::map(Pd_session::Virt_range) +{ + return Map_result::OK; +} -State Pd_session_component::managing_system(State const &) { return State(); } + +class System_control_dummy : public System_control +{ + public: + + Capability control_cap(Affinity::Location) const override + { + return { }; + } +}; + + +System_control & Core::init_system_control(Allocator &, Rpc_entrypoint &) +{ + static System_control_dummy dummy { }; + return dummy; +} diff --git a/repos/base/src/core/platform_rom_modules.cc b/repos/base/src/core/platform_rom_modules.cc index a885038b3e..1bed8a0363 100644 --- a/repos/base/src/core/platform_rom_modules.cc +++ b/repos/base/src/core/platform_rom_modules.cc @@ -15,23 +15,23 @@ #include #include -using namespace Genode; +using namespace Core; void Platform::_init_rom_modules() { - /* add boot modules to ROM FS */ - Boot_modules_header *header = &_boot_modules_headers_begin; - for (; header < &_boot_modules_headers_end; header++) { + Boot_modules_header const *header_ptr = &_boot_modules_headers_begin; - if (!header->size) { - warning("ignore zero-sized boot module '", - Cstring((char const *)header->name), "'"); + for (; header_ptr < &_boot_modules_headers_end; header_ptr++) { + + Rom_name const name((char const *)header_ptr->name); + + if (!header_ptr->size) { + warning("ignore zero-sized boot module '", name, "'"); continue; } - Rom_module &rom_module = *new (core_mem_alloc()) - Rom_module(_rom_module_phys(header->base), header->size, - (char const *)header->name); - _rom_fs.insert(&rom_module); + new (core_mem_alloc()) + Rom_module(_rom_fs, name, + _rom_module_phys(header_ptr->base), header_ptr->size); } } diff --git a/repos/base/src/core/platform_services.cc b/repos/base/src/core/platform_services.cc index a2cefe0c68..f925e1bcb2 100644 --- a/repos/base/src/core/platform_services.cc +++ b/repos/base/src/core/platform_services.cc @@ -15,6 +15,6 @@ #include -void Genode::platform_add_local_services(Rpc_entrypoint &, Sliced_heap &, - Registry &, - Trace::Source_registry &) { } +void Core::platform_add_local_services(Rpc_entrypoint &, Sliced_heap &, + Registry &, + Trace::Source_registry &) { } diff --git a/repos/base/src/core/ram_dataspace_factory.cc b/repos/base/src/core/ram_dataspace_factory.cc index 04911289a0..8c37503834 100644 --- a/repos/base/src/core/ram_dataspace_factory.cc +++ b/repos/base/src/core/ram_dataspace_factory.cc @@ -11,13 +11,10 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* Genode includes */ -#include - /* core includes */ #include -using namespace Genode; +using namespace Core; Ram_allocator::Alloc_result @@ -40,16 +37,24 @@ Ram_dataspace_factory::try_alloc(size_t ds_size, Cache cache) */ Range_allocator::Alloc_result allocated_range = Allocator::Alloc_error::DENIED; - /* - * If no physical constraint exists, try to allocate physical memory at - * high locations (3G for 32-bit / 4G for 64-bit platforms) in order to - * preserve lower physical regions for device drivers, which may have DMA - * constraints. - */ - if (_phys_range.start == 0 && _phys_range.end == ~0UL) { + /* apply constraints */ + if (_phys_range.start != 0 || _phys_range.end != ~0UL) { + for (size_t align_log2 = log2(ds_size); align_log2 >= 12; align_log2--) { + allocated_range = _phys_alloc.alloc_aligned(ds_size, (unsigned)align_log2, _phys_range); + if (allocated_range.ok()) + break; + } + } + /* + * If no physical constraint exists or constraints failed, try to allocate + * physical memory at high locations (3G for 32-bit / 4G for 64-bit platforms) + * in order to preserve lower physical regions for device drivers, which may + * have DMA constraints. + */ + if (!allocated_range.ok()) { addr_t const high_start = (sizeof(void *) == 4 ? 3UL : 4UL) << 30; - Phys_range const range { .start = high_start, .end = _phys_range.end }; + Phys_range const range { .start = high_start, .end = ~0UL }; for (size_t align_log2 = log2(ds_size); align_log2 >= 12; align_log2--) { allocated_range = _phys_alloc.alloc_aligned(ds_size, (unsigned)align_log2, range); @@ -58,7 +63,7 @@ Ram_dataspace_factory::try_alloc(size_t ds_size, Cache cache) } } - /* apply constraints, or retry if larger memory allocation failed */ + /* retry if larger non-constrained memory allocation failed */ if (!allocated_range.ok()) { for (size_t align_log2 = log2(ds_size); align_log2 >= 12; align_log2--) { allocated_range = _phys_alloc.alloc_aligned(ds_size, (unsigned)align_log2, _phys_range); diff --git a/repos/base/src/core/region_map_component.cc b/repos/base/src/core/region_map_component.cc index af2bf50681..830b87527f 100644 --- a/repos/base/src/core/region_map_component.cc +++ b/repos/base/src/core/region_map_component.cc @@ -14,7 +14,6 @@ */ /* Genode includes */ -#include #include #include @@ -24,240 +23,93 @@ #include #include -static const bool verbose_page_faults = false; +using namespace Core; -struct Genode::Region_map_component::Fault_area -{ - addr_t _fault_addr = 0; - addr_t _base = 0; - size_t _size_log2 = 0; - - addr_t _upper_bound() const { - return (_size_log2 == ~0UL) ? ~0UL : (_base + (1UL << _size_log2) - 1); } - - /** - * Default constructor, constructs invalid fault area - */ - Fault_area() { } - - /** - * Constructor, fault area spans the maximum address-space size - */ - Fault_area(addr_t fault_addr) : - _fault_addr(fault_addr), _size_log2(~0UL) { } - - /** - * Constrain fault area to specified region - */ - void constrain(addr_t region_base, size_t region_size) - { - /* - * Find flexpage around _fault_addr that lies within the - * specified region. - * - * Start with a 'size_log2' of one less than the minimal - * page size. If the specified constraint conflicts with - * the existing fault area, the loop breaks at the first - * iteration and we can check for this condition after the - * loop. - */ - size_t size_log2 = get_page_size_log2() - 1; - addr_t base = 0; - for (size_t try_size_log2 = get_page_size_log2(); - try_size_log2 < sizeof(addr_t)*8 ; try_size_log2++) { - addr_t fpage_mask = ~((1UL << try_size_log2) - 1); - addr_t try_base = _fault_addr & fpage_mask; - - /* check lower bound of existing fault area */ - if (try_base < _base) - break; - - /* check against upper bound of existing fault area */ - if (try_base + (1UL << try_size_log2) - 1 > _upper_bound()) - break; - - /* check against lower bound of region */ - if (try_base < region_base) - break; - - /* check against upper bound of region */ - if (try_base + (1UL << try_size_log2) - 1 > region_base + region_size - 1) - break; - - /* flexpage is compatible with fault area, use it */ - size_log2 = try_size_log2; - base = try_base; - } - - /* if constraint is compatible with the fault area, invalidate */ - if (size_log2 < get_page_size_log2()) { - _size_log2 = 0; - _base = 0; - } else { - _size_log2 = size_log2; - _base = base; - } - } - - /** - * Constrain fault area to specified flexpage size - */ - void constrain(size_t size_log2) - { - if (size_log2 >= _size_log2) - return; - - _base = _fault_addr & ~((1UL << size_log2) - 1); - _size_log2 = size_log2; - } - - /** - * Determine common flexpage size compatible with specified fault areas - */ - static size_t common_size_log2(Fault_area const &a1, Fault_area const &a2) - { - /* - * We have to make sure that the offset of page-fault address - * relative to the flexpage base is the same for both fault areas. - * This condition is met by the flexpage size equal to the number - * of common least-significant bits of both offsets. - */ - size_t const diff = (a1.fault_addr() - a1.base()) - ^ (a2.fault_addr() - a2.base()); - - /* - * Find highest clear bit in 'diff', starting from the least - * significant candidate. We can skip all bits lower then - * 'get_page_size_log2()' because they are not relevant as - * flexpage size (and are always zero). - */ - size_t n = get_page_size_log2(); - size_t const min_size_log2 = min(a1._size_log2, a2._size_log2); - for (; n < min_size_log2 && !(diff & (1UL << n)); n++); - - return n; - } - - addr_t fault_addr() const { return _fault_addr; } - addr_t base() const { return _base; } - bool valid() const { return _size_log2 > 0; } -}; - - -using namespace Genode; - -static void print_page_fault(char const *msg, - addr_t pf_addr, - addr_t pf_ip, - Region_map::State::Fault_type pf_type, - Pager_object const &obj) -{ - log(msg, " (", - pf_type == Region_map::State::WRITE_FAULT ? "WRITE" : - pf_type == Region_map::State::READ_FAULT ? "READ" : "EXEC", - " pf_addr=", Hex(pf_addr), " pf_ip=", Hex(pf_ip), " from ", obj, ") "); -} - - -/*********************** - ** Region-map client ** - ***********************/ - /* * This code is executed by the page-fault handler thread. */ -int Rm_client::pager(Ipc_pager &pager) +Pager_object::Pager_result Rm_client::pager(Ipc_pager &pager) { - Region_map::State::Fault_type pf_type = pager.write_fault() ? Region_map::State::WRITE_FAULT - : Region_map::State::READ_FAULT; - if (pager.exec_fault()) - pf_type = Region_map::State::EXEC_FAULT; - - addr_t pf_addr = pager.fault_addr(); - addr_t pf_ip = pager.fault_ip(); - - if (verbose_page_faults) - print_page_fault("page fault", pf_addr, pf_ip, pf_type, *this); - - auto lambda = [&] (Region_map_component *region_map, - Rm_region *region, - addr_t const ds_offset, - addr_t const region_offset, - addr_t const dst_region_size) -> int - { - Dataspace_component * dsc = region ? ®ion->dataspace() : nullptr; - if (!dsc) { - - /* - * We found no attachment at the page-fault address and therefore have - * to reflect the page fault as region-manager fault. The signal - * handler is then expected to request the state of the region map. - */ - - /* print a warning if it's no managed-dataspace */ - if (region_map == &member_rm()) - print_page_fault("no RM attachment", pf_addr, pf_ip, - pf_type, *this); - - /* register fault at responsible region map */ - if (region_map) - region_map->fault(*this, pf_addr - region_offset, pf_type); - - /* there is no attachment return an error condition */ - return 1; - } - - /* - * Check if dataspace is compatible with page-fault type - */ - if (pf_type == Region_map::State::WRITE_FAULT && - (!region->write() || !dsc->writeable())) { - - print_page_fault("attempted write at read-only memory", - pf_addr, pf_ip, pf_type, *this); - - /* register fault at responsible region map */ - if (region_map) - region_map->fault(*this, pf_addr - region_offset, pf_type); - return 2; - } - - if (pf_type == Region_map::State::EXEC_FAULT) { - - print_page_fault("attempted exec at non-executable memory", - pf_addr, pf_ip, pf_type, *this); - - /* register fault at responsible region map */ - if (region_map) - region_map->fault(*this, pf_addr - region_offset, pf_type); - return 3; - } - - Mapping mapping = Region_map_component::create_map_item(region_map, - *region, - ds_offset, - region_offset, - *dsc, pf_addr, - dst_region_size); - - /* - * On kernels with a mapping database, the 'dsc' dataspace is a leaf - * dataspace that corresponds to a virtual address range within core. To - * prepare the answer for the page fault, we make sure that this range is - * locally mapped in core. On platforms that support map operations of - * pages that are not locally mapped, the 'map_core_local' function may be - * empty. - */ - if (!dsc->io_mem()) - mapping.prepare_map_operation(); - - /* answer page fault with a flex-page mapping */ - pager.set_reply_mapping(mapping); - return 0; + Fault const fault { + .hotspot = { pager.fault_addr() }, + .access = pager.write_fault() ? Access::WRITE + : pager.exec_fault() ? Access::EXEC + : Access::READ, + .rwx = Rwx::rwx(), + .bounds = { .start = 0, .end = ~0UL }, }; - return member_rm().apply_to_dataspace(pf_addr, lambda); + + using Result = Region_map_component::With_mapping_result; + + Result const result = member_rm().with_mapping_for_fault(fault, + + [&] (Mapping const &mapping) + { + /* + * On kernels with a mapping database, the leaf dataspace + * corresponds to a virtual address range within core. To prepare + * the answer for the page fault, we make sure that this range is + * locally mapped in core. + */ + if (!mapping.io_mem) + mapping.prepare_map_operation(); + + /* answer page fault with a flex-page mapping */ + pager.set_reply_mapping(mapping); + }, + + [&] (Region_map_component &rm, Fault const &fault) /* reflect to user space */ + { + using Type = Region_map::Fault::Type; + Type const type = (fault.access == Access::READ) ? Type::READ + : (fault.access == Access::WRITE) ? Type::WRITE + : Type::EXEC; + /* deliver fault info to responsible region map */ + rm.fault(*this, { .type = type, .addr = fault.hotspot.value }); + } + ); + + if (result == Result::RESOLVED) + return Pager_result::CONTINUE; + + /* + * Error diagnostics + */ + + struct Origin + { + addr_t ip; + Pager_object &obj; + + void print(Output &out) const + { + Genode::print(out, "by ", obj, " ip=", Hex(ip)); + } + } origin { pager.fault_ip(), *this }; + + switch (result) { + case Result::RESOLVED: + case Result::REFLECTED: + break; + + case Result::RECURSION_LIMIT: + error("giving up on unexpectedly deep memory-mapping structure"); + error(fault, " ", origin); + break; + + case Result::NO_REGION: + error("illegal ", fault, " ", origin); + break; + + case Result::WRITE_VIOLATION: + case Result::EXEC_VIOLATION: + error(fault.access, " violation at address ", + fault.hotspot, " ", origin); + break; + } + return Pager_result::STOP; } @@ -266,12 +118,12 @@ int Rm_client::pager(Ipc_pager &pager) *************/ void Rm_faulter::fault(Region_map_component &faulting_region_map, - Region_map::State fault_state) + Region_map::Fault fault) { Mutex::Guard lock_guard(_mutex); _faulting_region_map = faulting_region_map.weak_ptr(); - _fault_state = fault_state; + _fault = fault; _pager_object.unresolved_page_fault_occurred(); } @@ -292,7 +144,7 @@ void Rm_faulter::dissolve_from_faulting_region_map(Region_map_component &caller) locked_ptr->discard_faulter(*this, DO_LOCK); } - _faulting_region_map = Genode::Weak_ptr(); + _faulting_region_map = Weak_ptr(); } @@ -301,8 +153,8 @@ void Rm_faulter::continue_after_resolved_fault() Mutex::Guard lock_guard(_mutex); _pager_object.wake_up(); - _faulting_region_map = Genode::Weak_ptr(); - _fault_state = Region_map::State(); + _faulting_region_map = Weak_ptr(); + _fault = { }; } @@ -310,96 +162,54 @@ void Rm_faulter::continue_after_resolved_fault() ** Region-map component ** **************************/ -Mapping Region_map_component::create_map_item(Region_map_component *, - Rm_region ®ion, - addr_t const ds_offset, - addr_t const region_offset, - Dataspace_component &dataspace, - addr_t const page_addr, - addr_t const dst_region_size) +Region_map::Attach_result +Region_map_component::_attach(Dataspace_capability ds_cap, Attach_attr const core_attr) { - addr_t const ds_base = dataspace.map_src_addr(); + Attr const attr = core_attr.attr; - Fault_area src_fault_area(ds_base + ds_offset); - Fault_area dst_fault_area(page_addr); - - src_fault_area.constrain(ds_base, dataspace.size()); - dst_fault_area.constrain(region_offset + region.base(), dst_region_size); - - /* - * Determine mapping size compatible with source and destination, - * and apply platform-specific constraint of mapping sizes. - */ - size_t map_size_log2 = dst_fault_area.common_size_log2(dst_fault_area, - src_fault_area); - map_size_log2 = constrain_map_size_log2(map_size_log2); - - src_fault_area.constrain(map_size_log2); - dst_fault_area.constrain(map_size_log2); - if (!src_fault_area.valid() || !dst_fault_area.valid()) - error("invalid mapping"); - - return Mapping { .dst_addr = dst_fault_area.base(), - .src_addr = src_fault_area.base(), - .size_log2 = map_size_log2, - .cached = dataspace.cacheability() == CACHED, - .io_mem = dataspace.io_mem(), - .dma_buffer = region.dma(), - .write_combined = dataspace.cacheability() == WRITE_COMBINED, - .writeable = region.write() && dataspace.writeable(), - .executable = region.executable() }; -} - - -Region_map::Local_addr -Region_map_component::_attach(Dataspace_capability ds_cap, Attach_attr const attr) -{ /* serialize access */ Mutex::Guard lock_guard(_mutex); - /* offset must be positive and page-aligned */ - if (attr.offset < 0 || align_addr(attr.offset, get_page_size_log2()) != attr.offset) - throw Region_conflict(); + /* offset must be page-aligned */ + if (align_addr(attr.offset, get_page_size_log2()) != attr.offset) + return Attach_error::REGION_CONFLICT; - auto lambda = [&] (Dataspace_component *dsc) { + auto lambda = [&] (Dataspace_component *dsc) -> Attach_result { using Alloc_error = Range_allocator::Alloc_error; /* check dataspace validity */ if (!dsc) - throw Invalid_dataspace(); + return Attach_error::INVALID_DATASPACE; unsigned const min_align_log2 = get_page_size_log2(); - size_t const off = attr.offset; - if (off >= dsc->size()) - throw Region_conflict(); + size_t const ds_size = dsc->size(); - size_t size = attr.size; + if (attr.offset >= ds_size) + return Attach_error::REGION_CONFLICT; - if (!size) - size = dsc->size() - attr.offset; + size_t size = attr.size ? attr.size : ds_size - attr.offset; /* work with page granularity */ size = align_addr(size, min_align_log2); /* deny creation of regions larger then the actual dataspace */ - if (dsc->size() < size + attr.offset) - throw Region_conflict(); + if (ds_size < size + attr.offset) + return Attach_error::REGION_CONFLICT; /* allocate region for attachment */ - void *attach_at = nullptr; - if (attr.use_local_addr) { - _map.alloc_addr(size, attr.local_addr).with_result( - [&] (void *ptr) { attach_at = ptr; }, - [&] (Range_allocator::Alloc_error error) { - switch (error) { - case Alloc_error::OUT_OF_RAM: throw Out_of_ram(); - case Alloc_error::OUT_OF_CAPS: throw Out_of_caps(); - case Alloc_error::DENIED: break; - } - throw Region_conflict(); - }); + bool at_defined = false; + addr_t at { }; + if (attr.use_at) { + Alloc_error error = Alloc_error::DENIED; + _map.alloc_addr(size, attr.at).with_result( + [&] (void *ptr) { at = addr_t(ptr); at_defined = true; }, + [&] (Alloc_error e) { error = e; }); + + if (error == Alloc_error::OUT_OF_RAM) return Attach_error::OUT_OF_RAM; + if (error == Alloc_error::OUT_OF_CAPS) return Attach_error::OUT_OF_CAPS; + } else { /* @@ -411,8 +221,7 @@ Region_map_component::_attach(Dataspace_capability ds_cap, Attach_attr const att if (align_log2 >= sizeof(void *)*8) align_log2 = min_align_log2; - bool done = false; - for (; !done && (align_log2 >= min_align_log2); align_log2--) { + for (; !at_defined && (align_log2 >= min_align_log2); align_log2--) { /* * Don't use an alignment higher than the alignment of the backing @@ -422,60 +231,52 @@ Region_map_component::_attach(Dataspace_capability ds_cap, Attach_attr const att if (((dsc->map_src_addr() + attr.offset) & ((1UL << align_log2) - 1)) != 0) continue; - /* try allocating the align region */ - _map.alloc_aligned(size, (unsigned)align_log2).with_result( + /* try allocating the aligned region */ + Alloc_error error = Alloc_error::DENIED; + _map.alloc_aligned(size, unsigned(align_log2)).with_result( + [&] (void *ptr) { at = addr_t(ptr); at_defined = true; }, + [&] (Alloc_error e) { error = e; }); - [&] (void *ptr) { - attach_at = ptr; - done = true; }, - - [&] (Range_allocator::Alloc_error error) { - switch (error) { - case Alloc_error::OUT_OF_RAM: throw Out_of_ram(); - case Alloc_error::OUT_OF_CAPS: throw Out_of_caps(); - case Alloc_error::DENIED: break; /* no fit */ - } - /* try smaller alignment in next iteration... */ - }); + if (error == Alloc_error::OUT_OF_RAM) return Attach_error::OUT_OF_RAM; + if (error == Alloc_error::OUT_OF_CAPS) return Attach_error::OUT_OF_CAPS; } - - if (!done) - throw Region_conflict(); } + if (!at_defined) + return Attach_error::REGION_CONFLICT; Rm_region::Attr const region_attr { - .base = (addr_t)attach_at, + .base = at, .size = size, .write = attr.writeable, .exec = attr.executable, .off = attr.offset, - .dma = attr.dma, + .dma = core_attr.dma, }; /* store attachment info in meta data */ try { - _map.construct_metadata(attach_at, *dsc, *this, region_attr); + _map.construct_metadata((void *)at, *dsc, *this, region_attr); } catch (Allocator_avl_tpl::Assign_metadata_failed) { error("failed to store attachment info"); - throw Invalid_dataspace(); + return Attach_error::INVALID_DATASPACE; } /* inform dataspace about attachment */ - Rm_region * const region_ptr = _map.metadata(attach_at); + Rm_region * const region_ptr = _map.metadata((void *)at); if (region_ptr) dsc->attached_to(*region_ptr); /* check if attach operation resolves any faulting region-manager clients */ _faulters.for_each([&] (Rm_faulter &faulter) { - if (faulter.fault_in_addr_range((addr_t)attach_at, size)) { + if (faulter.fault_in_addr_range(at, size)) { _faulters.remove(faulter); faulter.continue_after_resolved_fault(); } }); - return attach_at; + return Range { .start = at, .num_bytes = size }; }; return _ds_ep.apply(ds_cap, lambda); @@ -484,26 +285,33 @@ Region_map_component::_attach(Dataspace_capability ds_cap, Attach_attr const att addr_t Region_map_component::_core_local_addr(Rm_region & region) { - /** - * If this region references a managed dataspace, - * we have to recursively request the core-local address - */ - if (region.dataspace().sub_rm().valid()) { - auto lambda = [&] (Region_map_component * rmc) -> addr_t - { - /** - * It is possible that there is no dataspace attached - * inside the managed dataspace, in that case return zero. - */ - Rm_region * r = rmc ? rmc->_map.metadata((void*)region.offset()) - : nullptr;; - return r ? rmc->_core_local_addr(*r) : 0; - }; - return _session_ep.apply(region.dataspace().sub_rm(), lambda); - } + addr_t result = 0; - /* return core-local address of dataspace + region offset */ - return region.dataspace().core_local_addr() + region.offset(); + region.with_dataspace([&] (Dataspace_component &dataspace) { + /** + * If this region references a managed dataspace, + * we have to recursively request the core-local address + */ + if (dataspace.sub_rm().valid()) { + auto lambda = [&] (Region_map_component * rmc) -> addr_t + { + /** + * It is possible that there is no dataspace attached + * inside the managed dataspace, in that case return zero. + */ + Rm_region * r = rmc ? rmc->_map.metadata((void*)region.offset()) + : nullptr;; + return (r && !r->reserved()) ? rmc->_core_local_addr(*r) : 0; + }; + result = _session_ep.apply(dataspace.sub_rm(), lambda); + return; + } + + /* return core-local address of dataspace + region offset */ + result = dataspace.core_local_addr() + region.offset(); + }); + + return result; } @@ -533,23 +341,10 @@ void Region_map_component::unmap_region(addr_t base, size_t size) } -Region_map::Local_addr -Region_map_component::attach(Dataspace_capability ds_cap, size_t size, - off_t offset, bool use_local_addr, - Region_map::Local_addr local_addr, - bool executable, bool writeable) +Region_map::Attach_result +Region_map_component::attach(Dataspace_capability ds_cap, Attr const &attr) { - Attach_attr const attr { - .size = size, - .offset = offset, - .use_local_addr = use_local_addr, - .local_addr = local_addr, - .executable = executable, - .writeable = writeable, - .dma = false, - }; - - return _attach(ds_cap, attr); + return _attach(ds_cap, { .attr = attr, .dma = false }); } @@ -557,63 +352,39 @@ Region_map_component::Attach_dma_result Region_map_component::attach_dma(Dataspace_capability ds_cap, addr_t at) { Attach_attr const attr { - .size = 0, - .offset = 0, - .use_local_addr = true, - .local_addr = at, - .executable = false, - .writeable = true, + .attr = { + .size = { }, + .offset = { }, + .use_at = true, + .at = at, + .executable = false, + .writeable = true, + }, .dma = true, }; using Attach_dma_error = Pd_session::Attach_dma_error; - try { - _attach(ds_cap, attr); - return Pd_session::Attach_dma_ok(); - } - catch (Invalid_dataspace) { return Attach_dma_error::DENIED; } - catch (Region_conflict) { return Attach_dma_error::DENIED; } - catch (Out_of_ram) { return Attach_dma_error::OUT_OF_RAM; } - catch (Out_of_caps) { return Attach_dma_error::OUT_OF_CAPS; } + return _attach(ds_cap, attr).convert( + [&] (Range) { return Pd_session::Attach_dma_ok(); }, + [&] (Attach_error e) { + switch (e) { + case Attach_error::OUT_OF_RAM: return Attach_dma_error::OUT_OF_RAM; + case Attach_error::OUT_OF_CAPS: return Attach_dma_error::OUT_OF_CAPS; + case Attach_error::REGION_CONFLICT: break; + case Attach_error::INVALID_DATASPACE: break; + } + return Attach_dma_error::DENIED; + }); } -void Region_map_component::detach(Local_addr local_addr) +void Region_map_component::_reserve_and_flush_unsynchronized(Rm_region ®ion) { - /* serialize access */ - Mutex::Guard lock_guard(_mutex); - - /* read meta data for address */ - Rm_region *region_ptr = _map.metadata(local_addr); - - if (!region_ptr) { - if (_diag.enabled) - warning("detach: no attachment at ", (void *)local_addr); - return; - } - - if ((region_ptr->base() != static_cast(local_addr)) && _diag.enabled) - warning("detach: ", static_cast(local_addr), " is not " - "the beginning of the region ", Hex(region_ptr->base())); - - Dataspace_component &dsc = region_ptr->dataspace(); - /* inform dataspace about detachment */ - dsc.detached_from(*region_ptr); - - /* - * Create local copy of region data because the '_map.metadata' of the - * region will become unavailable as soon as we call '_map.free' below. - */ - Rm_region region = *region_ptr; - - /* - * We unregister the region from region map prior unmapping the pages to - * make sure that page faults occurring immediately after the unmap - * refer to an empty region not to the dataspace, which we just removed. - */ - _map.free(reinterpret_cast(region.base())); + region.with_dataspace([&] (Dataspace_component &dsc) { + dsc.detached_from(region); + }); if (!platform().supports_direct_unmap()) { @@ -627,10 +398,27 @@ void Region_map_component::detach(Local_addr local_addr) * of core memory (reference issue #3082) */ Address_space::Core_local_addr core_local { _core_local_addr(region) }; + + /* + * We mark the region as reserved prior unmapping the pages to + * make sure that page faults occurring immediately after the unmap + * do not refer to the dataspace, which we just removed. Since + * 'mark_as_reserved()' invalidates the dataspace pointer, it + * must be called after '_core_local_addr()'. + */ + region.mark_as_reserved(); + if (core_local.value) platform_specific().core_pd().flush(0, region.size(), core_local); } else { + /* + * We mark the region as reserved prior unmapping the pages to + * make sure that page faults occurring immediately after the unmap + * do not refer to the dataspace, which we just removed. + */ + region.mark_as_reserved(); + /* * Unmap this memory region from all region maps referencing it. */ @@ -639,6 +427,34 @@ void Region_map_component::detach(Local_addr local_addr) } +/* + * Flush the region, but keep it reserved until 'detach()' is called. + */ +void Region_map_component::reserve_and_flush(addr_t const at) +{ + /* serialize access */ + Mutex::Guard lock_guard(_mutex); + + _with_region(at, [&] (Rm_region ®ion) { + _reserve_and_flush_unsynchronized(region); + }); +} + + +void Region_map_component::detach_at(addr_t const at) +{ + /* serialize access */ + Mutex::Guard lock_guard(_mutex); + + _with_region(at, [&] (Rm_region ®ion) { + if (!region.reserved()) + _reserve_and_flush_unsynchronized(region); + /* free the reserved region */ + _map.free(reinterpret_cast(region.base())); + }); +} + + void Region_map_component::add_client(Rm_client &rm_client) { Mutex::Guard lock_guard(_mutex); @@ -656,17 +472,16 @@ void Region_map_component::remove_client(Rm_client &rm_client) } -void Region_map_component::fault(Rm_faulter &faulter, addr_t pf_addr, - Region_map::State::Fault_type pf_type) +void Region_map_component::fault(Rm_faulter &faulter, Region_map::Fault fault) { /* remember fault state in faulting thread */ - faulter.fault(*this, Region_map::State(pf_type, pf_addr)); + faulter.fault(*this, fault); /* enqueue faulter */ _faulters.enqueue(faulter); /* issue fault signal */ - _fault_notifier.submit(); + Signal_transmitter(_fault_sigh).submit(); } @@ -680,23 +495,21 @@ void Region_map_component::discard_faulter(Rm_faulter &faulter, bool do_lock) } -void Region_map_component::fault_handler(Signal_context_capability handler) +void Region_map_component::fault_handler(Signal_context_capability sigh) { - _fault_notifier.context(handler); + _fault_sigh = sigh; } -Region_map::State Region_map_component::state() +Region_map::Fault Region_map_component::fault() { /* serialize access */ Mutex::Guard lock_guard(_mutex); - /* return ready state if there are not current faulters */ - Region_map::State result; - - /* otherwise return fault information regarding the first faulter */ + /* return fault information regarding the first faulter */ + Region_map::Fault result { }; _faulters.head([&] (Rm_faulter &faulter) { - result = faulter.fault_state(); }); + result = faulter.fault(); }); return result; } @@ -775,7 +588,7 @@ Region_map_component::~Region_map_component() break; } - detach(out_addr); + detach_at(out_addr); } /* revoke dataspace representation */ diff --git a/repos/base/src/core/rom_session_component.cc b/repos/base/src/core/rom_session_component.cc index 5dc789588e..8e11f32302 100644 --- a/repos/base/src/core/rom_session_component.cc +++ b/repos/base/src/core/rom_session_component.cc @@ -11,11 +11,14 @@ * under the terms of the GNU Affero General Public License version 3. */ +/* Genode includes */ #include -#include #include -using namespace Genode; +/* core includes */ +#include + +using namespace Core; Rom_session_component::Rom_session_component(Rom_fs &rom_fs, diff --git a/repos/base/src/core/rpc_cap_factory.cc b/repos/base/src/core/rpc_cap_factory.cc index 30100f9054..73569ce43e 100644 --- a/repos/base/src/core/rpc_cap_factory.cc +++ b/repos/base/src/core/rpc_cap_factory.cc @@ -11,12 +11,12 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* core-local includes */ +/* core includes */ #include -long Genode::Rpc_cap_factory::_unique_id_cnt; +long Core::Rpc_cap_factory::_unique_id_cnt; -Genode::Mutex &Genode::Rpc_cap_factory::_mutex() +Genode::Mutex &Core::Rpc_cap_factory::_mutex() { static Mutex static_mutex; return static_mutex; diff --git a/repos/base/src/core/rpc_cap_factory_l4.cc b/repos/base/src/core/rpc_cap_factory_l4.cc index c427cd7c06..cdd83082d1 100644 --- a/repos/base/src/core/rpc_cap_factory_l4.cc +++ b/repos/base/src/core/rpc_cap_factory_l4.cc @@ -19,7 +19,7 @@ #include #include -using namespace Genode; +using namespace Core; static unsigned unique_id_cnt; @@ -36,10 +36,10 @@ Native_capability Rpc_cap_factory::_alloc(Rpc_cap_factory &, Rpc_obj_key const rpc_obj_key(++unique_id_cnt); /* combine thread ID of 'ep' with new unique ID */ - Capability_space::Ipc_cap_data cap_data = - Capability_space::ipc_cap_data(ep); + Genode::Capability_space::Ipc_cap_data cap_data = + Genode::Capability_space::ipc_cap_data(ep); - return Capability_space::import(cap_data.dst, rpc_obj_key); + return Genode::Capability_space::import(cap_data.dst, rpc_obj_key); } diff --git a/repos/base/src/core/signal_receiver.cc b/repos/base/src/core/signal_receiver.cc index 1fc0d2285b..decb899325 100644 --- a/repos/base/src/core/signal_receiver.cc +++ b/repos/base/src/core/signal_receiver.cc @@ -21,22 +21,39 @@ /* base-internal includes */ #include -/* core-local includes */ +/* core includes */ #include +#include -using namespace Genode; +using namespace Core; + + +static Pd_session *_pd_ptr; + + +Signal_receiver::Signal_receiver() : _pd(*_pd_ptr) +{ + if (!_pd_ptr) { + struct Missing_call_of_init_signal_receiver { }; + for(;;); + throw Missing_call_of_init_signal_receiver(); + } +} -Signal_receiver::Signal_receiver() { } void Signal_receiver::_platform_destructor() { } -void Signal_receiver::_platform_begin_dissolve (Signal_context *) { } -void Signal_receiver::_platform_finish_dissolve(Signal_context *) { } +void Signal_receiver::_platform_begin_dissolve (Signal_context &) { } +void Signal_receiver::_platform_finish_dissolve(Signal_context &) { } + void Signal_receiver::unblock_signal_waiter(Rpc_entrypoint &) { ASSERT_NEVER_CALLED; } -typedef Signal_context_capability Sigh_cap; -Sigh_cap Signal_receiver::manage(Signal_context *) { ASSERT_NEVER_CALLED; } +using Sigh_cap = Signal_context_capability; + + +Sigh_cap Signal_receiver::manage(Signal_context &) { ASSERT_NEVER_CALLED; } + void Signal_receiver::block_for_signal() { @@ -49,7 +66,12 @@ void Signal_receiver::block_for_signal() sleep_forever(); } + Signal Signal_receiver::pending_signal() { return Signal(); } + void Signal_receiver::local_submit(Signal::Data) { ASSERT_NEVER_CALLED; } + + +void Genode::init_signal_receiver(Pd_session &pd, Parent &) { _pd_ptr = &pd; } diff --git a/repos/base/src/core/signal_source_component.cc b/repos/base/src/core/signal_source_component.cc index 7b91c0be78..3de6f26b2c 100644 --- a/repos/base/src/core/signal_source_component.cc +++ b/repos/base/src/core/signal_source_component.cc @@ -17,7 +17,7 @@ /* core includes */ #include -using namespace Genode; +using namespace Core; /***************************** diff --git a/repos/base/src/core/signal_transmitter_noinit.cc b/repos/base/src/core/signal_transmitter_noinit.cc index 44b01e4734..62ba8f6342 100644 --- a/repos/base/src/core/signal_transmitter_noinit.cc +++ b/repos/base/src/core/signal_transmitter_noinit.cc @@ -14,12 +14,13 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* core-local includes */ +/* core includes */ #include #include -using namespace Genode; +using namespace Core; -void Genode::init_core_signal_transmitter(Rpc_entrypoint &) { } + +void Core::init_core_signal_transmitter(Rpc_entrypoint &) { } Rpc_entrypoint &Core_env::signal_ep() { return _entrypoint; } diff --git a/repos/base/src/core/signal_transmitter_proxy.cc b/repos/base/src/core/signal_transmitter_proxy.cc index 3d861a3849..9e9a0f3f79 100644 --- a/repos/base/src/core/signal_transmitter_proxy.cc +++ b/repos/base/src/core/signal_transmitter_proxy.cc @@ -16,7 +16,7 @@ #include #include -/* core-local includes */ +/* core includes */ #include #include #include @@ -24,25 +24,16 @@ /* base-internal includes */ #include -using namespace Genode; +using namespace Core; static Constructible delivery_proxy; -/* - * Entrypoint that serves the 'Signal_source' RPC objects - */ -static Rpc_entrypoint *_ep; - - -void Genode::init_core_signal_transmitter(Rpc_entrypoint &ep) { _ep = &ep; } - - -void Genode::init_signal_transmitter(Env &) +void Core::init_core_signal_transmitter(Rpc_entrypoint &ep) { - if (!delivery_proxy.constructed() && _ep) - delivery_proxy.construct(*_ep); + if (!delivery_proxy.constructed()) + delivery_proxy.construct(ep); } diff --git a/repos/base/src/core/spec/x86/io_port_session_component.cc b/repos/base/src/core/spec/x86/io_port_session_component.cc index 200fcf6b2a..10c1874098 100644 --- a/repos/base/src/core/spec/x86/io_port_session_component.cc +++ b/repos/base/src/core/spec/x86/io_port_session_component.cc @@ -19,13 +19,9 @@ /* core includes */ #include -using namespace Genode; +using namespace Core; -/****************************** - ** Constructor / destructor ** - ******************************/ - Io_port_session_component::Io_port_session_component(Range_allocator &io_port_alloc, const char *args) : _io_port_alloc(io_port_alloc) diff --git a/repos/base/src/core/spec/x86/io_port_session_support.cc b/repos/base/src/core/spec/x86/io_port_session_support.cc index f65579068b..a51e505e31 100644 --- a/repos/base/src/core/spec/x86/io_port_session_support.cc +++ b/repos/base/src/core/spec/x86/io_port_session_support.cc @@ -14,7 +14,7 @@ /* core includes */ #include -using namespace Genode; +using namespace Core; /************** diff --git a/repos/base/src/core/spec/x86/platform_services.cc b/repos/base/src/core/spec/x86/platform_services.cc index 5bd9f18921..1edc5d85e2 100644 --- a/repos/base/src/core/spec/x86/platform_services.cc +++ b/repos/base/src/core/spec/x86/platform_services.cc @@ -24,10 +24,10 @@ /* * Add x86 specific ioport service */ -void Genode::platform_add_local_services(Rpc_entrypoint &, - Sliced_heap &sliced_heap, - Registry &local_services, - Trace::Source_registry &) +void Core::platform_add_local_services(Rpc_entrypoint &, + Sliced_heap &sliced_heap, + Registry &local_services, + Trace::Source_registry &) { static Io_port_root io_port_root(*core_env().pd_session(), platform().io_port_alloc(), sliced_heap); diff --git a/repos/base/src/core/stack_area.cc b/repos/base/src/core/stack_area.cc index c981eb54e5..a8116e91d1 100644 --- a/repos/base/src/core/stack_area.cc +++ b/repos/base/src/core/stack_area.cc @@ -15,7 +15,6 @@ /* Genode includes */ #include #include -#include #include #include @@ -37,7 +36,7 @@ namespace Genode { } -using namespace Genode; +using namespace Core; /** @@ -56,7 +55,7 @@ class Stack_area_region_map : public Region_map { private: - using Ds_slab = Synced_allocator >; Ds_slab _ds_slab { platform().core_mem_alloc() }; @@ -66,52 +65,53 @@ class Stack_area_region_map : public Region_map /** * Allocate and attach on-the-fly backing store to stack area */ - Local_addr attach(Dataspace_capability, size_t size, off_t, - bool, Local_addr local_addr, bool, bool) override + Attach_result attach(Dataspace_capability, Attr const &attr) override { /* allocate physical memory */ - size = round_page(size); + size_t const size = round_page(attr.size); Range_allocator &phys = platform_specific().ram_alloc(); - return phys.alloc_aligned(size, get_page_size_log2()).convert( + return phys.alloc_aligned(size, get_page_size_log2()).convert( - [&] (void *phys_ptr) { + [&] (void *phys_ptr) -> Attach_result { - addr_t const phys_base = (addr_t)phys_ptr; + try { + addr_t const phys_base = (addr_t)phys_ptr; - Dataspace_component &ds = *new (&_ds_slab) - Dataspace_component(size, 0, (addr_t)phys_base, CACHED, true, 0); + Dataspace_component &ds = *new (&_ds_slab) + Dataspace_component(size, 0, (addr_t)phys_base, CACHED, true, 0); - addr_t const core_local_addr = stack_area_virtual_base() - + (addr_t)local_addr; + addr_t const core_local_addr = stack_area_virtual_base() + + attr.at; - if (!map_local(ds.phys_addr(), core_local_addr, - ds.size() >> get_page_size_log2())) { - error("could not map phys ", Hex(ds.phys_addr()), - " at local ", Hex(core_local_addr)); + if (!map_local(ds.phys_addr(), core_local_addr, + ds.size() >> get_page_size_log2())) { + error("could not map phys ", Hex(ds.phys_addr()), + " at local ", Hex(core_local_addr)); - phys.free(phys_ptr); - return Local_addr { (addr_t)0 }; + phys.free(phys_ptr); + return Attach_error::INVALID_DATASPACE; + } + + ds.assign_core_local_addr((void*)core_local_addr); + + return Range { .start = attr.at, .num_bytes = size }; } - - ds.assign_core_local_addr((void*)core_local_addr); - - return local_addr; + catch (Out_of_ram) { return Attach_error::OUT_OF_RAM; } + catch (Out_of_caps) { return Attach_error::OUT_OF_CAPS; } }, [&] (Range_allocator::Alloc_error) { error("could not allocate backing store for new stack"); - return (addr_t)0; }); + return Attach_error::REGION_CONFLICT; }); } - void detach(Local_addr local_addr) override + void detach(addr_t const at) override { - using Genode::addr_t; - - if ((addr_t)local_addr >= stack_area_virtual_size()) + if (at >= stack_area_virtual_size()) return; - addr_t const detach = stack_area_virtual_base() + (addr_t)local_addr; + addr_t const detach = stack_area_virtual_base() + at; addr_t const stack = stack_virtual_size(); addr_t const pages = ((detach & ~(stack - 1)) + stack - detach) >> get_page_size_log2(); @@ -121,9 +121,9 @@ class Stack_area_region_map : public Region_map void fault_handler(Signal_context_capability) override { } - State state() override { return State(); } + Fault fault() override { return { }; } - Dataspace_capability dataspace() override { return Dataspace_capability(); } + Dataspace_capability dataspace() override { return { }; } }; diff --git a/repos/base/src/core/trace_session_component.cc b/repos/base/src/core/trace_session_component.cc index 235da3555e..72688722ed 100644 --- a/repos/base/src/core/trace_session_component.cc +++ b/repos/base/src/core/trace_session_component.cc @@ -11,14 +11,15 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* core-internal includes */ -#include +/* Genode includes */ #include #include +/* core-internal includes */ +#include -using namespace Genode; -using namespace Genode::Trace; +using namespace Core; +using namespace Core::Trace; Dataspace_capability Session_component::dataspace() @@ -27,129 +28,139 @@ Dataspace_capability Session_component::dataspace() } -size_t Session_component::subjects() +Session_component::Subjects_rpc_result Session_component::subjects() { - _subjects.import_new_sources(_sources); - - return _subjects.subjects(_argument_buffer.local_addr(), - _argument_buffer.size()/sizeof(Subject_id)); -} - - -size_t Session_component::subject_infos() -{ - _subjects.import_new_sources(_sources); - - size_t const count = _argument_buffer.size() / (sizeof(Subject_info) + sizeof(Subject_id)); - Subject_info *infos = _argument_buffer.local_addr(); - Subject_id *ids = reinterpret_cast(infos + count); - - return _subjects.subjects(infos, ids, count); -} - - -Policy_id Session_component::alloc_policy(size_t size) -{ - if (size > _argument_buffer.size()) - throw Policy_too_large(); - - /* - * Using prefix incrementation makes sure a policy with id == 0 is - * invalid. - */ - Policy_id const id(++_policy_cnt); - - Ram_quota const amount { size }; - - /* - * \throw Out_of_ram - */ - withdraw(amount); - try { - Dataspace_capability ds_cap = _ram.alloc(size); - _policies.insert(*this, id, _policies_slab, ds_cap, size); - - } catch (...) { - - /* revert withdrawal or quota */ - replenish(amount); - throw; + _subjects.import_new_sources(_sources); } + catch (Out_of_ram) { return Alloc_rpc_error::OUT_OF_RAM; } + catch (Out_of_caps) { return Alloc_rpc_error::OUT_OF_CAPS; } - return id; + return Num_subjects { _subjects.subjects(_argument_buffer.local_addr(), + _argument_buffer.size()/sizeof(Subject_id)) }; } -Dataspace_capability Session_component::policy(Policy_id id) +Session_component::Infos_rpc_result Session_component::subject_infos() { - return _policies.dataspace(*this, id); -} - - -void Session_component::unload_policy(Policy_id id) -{ - _policies.remove(*this, id); -} - - -void Session_component::trace(Subject_id subject_id, Policy_id policy_id, - size_t buffer_size) -{ - size_t const policy_size = _policies.size(*this, policy_id); - - Ram_quota const required_ram { buffer_size + policy_size }; - - Trace::Subject &subject = _subjects.lookup_by_id(subject_id); - - /* revert quota from previous call to trace */ - if (subject.allocated_memory()) { - replenish(Ram_quota{subject.allocated_memory()}); - subject.reset_allocated_memory(); - } - - /* - * Account RAM needed for trace buffer and policy buffer to the trace - * session. - * - * \throw Out_of_ram - */ - withdraw(required_ram); - try { - subject.trace(policy_id, _policies.dataspace(*this, policy_id), - policy_size, _ram, _local_rm, buffer_size); - } catch (...) { - /* revert withdrawal or quota */ - replenish(required_ram); - throw; + _subjects.import_new_sources(_sources); } + catch (Out_of_ram) { return Alloc_rpc_error::OUT_OF_RAM; } + catch (Out_of_caps) { return Alloc_rpc_error::OUT_OF_CAPS; } + + unsigned const count = unsigned(_argument_buffer.size() / + (sizeof(Subject_info) + sizeof(Subject_id))); + + Subject_info * const infos = _argument_buffer.local_addr(); + Subject_id * const ids = reinterpret_cast(infos + count); + + return Num_subjects { _subjects.subjects(infos, ids, count) }; } -void Session_component::pause(Subject_id subject_id) +Session_component::Alloc_policy_rpc_result Session_component::alloc_policy(Policy_size size) { - _subjects.lookup_by_id(subject_id).pause(); + size.num_bytes = min(size.num_bytes, _argument_buffer.size()); + + Policy_id const id { ++_policy_cnt }; + + return _ram.try_alloc(size.num_bytes).convert( + + [&] (Ram_dataspace_capability const ds_cap) -> Alloc_policy_rpc_result { + try { + _policies.insert(*this, id, _policies_slab, ds_cap, size); + } + catch (Out_of_ram) { _ram.free(ds_cap); return Alloc_policy_rpc_error::OUT_OF_RAM; } + catch (Out_of_caps) { _ram.free(ds_cap); return Alloc_policy_rpc_error::OUT_OF_CAPS; } + return id; + }, + [&] (Ram_allocator::Alloc_error const e) -> Alloc_policy_rpc_result { + switch (e) { + case Ram_allocator::Alloc_error::OUT_OF_RAM: return Alloc_policy_rpc_error::OUT_OF_RAM; + case Ram_allocator::Alloc_error::OUT_OF_CAPS: return Alloc_policy_rpc_error::OUT_OF_CAPS; + case Ram_allocator::Alloc_error::DENIED: break; + } + return Alloc_policy_rpc_error::INVALID; + }); } -void Session_component::resume(Subject_id subject_id) +Dataspace_capability Session_component::policy(Policy_id const id) { - _subjects.lookup_by_id(subject_id).resume(); + Dataspace_capability result { }; + _policies.with_dataspace(*this, id, [&] (Dataspace_capability ds) { + result = ds; }); + return result; } -Dataspace_capability Session_component::buffer(Subject_id subject_id) +void Session_component::unload_policy(Policy_id const id) { - return _subjects.lookup_by_id(subject_id).buffer(); + _policies.with_dataspace(*this, id, [&] (Dataspace_capability ds) { + _policies.remove(*this, id); + _ram.free(static_cap_cast(ds)); }); } -void Session_component::free(Subject_id subject_id) +Session_component::Trace_rpc_result +Session_component::trace(Subject_id subject_id, Policy_id policy_id, Buffer_size size) { - Ram_quota const released_ram { _subjects.release(subject_id) }; + Policy_size const policy_size = _policies.size(*this, policy_id); - replenish(released_ram); + if (policy_size.num_bytes == 0) + return Trace_rpc_error::INVALID_POLICY; + + Dataspace_capability const ds = policy(policy_id); + + auto rpc_result = [] (Subject::Trace_result const result) -> Trace_rpc_result + { + using Result = Subject::Trace_result; + switch (result) { + case Result::OK: return Trace_ok { }; + case Result::OUT_OF_RAM: return Trace_rpc_error::OUT_OF_RAM; + case Result::OUT_OF_CAPS: return Trace_rpc_error::OUT_OF_CAPS; + case Result::FOREIGN: return Trace_rpc_error::FOREIGN; + case Result::SOURCE_IS_DEAD: return Trace_rpc_error::SOURCE_IS_DEAD; + case Result::INVALID_SUBJECT: break; + }; + return Trace_rpc_error::INVALID_SUBJECT; + }; + + Trace_rpc_result result = Trace_rpc_error::INVALID_SUBJECT; + + _subjects.with_subject(subject_id, [&] (Subject &subject) { + result = rpc_result(subject.trace(policy_id, ds, policy_size, _ram, + _local_rm, size)); }); + + return result; +} + + +void Session_component::pause(Subject_id id) +{ + _subjects.with_subject(id, [&] (Subject &subject) { subject.pause(); }); +} + + +void Session_component::resume(Subject_id id) +{ + _subjects.with_subject(id, [&] (Subject &subject) { subject.resume(); }); +} + + +Dataspace_capability Session_component::buffer(Subject_id id) +{ + Dataspace_capability result { }; + _subjects.with_subject(id, [&] (Subject &subject) { + result = subject.buffer(); }); + return result; +} + + +void Session_component::free(Subject_id id) +{ + _subjects.release(id); } @@ -160,7 +171,6 @@ Session_component::Session_component(Rpc_entrypoint &ep, Ram_allocator &ram, Region_map &local_rm, size_t arg_buffer_size, - unsigned /* parent_levels */, Source_registry &sources, Policy_registry &policies) : @@ -171,7 +181,7 @@ Session_component::Session_component(Rpc_entrypoint &ep, _policies_slab(&_md_alloc), _sources(sources), _policies(policies), - _subjects(_subjects_slab, _sources), + _subjects(_subjects_slab, _sources, _filter()), _argument_buffer(_ram, local_rm, arg_buffer_size) { } diff --git a/repos/base/src/core/vm_session_common.cc b/repos/base/src/core/vm_session_common.cc index acf7fa256e..23c71f5fa0 100644 --- a/repos/base/src/core/vm_session_common.cc +++ b/repos/base/src/core/vm_session_common.cc @@ -16,16 +16,16 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* Base includes */ +/* Genode includes */ #include -/* Core includes */ +/* core includes */ #include #include #include -using Genode::addr_t; -using Genode::Vm_session_component; +using namespace Core; + void Vm_session_component::attach(Dataspace_capability const cap, addr_t const guest_phys, @@ -65,6 +65,8 @@ void Vm_session_component::attach(Dataspace_capability const cap, using Alloc_error = Range_allocator::Alloc_error; + Region_map_detach &rm_detach = *this; + _map.alloc_addr(attribute.size, guest_phys).with_result( [&] (void *) { @@ -75,14 +77,14 @@ void Vm_session_component::attach(Dataspace_capability const cap, .size = attribute.size, .write = dsc.writeable() && attribute.writeable, .exec = attribute.executable, - .off = (off_t)attribute.offset, + .off = attribute.offset, .dma = false, }; /* store attachment info in meta data */ try { _map.construct_metadata((void *)guest_phys, - dsc, *this, region_attr); + dsc, rm_detach, region_attr); } catch (Allocator_avl_tpl::Assign_metadata_failed) { error("failed to store attachment info"); @@ -112,8 +114,10 @@ void Vm_session_component::attach(Dataspace_capability const cap, Rm_region ®ion = *region_ptr; - if (!(cap == region.dataspace().cap())) - throw Region_conflict(); + region.with_dataspace([&] (Dataspace_component &dataspace) { + if (!(cap == dataspace.cap())) + throw Region_conflict(); + }); if (guest_phys < region.base() || guest_phys > region.base() + region.size() - 1) @@ -147,12 +151,7 @@ void Vm_session_component::detach(addr_t guest_phys, size_t size) if (region) { iteration_size = region->size(); - - /* inform dataspace */ - region->dataspace().detached_from(*region); - - /* cleanup metadata */ - _map.free(reinterpret_cast(region->base())); + detach_at(region->base()); } if (addr >= guest_phys_end - (iteration_size - 1)) @@ -160,23 +159,51 @@ void Vm_session_component::detach(addr_t guest_phys, size_t size) addr += iteration_size; } while (true); - - /* kernel specific code to detach memory from guest */ - _detach_vm_memory(guest_phys, size); } -void Vm_session_component::detach(Region_map::Local_addr addr) +void Vm_session_component::_with_region(addr_t const addr, + auto const &fn) { - Rm_region *region = _map.metadata(addr); + Rm_region *region = _map.metadata((void *)addr); if (region) - detach(region->base(), region->size()); + fn(*region); else - Genode::error(__PRETTY_FUNCTION__, " unknown region"); + error(__PRETTY_FUNCTION__, " unknown region"); +} + + +void Vm_session_component::detach_at(addr_t const addr) +{ + _with_region(addr, [&] (Rm_region ®ion) { + + if (!region.reserved()) + reserve_and_flush(addr); + + /* free the reserved region */ + _map.free(reinterpret_cast(region.base())); + }); } void Vm_session_component::unmap_region(addr_t base, size_t size) { - Genode::error(__func__, " unimplemented ", base, " ", size); + error(__func__, " unimplemented ", base, " ", size); +} + + +void Vm_session_component::reserve_and_flush(addr_t const addr) +{ + _with_region(addr, [&] (Rm_region ®ion) { + + /* inform dataspace */ + region.with_dataspace([&] (Dataspace_component &dataspace) { + dataspace.detached_from(region); + }); + + region.mark_as_reserved(); + + /* kernel specific code to detach memory from guest */ + _detach_vm_memory(region.base(), region.size()); + }); } diff --git a/repos/base/src/include/base/internal/alarm_registry.h b/repos/base/src/include/base/internal/alarm_registry.h new file mode 100644 index 0000000000..4c1eb8c241 --- /dev/null +++ b/repos/base/src/include/base/internal/alarm_registry.h @@ -0,0 +1,281 @@ +/* + * \brief Registry of time-sorted alarms + * \author Norman Feske + * \date 2024-03-06 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _INCLUDE__BASE__INTERNAL__ALARM_REGISTRY_H_ +#define _INCLUDE__BASE__INTERNAL__ALARM_REGISTRY_H_ + +/* Genode includes */ +#include + +namespace Genode { template class Alarm_registry; } + + +/** + * Registry of schedules alarm objects + * + * \param T alarm type, must be derived from 'Alarm_registry::Element' + * \param CLOCK type representing a circular clock + * + * The registry represents a set of scheduled alarms. An alarm object is + * scheduled upon creation and de-scheduled on destruction. + * + * The 'CLOCK' type must be constructible with an '' numeric value + * where '' can be an unsigned integer of any byte width. + * The clock provides the following interface: + * + * ! static constexpr MASK = ; + * ! value() const; + * ! void print(Output &) const; + * + * 'MASK' defines the limit of the circular clock. + * The 'value()' method returns a number between 0 and MASK. + * The 'print' method is needed only when using 'Alarm_registry::print'. + * In this case, the alarm type must also provide a 'print' method. + */ +template +class Genode::Alarm_registry : Noncopyable +{ + private: + + using Clock = CLOCK; + + struct Range + { + Clock start, end; /* range [start,end] where 'start' >= 'end' */ + + void with_intersection(Range const other, auto const &fn) const + { + auto const f = max(start.value(), other.start.value()); + auto const t = min(end.value(), other.end.value()); + + if (f <= t) + fn(Range { Clock { f }, Clock { t } }); + } + + bool contains(Clock const time) const + { + return (time.value() >= start.value()) + && (time.value() <= end.value()); + } + + void print(Output &out) const + { + Genode::print(out, "[", start.value(), "...", end.value(), "]"); + } + }; + + public: + + struct None { }; + using Soonest_result = Attempt; + + class Element : Avl_node + { + private: + + Alarm_registry &_registry; + + T &_obj; + + friend class Alarm_registry; + friend class Avl_node; + friend class Avl_tree; + + public: + + Clock time; + + Element(Alarm_registry ®istry, T &obj, Clock time) + : + _registry(registry), _obj(obj), time(time) + { + _registry._elements.insert(this); + } + + ~Element() + { + _registry._elements.remove(this); + } + + /** + * Avl_node ordering, allow duplicated keys + */ + bool higher(Element const * const other) const + { + return time.value() <= other->time.value(); + } + + void print(Output &out) const + { + Genode::print(out, _obj, ": time=", time); + } + + private: + + static void _with_child(auto &element, bool side, auto const &fn) + { + if (element.child(side)) + fn(*element.child(side)); + } + + void _for_each(Range const range, auto const &fn) const + { + _with_child(*this, this->LEFT, [&] (Element const &child) { + range.with_intersection({ Clock { }, time }, [&] (Range l_range) { + child._for_each(l_range, fn); }); }); + + if (range.contains(time)) + fn(_obj); + + _with_child(*this, this->RIGHT, [&] (Element const &child) { + range.with_intersection({ time, Clock { Clock::MASK }}, [&] (Range r_range) { + child._for_each(r_range, fn); }); }); + } + + Element *_find_any(Range const range) + { + if (range.contains(time)) + return this; + + Element *result = nullptr; + + _with_child(*this, this->LEFT, [&] (Element &child) { + range.with_intersection({ Clock { }, time }, [&] (Range l_range) { + result = child._find_any(l_range); }); }); + + if (result) + return result; + + _with_child(*this, this->RIGHT, [&] (Element &child) { + range.with_intersection({ time, Clock { Clock::MASK }}, [&] (Range r_range) { + result = child._find_any(r_range); }); }); + + return result; + } + + Soonest_result _soonest(Clock const now) const + { + Soonest_result result = None { }; + + if (time.value() >= now.value()) { + result = time; + _with_child(*this, this->LEFT, [&] (Element const &child) { + child._soonest(now).with_result( + [&] (Clock left_soonest) { + if (time.value() > left_soonest.value()) + result = left_soonest; }, + [&] (None) { }); }); + } else { + _with_child(*this, this->RIGHT, [&] (Element const &child) { + result = child._soonest(now); }); + } + + return result; + } + }; + + private: + + Avl_tree _elements { }; + + static void _with_first(auto ®istry, auto const &fn) + { + if (registry._elements.first()) + fn(*registry._elements.first()); + } + + /* + * Call 'fn' up to two times, with the first element and a search range + * as argument. + */ + static void _for_each_search_range(auto ®istry, Clock start, Clock end, + auto const &fn) + { + _with_first(registry, [&] (auto &first) { + + if (start.value() <= end.value()) { + fn(first, Range { start, end }); + + } else if (start.value() > end.value()) { + fn(first, Range { start, Clock { Clock::MASK } }); + fn(first, Range { Clock { }, end }); + } + }); + } + + public: + + /** + * Return soonest alarm time from 'now' + */ + Soonest_result soonest(Clock const now) const + { + Soonest_result result = None { }; + + _with_first(*this, [&] (auto &first) { + first._soonest(now).with_result( + [&] (Clock soonest) { + result = soonest; }, + [&] (None) { /* clock wrapped, search from beginning */ + result = first._soonest(Clock { }); }); }); + + return result; + } + + /** + * Call 'fn' for each alarm scheduled between 'start' and 'end' + * + * The 'start' and 'end' values may wrap. + */ + void for_each_in_range(Clock const start, Clock const end, auto const &fn) const + { + _for_each_search_range(*this, start, end, [&] (Element const &e, Range range) { + e._for_each(range, fn); }); + } + + /** + * Call 'fn' with any alarm scheduled between 'start' and 'end' + * + * \return true if 'fn' was called + * + * The found alarm is passed to 'fn' as non-const reference, which + * allows the caller to modify or destroy it. + * + * The return value is handy for calling 'with_any_in_range' as a + * condition of a while loop, purging all alarms within the time + * window. + */ + bool with_any_in_range(Clock const start, Clock const end, auto const &fn) + { + Element *found_ptr = nullptr; + _for_each_search_range(*this, start, end, [&] (Element &e, Range range) { + if (!found_ptr) + found_ptr = e._find_any(range); }); + + if (found_ptr) + fn(found_ptr->_obj); + + return found_ptr != nullptr; + } + + void print(Output &out) const + { + bool first = true; + for_each_in_range(Clock { }, Clock { Clock::MASK }, [&] (Element const &e) { + Genode::print(out, first ? "" : "\n", e); + first = false; + }); + } +}; + +#endif /* _INCLUDE__BASE__INTERNAL__ALARM_REGISTRY_H_ */ diff --git a/repos/base/src/include/base/internal/attached_stack_area.h b/repos/base/src/include/base/internal/attached_stack_area.h index f48949a5ba..5347485559 100644 --- a/repos/base/src/include/base/internal/attached_stack_area.h +++ b/repos/base/src/include/base/internal/attached_stack_area.h @@ -33,11 +33,16 @@ struct Genode::Attached_stack_area : Expanding_region_map_client Expanding_region_map_client(parent, pd, Pd_session_client(pd).stack_area(), Parent::Env::pd()) { - Region_map_client address_space(Pd_session_client(pd).address_space()); + Region_map_client local_rm(Pd_session_client(pd).address_space()); - address_space.attach_at(Expanding_region_map_client::dataspace(), - stack_area_virtual_base(), - stack_area_virtual_size()); + local_rm.attach(Expanding_region_map_client::dataspace(), Region_map::Attr { + .size = stack_area_virtual_size(), + .offset = { }, + .use_at = true, + .at = stack_area_virtual_base(), + .executable = false, + .writeable = true + }); } }; diff --git a/repos/base/src/include/base/internal/capability_space_tpl.h b/repos/base/src/include/base/internal/capability_space_tpl.h index 7b2f9d083a..8fdf3b4aa6 100644 --- a/repos/base/src/include/base/internal/capability_space_tpl.h +++ b/repos/base/src/include/base/internal/capability_space_tpl.h @@ -82,7 +82,7 @@ class Genode::Capability_space_tpl { private: - typedef CAP_DATA Data; + using Data = CAP_DATA; /** * Supplement Native_capability::Data with the meta data needed to @@ -90,8 +90,7 @@ class Genode::Capability_space_tpl */ struct Tree_managed_data : Data, Avl_node { - template - Tree_managed_data(ARGS... args) : Data(args...) { } + Tree_managed_data(auto... args) : Data(args...) { } Tree_managed_data() { } @@ -143,8 +142,7 @@ class Genode::Capability_space_tpl * The arguments are passed to the constructor of the * 'Native_capability::Data' type. */ - template - Native_capability::Data &create_capability(ARGS... args) + Native_capability::Data &create_capability(auto... args) { Mutex::Guard guard(_mutex); diff --git a/repos/base/src/include/base/internal/crt0.h b/repos/base/src/include/base/internal/crt0.h index 30f118b8dc..56630dbcbd 100644 --- a/repos/base/src/include/base/internal/crt0.h +++ b/repos/base/src/include/base/internal/crt0.h @@ -41,6 +41,6 @@ extern unsigned char _initial_stack_base[]; * capability prior the execution of the main thread. It corresponds to the * '_parent_cap' symbol defined in 'src/ld/genode.ld'. */ -extern unsigned long _parent_cap; +extern unsigned long _parent_cap[]; #endif /* _INCLUDE__BASE__CRT0_H_ */ diff --git a/repos/base/src/include/base/internal/elf_format.h b/repos/base/src/include/base/internal/elf_format.h index 2fd9f7959a..2bcce2c246 100644 --- a/repos/base/src/include/base/internal/elf_format.h +++ b/repos/base/src/include/base/internal/elf_format.h @@ -37,36 +37,36 @@ extern "C" { #include /* type for a 16-bit quantity. */ -typedef genode_uint16_t Elf32_Half; -typedef genode_uint16_t Elf64_Half; +using Elf32_Half = genode_uint16_t; +using Elf64_Half = genode_uint16_t; /* types for signed and unsigned 32-bit quantities */ -typedef genode_uint32_t Elf32_Word; -typedef genode_int32_t Elf32_Sword; -typedef genode_uint32_t Elf64_Word; -typedef genode_int32_t Elf64_Sword; +using Elf32_Word = genode_uint32_t; +using Elf32_Sword = genode_int32_t; +using Elf64_Word = genode_uint32_t; +using Elf64_Sword = genode_int32_t; /* types for signed and unsigned 64-bit quantities */ -typedef genode_uint64_t Elf32_Xword; -typedef genode_int64_t Elf32_Sxword; -typedef genode_uint64_t Elf64_Xword; -typedef genode_int64_t Elf64_Sxword; +using Elf32_Xword = genode_uint64_t; +using Elf32_Sxword = genode_int64_t; +using Elf64_Xword = genode_uint64_t; +using Elf64_Sxword = genode_int64_t; /* type of addresses */ -typedef genode_uint32_t Elf32_Addr; -typedef genode_uint64_t Elf64_Addr; +using Elf32_Addr = genode_uint32_t; +using Elf64_Addr = genode_uint64_t; /* type of file offsets */ -typedef genode_uint32_t Elf32_Off; -typedef genode_uint64_t Elf64_Off; +using Elf32_Off = genode_uint32_t; +using Elf64_Off = genode_uint64_t; /* type for section indices, which are 16-bit quantities */ -typedef genode_uint16_t Elf32_Section; -typedef genode_uint16_t Elf64_Section; +using Elf32_Section = genode_uint16_t; +using Elf64_Section = genode_uint16_t; /* type for version symbol information */ -typedef Elf32_Half Elf32_Versym; -typedef Elf64_Half Elf64_Versym; +using Elf32_Versym = Elf32_Half; +using Elf64_Versym = Elf64_Half; /** @@ -74,7 +74,7 @@ typedef Elf64_Half Elf64_Versym; */ enum { EI_NIDENT = 16 }; -typedef struct +struct Elf32_Ehdr { unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ Elf32_Half e_type; /* Object file type */ @@ -90,9 +90,9 @@ typedef struct Elf32_Half e_shentsize; /* Section header table entry size */ Elf32_Half e_shnum; /* Section header table entry count */ Elf32_Half e_shstrndx; /* Section header string table index */ -} Elf32_Ehdr; +}; -typedef struct +struct Elf64_Ehdr { unsigned char e_ident[EI_NIDENT]; /* magic number and other info */ Elf64_Half e_type; /* object file type */ @@ -108,7 +108,7 @@ typedef struct Elf64_Half e_shentsize; /* section header table entry size */ Elf64_Half e_shnum; /* section header table entry count */ Elf64_Half e_shstrndx; /* section header string table index */ -} Elf64_Ehdr; +}; /** * Fields in the e_ident array. The EI_* macros are indices into the @@ -183,7 +183,7 @@ enum { /** * Program segment header */ -typedef struct +struct Elf32_Phdr { Elf32_Word p_type; /* segment type */ Elf32_Off p_offset; /* segment file offset */ @@ -193,9 +193,9 @@ typedef struct Elf32_Word p_memsz; /* segment size in memory */ Elf32_Word p_flags; /* segment flags */ Elf32_Word p_align; /* segment alignment */ -} Elf32_Phdr; +}; -typedef struct +struct Elf64_Phdr { Elf64_Word p_type; /* segment type */ Elf64_Word p_flags; /* segment flags */ @@ -205,7 +205,7 @@ typedef struct Elf64_Xword p_filesz; /* segment size in file */ Elf64_Xword p_memsz; /* segment size in memory */ Elf64_Xword p_align; /* segment alignment */ -} Elf64_Phdr; +}; /** * Legal values for p_type (segment type) @@ -242,12 +242,12 @@ enum { */ #ifdef _LP64 -typedef Elf64_Ehdr Elf_Ehdr; -typedef Elf64_Phdr Elf_Phdr; +using Elf_Ehdr = Elf64_Ehdr; +using Elf_Phdr = Elf64_Phdr; #define ELFCLASS ELFCLASS64 #else -typedef Elf32_Ehdr Elf_Ehdr; -typedef Elf32_Phdr Elf_Phdr; +using Elf_Ehdr = Elf32_Ehdr; +using Elf_Phdr = Elf32_Phdr; #define ELFCLASS ELFCLASS32 #endif /* _LP64 */ diff --git a/repos/base/src/include/base/internal/expanding_cpu_session_client.h b/repos/base/src/include/base/internal/expanding_cpu_session_client.h index 3b47b3a30a..4f73b24bc9 100644 --- a/repos/base/src/include/base/internal/expanding_cpu_session_client.h +++ b/repos/base/src/include/base/internal/expanding_cpu_session_client.h @@ -38,19 +38,27 @@ struct Genode::Expanding_cpu_session_client : Upgradeable_client(cap), id) { } - Thread_capability + Create_thread_result create_thread(Pd_session_capability pd, Name const &name, Affinity::Location location, Weight weight, addr_t utcb) override { - return retry( - [&] () { - return retry( - [&] () { - return Cpu_session_client::create_thread(pd, name, location, - weight, utcb); }, - [&] () { upgrade_caps(2); }); - }, - [&] () { upgrade_ram(8*1024); }); + Thread_capability result { }; + bool denied = false; + while (!result.valid()) { + using Error = Cpu_session::Create_thread_error; + Cpu_session_client::create_thread(pd, name, location, weight, utcb).with_result( + [&] (Thread_capability cap) { result = cap; }, + [&] (Error e) { + switch (e) { + case Error::OUT_OF_RAM: upgrade_ram(8*1024); break; + case Error::OUT_OF_CAPS: upgrade_caps(2); break; + case Error::DENIED: denied = true; break; + } + }); + if (denied) + return Error::DENIED; + } + return result; } }; diff --git a/repos/base/src/include/base/internal/expanding_parent_client.h b/repos/base/src/include/base/internal/expanding_parent_client.h index a2ff3f6b74..af2fe56713 100644 --- a/repos/base/src/include/base/internal/expanding_parent_client.h +++ b/repos/base/src/include/base/internal/expanding_parent_client.h @@ -90,7 +90,7 @@ class Genode::Expanding_parent_client : public Parent_client { if (!_fallback_sig_cap.valid()) { _fallback_sig_rcv.construct(); - _fallback_sig_cap = _fallback_sig_rcv->manage(&_fallback_sig_ctx); + _fallback_sig_cap = _fallback_sig_rcv->manage(_fallback_sig_ctx); } } @@ -113,10 +113,10 @@ class Genode::Expanding_parent_client : public Parent_client } } - Session_capability session(Client::Id id, - Service_name const &name, - Session_args const &args, - Affinity const &affinity) override + Session_result session(Client::Id id, + Service_name const &name, + Session_args const &args, + Affinity const &affinity) override { return Parent_client::session(id, name, args, affinity); } @@ -130,39 +130,28 @@ class Genode::Expanding_parent_client : public Parent_client */ if (id == Env::pd()) { resource_request(Resource_args(args.string())); - return UPGRADE_DONE; + return Upgrade_result::OK; } /* - * If the upgrade fails, attempt to issue a resource request twice. - * - * If the default fallback for resource-available signals is used, - * the first request will block until the resources are upgraded. - * The second attempt to upgrade will succeed. - * - * If a custom handler is installed, the resource quest will return - * immediately. The second upgrade attempt may fail too if the - * parent handles the resource request asynchronously. In this - * case, we escalate the problem to caller by propagating the - * 'Out_of_ram' or 'Out_of_caps' exception. Now, it is the job of - * the caller to issue (and respond to) a resource request. + * If the upgrade fails, attempt to issue a resource request */ Session::Resources const amount = session_resources_from_args(args.string()); using Arg = String<64>; - return retry( - [&] () { - return retry( - [&] () { return Parent_client::upgrade(id, args); }, - [&] () { - Arg cap_arg("cap_quota=", amount.cap_quota); - resource_request(Resource_args(cap_arg.string())); - }); - }, - [&] () { + for (;;) { + Upgrade_result const result = Parent_client::upgrade(id, args); + if (result == Upgrade_result::OUT_OF_RAM) { Arg ram_arg("ram_quota=", amount.ram_quota); resource_request(Resource_args(ram_arg.string())); - }); + } + else if (result == Upgrade_result::OUT_OF_CAPS) { + Arg cap_arg("cap_quota=", amount.cap_quota); + resource_request(Resource_args(cap_arg.string())); + } + else + return result; + } } void resource_avail_sigh(Signal_context_capability sigh) override diff --git a/repos/base/src/include/base/internal/expanding_pd_session_client.h b/repos/base/src/include/base/internal/expanding_pd_session_client.h index bd2fd35687..fea7aa48fe 100644 --- a/repos/base/src/include/base/internal/expanding_pd_session_client.h +++ b/repos/base/src/include/base/internal/expanding_pd_session_client.h @@ -38,7 +38,7 @@ struct Genode::Expanding_pd_session_client : Pd_session_client Expanding_pd_session_client(Parent &parent, Pd_session_capability cap) : Pd_session_client(cap), _parent(parent) { } - Alloc_result try_alloc(size_t size, Cache cache = UNCACHED) override + Alloc_result try_alloc(size_t size, Cache cache) override { /* * If the PD session runs out of quota, issue a resource request @@ -83,26 +83,30 @@ struct Genode::Expanding_pd_session_client : Pd_session_client } } - void transfer_quota(Pd_session_capability pd_session, Ram_quota amount) override + Transfer_ram_quota_result transfer_quota(Pd_session_capability pd_session, Ram_quota amount) override { /* * Should the transfer fail because we don't have enough quota, request * the needed amount from the parent. */ - enum { NUM_ATTEMPTS = 2 }; - retry( - [&] () { Pd_session_client::transfer_quota(pd_session, amount); }, - [&] () { _request_ram_from_parent(amount.value); }, - NUM_ATTEMPTS); + for (;;) { + auto const result = Pd_session_client::transfer_quota(pd_session, amount); + if (result != Transfer_ram_quota_result::OUT_OF_RAM) + return result; + + _request_ram_from_parent(amount.value); + } } - void transfer_quota(Pd_session_capability pd_session, Cap_quota amount) override + Transfer_cap_quota_result transfer_quota(Pd_session_capability pd_session, Cap_quota amount) override { - enum { NUM_ATTEMPTS = 2 }; - retry( - [&] () { Pd_session_client::transfer_quota(pd_session, amount); }, - [&] () { _request_caps_from_parent(amount.value); }, - NUM_ATTEMPTS); + for (;;) { + auto const result = Pd_session_client::transfer_quota(pd_session, amount); + if (result != Transfer_cap_quota_result::OUT_OF_CAPS) + return result; + + _request_caps_from_parent(amount.value); + } } }; diff --git a/repos/base/src/include/base/internal/expanding_region_map_client.h b/repos/base/src/include/base/internal/expanding_region_map_client.h index bca104edd3..b06b37f85d 100644 --- a/repos/base/src/include/base/internal/expanding_region_map_client.h +++ b/repos/base/src/include/base/internal/expanding_region_map_client.h @@ -34,22 +34,15 @@ struct Genode::Expanding_region_map_client : Region_map_client Parent::Client::Id pd_id) : Region_map_client(rm), _pd_client(parent, pd, pd_id) { } - Local_addr attach(Dataspace_capability ds, size_t size, off_t offset, - bool use_local_addr, Local_addr local_addr, - bool executable, bool writeable) override + Attach_result attach(Dataspace_capability ds, Attr const &attr) override { - return retry( - [&] () { - return retry( - [&] { - return Region_map_client::attach(ds, size, offset, - use_local_addr, - local_addr, - executable, - writeable); }, - [&] { _pd_client.upgrade_caps(2); }); - }, - [&] () { _pd_client.upgrade_ram(8*1024); }); + for (;;) { + Attach_result const result = Region_map_client::attach(ds, attr); + if (result == Attach_error::OUT_OF_RAM) _pd_client.upgrade_ram(8*1024); + else if (result == Attach_error::OUT_OF_CAPS) _pd_client.upgrade_caps(2); + else + return result; + } } }; diff --git a/repos/base/src/include/base/internal/globals.h b/repos/base/src/include/base/internal/globals.h index 4eeb3aa8c2..961eb81ed7 100644 --- a/repos/base/src/include/base/internal/globals.h +++ b/repos/base/src/include/base/internal/globals.h @@ -21,37 +21,42 @@ namespace Genode { class Region_map; class Ram_allocator; class Env; + class Platform; class Local_session_id_space; extern Region_map *env_stack_area_region_map; extern Ram_allocator *env_stack_area_ram_allocator; - Thread_capability main_thread_cap(); + Platform &init_platform(); void init_stack_area(); - void init_exception_handling(Env &); + void init_exception_handling(Ram_allocator &, Region_map &); void init_signal_transmitter(Env &); - void init_cxx_heap(Env &); + void init_signal_receiver(Pd_session &, Parent &); + void init_cap_slab(Pd_session &, Parent &); + void init_cxx_heap(Ram_allocator &, Region_map &); void init_cxx_guard(); void init_ldso_phdr(Env &); void init_signal_thread(Env &); void init_root_proxy(Env &); void init_tracing(Env &); void init_log(Parent &); + void init_rpc_cap_alloc(Parent &); void init_parent_resource_requests(Env &); void init_heartbeat_monitoring(Env &); - void deinit_heartbeat_monitoring(); + void init_thread(Cpu_session &, Region_map &); + void init_thread_start(Capability); + void init_thread_bootstrap(Cpu_session &, Thread_capability); void exec_static_constructors(); - void destroy_signal_thread(); - void cxx_demangle(char const*, char*, size_t); void cxx_current_exception(char *out, size_t size); void cxx_free_tls(void *thread); Id_space &env_session_id_space(); - Env &internal_env(); + void prepare_init_main_thread(); + void bootstrap_component(Platform &); void binary_ready_hook_for_platform(); } diff --git a/repos/base/src/include/base/internal/ipc_server.h b/repos/base/src/include/base/internal/ipc_server.h index 91b4ed803f..dfca2b0d4d 100644 --- a/repos/base/src/include/base/internal/ipc_server.h +++ b/repos/base/src/include/base/internal/ipc_server.h @@ -28,7 +28,7 @@ namespace Genode { void ipc_reply(Native_capability caller, Rpc_exception_code, Msgbuf_base &snd_msg); - typedef Native_capability Reply_capability; + using Reply_capability = Native_capability; struct Rpc_request { diff --git a/repos/base/src/include/base/internal/output.h b/repos/base/src/include/base/internal/output.h index ada980e5c7..297b993419 100644 --- a/repos/base/src/include/base/internal/output.h +++ b/repos/base/src/include/base/internal/output.h @@ -32,8 +32,7 @@ static inline char ascii(int digit, int uppercase = 0) /** * Output signed value with the specified base */ -template -static inline void out_signed(T value, unsigned base, OUT_CHAR_FN const &out_char) +static inline void out_signed(auto value, unsigned base, auto const &out_char_fn) { /** * for base 8, the number of digits is the number of value bytes times 3 @@ -61,20 +60,19 @@ static inline void out_signed(T value, unsigned base, OUT_CHAR_FN const &out_cha /* add sign to buffer for negative values */ if (neg) - out_char('-'); + out_char_fn('-'); /* output buffer in reverse order */ for (; i--; ) - out_char(buf[i]); + out_char_fn(buf[i]); } /** * Output unsigned value with the specified base and padding */ -template -static inline void out_unsigned(T value, unsigned base, int pad, - OUT_CHAR_FN const &out_char) +static inline void out_unsigned(auto value, unsigned base, int pad, + auto const &out_char_fn) { /** * for base 8, the number of digits is the number of value bytes times 3 @@ -97,19 +95,19 @@ static inline void out_unsigned(T value, unsigned base, int pad, /* add padding zeros */ for (; pad-- > 0; ) - out_char(ascii(0)); + out_char_fn(ascii(0)); /* output buffer in reverse order */ for (; i--; ) - out_char(buf[i]); + out_char_fn(buf[i]); } /** * Output floating point value */ -template -static inline void out_float(T value, unsigned base, unsigned length, OUT_CHAR_FN const &out_char) +template +static inline void out_float(T value, unsigned base, unsigned length, auto const &out_char_fn) { using namespace Genode; @@ -136,10 +134,10 @@ static inline void out_float(T value, unsigned base, unsigned length, OUT_CHAR_F uint64_t integer = (uint64_t)volatile_value; if (neg) - out_char('-'); + out_char_fn('-'); - out_unsigned(integer, base, 0, out_char); - out_char('.'); + out_unsigned(integer, base, 0, out_char_fn); + out_char_fn('.'); if (length) { do { @@ -147,7 +145,7 @@ static inline void out_float(T value, unsigned base, unsigned length, OUT_CHAR_F volatile_value = (T)(volatile_value * (T)base); integer = (uint64_t)volatile_value; - out_char(ascii((int)integer)); + out_char_fn(ascii((int)integer)); length--; } while (length && (volatile_value > 0.0)); diff --git a/repos/base/src/include/base/internal/page_size.h b/repos/base/src/include/base/internal/page_size.h index 6aa7731062..1f352f3ec5 100644 --- a/repos/base/src/include/base/internal/page_size.h +++ b/repos/base/src/include/base/internal/page_size.h @@ -18,8 +18,8 @@ namespace Genode { - constexpr size_t get_page_size_log2() { return 12; } - constexpr size_t get_page_size() { return 1 << get_page_size_log2(); } + constexpr uint8_t get_page_size_log2() { return 12; } + constexpr size_t get_page_size() { return 1 << get_page_size_log2(); } } #endif /* _INCLUDE__BASE__INTERNAL__PAGE_SIZE_H_ */ diff --git a/repos/base/src/include/base/internal/platform.h b/repos/base/src/include/base/internal/platform.h new file mode 100644 index 0000000000..8c94f3b825 --- /dev/null +++ b/repos/base/src/include/base/internal/platform.h @@ -0,0 +1,59 @@ +/* + * \brief Platform of Genode component + * \author Norman Feske + * \author Christian Helmuth + * \date 2006-07-28 + */ + +/* + * Copyright (C) 2006-2023 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _INCLUDE__BASE__INTERNAL__PLATFORM_H_ +#define _INCLUDE__BASE__INTERNAL__PLATFORM_H_ + +/* base-internal includes */ +#include +#include +#include +#include +#include +#include +#include + +namespace Genode { class Platform; } + + +struct Genode::Platform : Noncopyable +{ + Expanding_parent_client parent { Genode::parent_cap() }; + + template Capability _request(Parent::Client::Id id) + { + return parent.session_cap(id).convert>( + [&] (Capability cap) { return static_cap_cast(cap); }, + [&] (Parent::Session_cap_error) { return Capability(); }); + } + + Expanding_pd_session_client pd { + parent, _request(Parent::Env::pd()) }; + + Expanding_cpu_session_client cpu { + parent, _request(Parent::Env::cpu()), Parent::Env::cpu() }; + + Expanding_region_map_client rm { + parent, pd.rpc_cap(), pd.address_space(), Parent::Env::pd() }; + + Attached_stack_area stack_area { parent, pd.rpc_cap() }; + + Platform() + { + env_stack_area_ram_allocator = &pd; + env_stack_area_region_map = &stack_area; + } +}; + +#endif /* _INCLUDE__BASE__INTERNAL__PLATFORM_H_ */ diff --git a/repos/base/src/include/base/internal/platform_env.h b/repos/base/src/include/base/internal/platform_env.h deleted file mode 100644 index a4919ff640..0000000000 --- a/repos/base/src/include/base/internal/platform_env.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * \brief Platform environment of Genode process - * \author Norman Feske - * \author Christian Helmuth - * \date 2006-07-28 - * - * This file is a generic variant of the platform environment, which is - * suitable for platforms such as L4ka::Pistachio and L4/Fiasco. On other - * platforms, it may be replaced by a platform-specific version residing - * in the corresponding 'base-' repository. - */ - -/* - * Copyright (C) 2006-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _INCLUDE__BASE__INTERNAL__PLATFORM_ENV_H_ -#define _INCLUDE__BASE__INTERNAL__PLATFORM_ENV_H_ - -/* Genode includes */ -#include -#include -#include -#include - -/* base-internal includes */ -#include -#include -#include -#include -#include -#include -#include - - -namespace Genode { - - class Platform_env_base : public Env_deprecated { }; - class Platform_env; -} - - -class Genode::Platform_env : public Platform_env_base -{ - private: - - Expanding_parent_client _parent_client; - - struct Resources - { - template - Capability request(Parent &parent, Parent::Client::Id id) - { - return static_cap_cast(parent.session_cap(id)); - } - - Expanding_pd_session_client pd; - Expanding_cpu_session_client cpu; - Expanding_region_map_client rm; - - Resources(Parent &parent) - : - pd (parent, request (parent, Parent::Env::pd())), - cpu(parent, request(parent, Parent::Env::cpu()), - Parent::Env::cpu()), - rm(parent, pd.rpc_cap(), pd.address_space(), Parent::Env::pd()) - { } - }; - - Resources _resources; - - Heap _heap; - - /* - * The '_heap' must be initialized before the '_stack_area' - * because the 'Local_parent' performs a dynamic memory allocation - * due to the creation of the stack area's sub-RM session. - */ - Attached_stack_area _stack_area { _parent_client, _resources.pd.rpc_cap() }; - - public: - - /** - * Standard constructor - */ - Platform_env() - : - _parent_client(Genode::parent_cap()), - _resources(_parent_client), - _heap(&_resources.pd, &_resources.rm, Heap::UNLIMITED) - { - env_stack_area_ram_allocator = &_resources.pd; - env_stack_area_region_map = &_stack_area; - } - - - /****************************** - ** Env_deprecated interface ** - ******************************/ - - Parent *parent() override { return &_parent_client; } - Cpu_session *cpu_session() override { return &_resources.cpu; } - Cpu_session_capability cpu_session_cap() override { return _resources.cpu.rpc_cap(); } - Pd_session *pd_session() override { return &_resources.pd; } - Pd_session_capability pd_session_cap() override { return _resources.pd.rpc_cap(); } - Region_map *rm_session() override { return &_resources.rm; } -}; - -#endif /* _INCLUDE__BASE__INTERNAL__PLATFORM_ENV_H_ */ diff --git a/repos/base/src/include/base/internal/stack.h b/repos/base/src/include/base/internal/stack.h index c2f13382c7..0c5cd82ca9 100644 --- a/repos/base/src/include/base/internal/stack.h +++ b/repos/base/src/include/base/internal/stack.h @@ -74,7 +74,7 @@ class Genode::Stack { public: - typedef Cpu_session::Name Name; + using Name = Cpu_session::Name; private: diff --git a/repos/base/src/include/base/internal/trace_control.h b/repos/base/src/include/base/internal/trace_control.h index e185d16f64..3dcd244644 100644 --- a/repos/base/src/include/base/internal/trace_control.h +++ b/repos/base/src/include/base/internal/trace_control.h @@ -145,7 +145,7 @@ class Genode::Trace::Control void trace() { - _policy_version++; + _policy_version = _policy_version + 1; enable(); } diff --git a/repos/base/src/include/base/internal/unmanaged_singleton.h b/repos/base/src/include/base/internal/unmanaged_singleton.h index 3ad243a810..0909cd5d71 100644 --- a/repos/base/src/include/base/internal/unmanaged_singleton.h +++ b/repos/base/src/include/base/internal/unmanaged_singleton.h @@ -54,8 +54,8 @@ struct Unmanaged_singleton_constructor /** * Call the constructor of 'T' with arguments 'args' at 'dst' */ - template - static void call(char * const dst, ARGS &&... args) { new (dst) T(args...); } + template + static void call(char * const dst, auto &&... args) { new (dst) T(args...); } }; /** @@ -67,8 +67,8 @@ struct Unmanaged_singleton_constructor * * \return object pointer */ -template -static inline T * unmanaged_singleton(ARGS &&... args) +template +static inline T * unmanaged_singleton(auto &&... args) { /* * Each instantiation of the function template with a different type 'T' diff --git a/repos/base/src/include/base/internal/upgradeable_client.h b/repos/base/src/include/base/internal/upgradeable_client.h index 3bfeb97a21..3137e22af8 100644 --- a/repos/base/src/include/base/internal/upgradeable_client.h +++ b/repos/base/src/include/base/internal/upgradeable_client.h @@ -26,7 +26,7 @@ namespace Genode { template struct Upgradeable_client; } template struct Genode::Upgradeable_client : CLIENT { - typedef Genode::Capability Capability; + using Capability = Genode::Capability; Parent &_parent; Parent::Client::Id _id; diff --git a/repos/base/src/include/base/internal/xoroshiro.h b/repos/base/src/include/base/internal/xoroshiro.h new file mode 100644 index 0000000000..aadd2e398d --- /dev/null +++ b/repos/base/src/include/base/internal/xoroshiro.h @@ -0,0 +1,66 @@ +/* + * \brief Xoroshiro pseudo random-number generator + * \author Josef Soentgen + * \date 2022-05-19 + * + * Based on Xoroshiro128+ written in 2014-2016 by Sebastiano Vigna (vigna@acm.org) + * + * (see http://xoroshiro.di.unimi.it/xorshift128plus.c and + * http://xoroshiro.di.unimi.it/splitmix64.c) + */ + +/* + * Copyright (C) 2022 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _INCLUDE__BASE__INTERNAL__XOROSHIRO_H_ +#define _INCLUDE__BASE__INTERNAL__XOROSHIRO_H_ + +#include + +namespace Genode { class Xoroshiro_128_plus; } + + +class Genode::Xoroshiro_128_plus +{ + private: + + uint64_t _seed; + uint64_t _s[2] { _splitmix64(), _splitmix64() }; + + uint64_t _splitmix64() + { + uint64_t z = (_seed += __UINT64_C(0x9E3779B97F4A7C15)); + z = (z ^ (z >> 30)) * __UINT64_C(0xBF58476D1CE4E5B9); + z = (z ^ (z >> 27)) * __UINT64_C(0x94D049BB133111EB); + return z ^ (z >> 31); + } + + static uint64_t _rotl(uint64_t const x, int const k) + { + return (x << k) | (x >> (64 - k)); + } + + public: + + Xoroshiro_128_plus(uint64_t seed) : _seed(seed) { } + + uint64_t value() + { + uint64_t const s0 = _s[0]; + uint64_t s1 = _s[1]; + uint64_t const result = s0 + s1; + + s1 ^= s0; + + _s[0] = _rotl(s0, 55) ^ s1 ^ (s1 << 14); + _s[1] = _rotl(s1, 36); + + return result; + } +}; + +#endif /* _INCLUDE__BASE__INTERNAL__XOROSHIRO_H_ */ diff --git a/repos/base/src/include/pager/capability.h b/repos/base/src/include/pager/capability.h index efd441b0ce..997c8f618a 100644 --- a/repos/base/src/include/pager/capability.h +++ b/repos/base/src/include/pager/capability.h @@ -16,15 +16,4 @@ #include -namespace Genode { - - /* - * The 'Pager_capability' type is returned by 'Region_map::add_client' and - * passed as argument to 'Cpu_session::set_pager'. It is never invoked or - * otherwise used. - */ - class Pager_object; - typedef Capability Pager_capability; -} - #endif /* _INCLUDE__PAGER__CAPABILITY_H_ */ diff --git a/repos/base/src/include/signal_source/capability.h b/repos/base/src/include/signal_source/capability.h deleted file mode 100644 index 0364ad7bc1..0000000000 --- a/repos/base/src/include/signal_source/capability.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * \brief Signal-source capability type - * \author Norman Feske - * \date 2016-01-04 - */ - -/* - * Copyright (C) 2016-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _INCLUDE__SIGNAL_SOURCE__CAPABILITY_H_ -#define _INCLUDE__SIGNAL_SOURCE__CAPABILITY_H_ - -#include -#include - -namespace Genode { typedef Capability Signal_source_capability; } - -#endif /* _INCLUDE__SIGNAL_SOURCE__CAPABILITY_H_ */ diff --git a/repos/base/src/include/signal_source/client.h b/repos/base/src/include/signal_source/client.h index 42f5f9672f..949b396adf 100644 --- a/repos/base/src/include/signal_source/client.h +++ b/repos/base/src/include/signal_source/client.h @@ -16,13 +16,14 @@ #include #include +#include #include namespace Genode { class Signal_source_client; } struct Genode::Signal_source_client : Rpc_client { - Signal_source_client(Capability signal_source) + Signal_source_client(Cpu_session &, Capability signal_source) : Rpc_client(signal_source) { } Signal wait_for_signal() override { return call(); } diff --git a/repos/base/src/ld/genode.ld b/repos/base/src/ld/genode.ld index db72891a67..ee68971b0b 100644 --- a/repos/base/src/ld/genode.ld +++ b/repos/base/src/ld/genode.ld @@ -33,14 +33,18 @@ SECTIONS *(.text .text.* .gnu.linkonce.t.*) *(.fini) *(.rodata .rodata.* .gnu.linkonce.r.*) + } : ro = 0x0 - . = ALIGN(0x08); + . = ALIGN(0x08); + .ctors : { _ctors_start = .; KEEP (*(.ctors)) KEEP (*(SORT(.ctors.*))) KEEP (*(.init_array)) /* list of constructors specific for ARM eabi */ _ctors_end = .; + } : ro = 0x0 + .dtors : { _dtors_start = .; KEEP (*(SORT(.dtors.*))) KEEP (*(.dtors)) @@ -84,6 +88,9 @@ SECTIONS *(.data .gnu.linkonce.d.*) + __dso_handle = .; + LONG(0x0); + /* include all data subsections except those of the boot modules */ *(EXCLUDE_FILE (*boot_modules.o) .data.*) } : rw diff --git a/repos/base/src/ld/genode_dyn.dl b/repos/base/src/ld/genode_dyn.dl index c063c5617d..9f5149bc20 100644 --- a/repos/base/src/ld/genode_dyn.dl +++ b/repos/base/src/ld/genode_dyn.dl @@ -15,5 +15,4 @@ _dtors_end; _ZN9Component9constructERN6Genode3EnvE; _ZN9Component10stack_sizeEv; - main; }; diff --git a/repos/base/src/ld/genode_dyn.ld b/repos/base/src/ld/genode_dyn.ld index 57ec92f0f6..ce35f023c1 100644 --- a/repos/base/src/ld/genode_dyn.ld +++ b/repos/base/src/ld/genode_dyn.ld @@ -34,16 +34,15 @@ SECTIONS /* * The ELF entry point is unused for dynamically linked components. The - * dynamic linker determined the entry point by looking up the symbol of - * the 'Component::construct' function or - if it does not exist - the - * 'main' function (for legacy components). + * dynamic linker determines the entry point by looking up the symbol of + * the 'Component::construct' function. * * \deprecated The support for legacy main functions will be removed. * * The 'KEEP' directive prevents text that is reachable from one of the * possible entry points from being garbage collected. */ - KEEP(*(.text._ZN9Component9constructERN6Genode3EnvE .text.main)) + KEEP(*(.text._ZN9Component9constructERN6Genode3EnvE)) *(.text .stub .text.* .gnu.linkonce.t.*) @@ -212,17 +211,6 @@ SECTIONS } .jcr : { KEEP (*(.jcr)) } .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) } - .dynamic : - { - *(.dynamic) - - /* - * Make sure to have a least one entry within the dynamic section, so the - * dynamic sgement point to something valid in case there are no dynamic - * symbols - */ - LONG(0x0); - } : rw : dynamic /* merge .got.plt and .got into .got, since the ARM toolchain for OKL4 * set's * DT_PLTGOT to .got instead of .got.plt */ @@ -247,6 +235,20 @@ SECTIONS LONG(0x0); } .data1 : { *(.data1) } + + .dynamic : + { + *(.dynamic) + + /* + * Make sure to have a least one entry within the dynamic section, so the + * dynamic segment points to something valid in case there are no dynamic + * symbols in a binary. These semi-static binaries are not supported by + * our dynamic linker that depends on the .dynamic section. + */ + LONG(0x0); + } : rw : dynamic + _edata = .; PROVIDE (edata = .); __bss_start = .; .bss : @@ -264,7 +266,7 @@ SECTIONS * pad the .data section. */ . = ALIGN(. != 0 ? 32 / 8 : 1); - } + } : rw . = ALIGN(32 / 8); . = ALIGN(32 / 8); _end = .; PROVIDE (end = .); diff --git a/repos/base/src/ld/genode_rel.ld b/repos/base/src/ld/genode_rel.ld index 9b5add9066..85c44dfb93 100644 --- a/repos/base/src/ld/genode_rel.ld +++ b/repos/base/src/ld/genode_rel.ld @@ -15,10 +15,10 @@ PHDRS { - ro PT_LOAD; - rw PT_LOAD; - dynamic PT_DYNAMIC; - eh_frame PT_GNU_EH_FRAME; + ro PT_LOAD; + rw PT_LOAD; + dynamic PT_DYNAMIC; + eh_frame PT_GNU_EH_FRAME; } SECTIONS @@ -97,7 +97,7 @@ SECTIONS { /* * Leave space for parent capability parameters at start of data - * section. The protection domain creator is reponsible for storing + * section. The protection-domain creator is reponsible for storing * sane values here. */ _parent_cap = .; @@ -130,6 +130,7 @@ SECTIONS .ARM.extab : { *(.ARM.extab*) } + __exidx_start = .; .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) @@ -189,7 +190,6 @@ SECTIONS .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) } .data1 : { *(.data1) } - .dynamic : { *(.dynamic) } : dynamic : rw /* See: genode_dyn.ld */ .got : { *(.got.plt) *(.got) } /* Exception handling */ @@ -199,6 +199,9 @@ SECTIONS KEEP (*(.eh_frame)) LONG(0) } + + .dynamic : { *(.dynamic) } : rw : dynamic + _edata = .; PROVIDE (edata = .); __bss_start = .; .bss : @@ -216,7 +219,7 @@ SECTIONS * pad the .data section. */ . = ALIGN(. != 0 ? 32 / 8 : 1); - } + } : rw . = ALIGN(32 / 8); . = ALIGN(32 / 8); _end = .; PROVIDE (end = .); diff --git a/repos/base/src/lib/base/allocator_avl.cc b/repos/base/src/lib/base/allocator_avl.cc index d89e5c12c2..fdddc66c4d 100644 --- a/repos/base/src/lib/base/allocator_avl.cc +++ b/repos/base/src/lib/base/allocator_avl.cc @@ -171,8 +171,7 @@ void Allocator_avl_base::_cut_from_block(Block &b, addr_t addr, size_t size, Two } -template -bool Allocator_avl_base::_revert_block_ranges(FN const &any_block_fn) +bool Allocator_avl_base::_revert_block_ranges(auto const &any_block_fn) { size_t blocks = 0; for (bool loop = true; loop; blocks++) { @@ -196,7 +195,7 @@ bool Allocator_avl_base::_revert_block_ranges(FN const &any_block_fn) bool Allocator_avl_base::_revert_unused_ranges() { - return _revert_block_ranges([&] () { + return _revert_block_ranges([&] { return _find_any_unused_block(_addr_tree.first()); }); } @@ -219,7 +218,7 @@ void Allocator_avl_base::_revert_allocations_and_ranges() " at allocator destruction time"); /* destroy all remaining blocks */ - _revert_block_ranges([&] () { return _addr_tree.first(); }); + _revert_block_ranges([&] { return _addr_tree.first(); }); } @@ -309,10 +308,9 @@ Allocator_avl_base::Range_result Allocator_avl_base::remove_range(addr_t base, s } -template Allocator::Alloc_result Allocator_avl_base::_allocate(size_t const size, unsigned align, Range range, - SEARCH_FN const &search_fn) + auto const &search_fn) { return _alloc_two_blocks_metadata().convert( @@ -322,7 +320,7 @@ Allocator_avl_base::_allocate(size_t const size, unsigned align, Range range, Block *b_ptr = _addr_tree.first(); b_ptr = b_ptr ? search_fn(*b_ptr) : 0; - if (!b_ptr) { + if (!b_ptr || b_ptr->used()) { /* range conflict */ _md_alloc.free(two_blocks.b1_ptr, sizeof(Block)); _md_alloc.free(two_blocks.b2_ptr, sizeof(Block)); @@ -362,10 +360,6 @@ Allocator_avl_base::alloc_aligned(size_t size, unsigned align, Range range) Range_allocator::Alloc_result Allocator_avl_base::alloc_addr(size_t size, addr_t addr) { /* check for integer overflow */ - if (addr + size - 1 < addr) - return Alloc_error::DENIED; - - /* check for range conflict */ if (!_sum_in_range(addr, size)) return Alloc_error::DENIED; diff --git a/repos/base/src/lib/base/avl_tree.cc b/repos/base/src/lib/base/avl_tree.cc index 42d4b35c65..d890ecb763 100644 --- a/repos/base/src/lib/base/avl_tree.cc +++ b/repos/base/src/lib/base/avl_tree.cc @@ -84,6 +84,8 @@ void Avl_node_base::_rebalance_subtree(Avl_node_base *node, Policy &policy) { int v = node->_child_depth(RIGHT) - node->_child_depth(LEFT); + auto abs = [] (auto v) { return v >= 0 ? v : -v; }; + /* return if subtree is in balance */ if (abs(v) < 2) return; diff --git a/repos/base/src/lib/base/capability_slab.cc b/repos/base/src/lib/base/capability_slab.cc new file mode 100644 index 0000000000..13db351958 --- /dev/null +++ b/repos/base/src/lib/base/capability_slab.cc @@ -0,0 +1,16 @@ +/* + * \brief Capability slab init for kernels without an expandable cap space + * \author Norman Feske + * \date 2023-06-20 + */ + +/* + * Copyright (C) 2023 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#include + +void Genode::init_cap_slab(Pd_session &, Parent &) { } diff --git a/repos/base/src/lib/base/child.cc b/repos/base/src/lib/base/child.cc index 42e557a09e..98834b8a60 100644 --- a/repos/base/src/lib/base/child.cc +++ b/repos/base/src/lib/base/child.cc @@ -92,56 +92,56 @@ void Child::session_sigh(Signal_context_capability sigh) /** * Create session-state object for a dynamically created session * - * \throw Out_of_ram - * \throw Out_of_caps - * \throw Insufficient_cap_quota - * \throw Insufficient_ram_quota - * \throw Service_denied + * If successful, 'fn' is called with a new 'Session_state &' as argument. */ -Session_state & -create_session(Child_policy::Name const &child_name, Service &service, - Session_label const &label, Session::Diag diag, - Session_state::Factory &factory, Id_space &id_space, - Parent::Client::Id id, Session_state::Args const &args, - Affinity const &affinity) +Parent::Session_result +with_new_session(Child_policy::Name const &child_name, Service &service, + Session_label const &label, Session::Diag diag, + Session_state::Factory &factory, Id_space &id_space, + Parent::Client::Id id, Session_state::Args const &args, + Affinity const &affinity, + auto const &fn) { + using Error = Parent::Session_error; + + Error session_error = Error::DENIED; try { - return service.create_session(factory, id_space, id, label, diag, args, affinity); } - - catch (Insufficient_ram_quota) { - error(child_name, " requested session with insufficient RAM quota"); - throw; } - - catch (Insufficient_cap_quota) { - error(child_name, " requested session with insufficient cap quota"); - throw; } - - catch (Allocator::Out_of_memory) { - error(child_name, " session meta data could not be allocated"); - throw Out_of_ram(); } - + return fn(service.create_session(factory, id_space, id, label, diag, args, affinity)); + } + catch (Insufficient_ram_quota) { session_error = Error::INSUFFICIENT_RAM_QUOTA; } + catch (Insufficient_cap_quota) { session_error = Error::INSUFFICIENT_CAP_QUOTA; } + catch (Out_of_ram) { session_error = Error::OUT_OF_RAM; } + catch (Out_of_caps) { session_error = Error::OUT_OF_CAPS; } catch (Id_space::Conflicting_id) { error(child_name, " requested conflicting session ID ", id, " " "(service=", service.name(), " args=", args, ")"); - try { - id_space.apply(id, [&] (Session_state &session) { - error("existing session: ", session); }); - } - catch (Id_space::Unknown_id) { } + id_space.apply(id, + [&] (Session_state &session) { error("existing session: ", session); }, + [&] /* missing */ { }); } - throw Service_denied(); + + if (session_error == Error::OUT_OF_RAM || session_error == Error::OUT_OF_CAPS) + error(child_name, " session meta data could not be allocated"); + + if (session_error == Error::INSUFFICIENT_RAM_QUOTA) + error(child_name, " requested session with insufficient RAM quota"); + + if (session_error == Error::INSUFFICIENT_CAP_QUOTA) + error(child_name, " requested session with insufficient cap quota"); + + return session_error; } -Session_capability Child::session(Parent::Client::Id id, - Parent::Service_name const &name, - Parent::Session_args const &args, - Affinity const &affinity) +Parent::Session_result Child::session(Parent::Client::Id id, + Parent::Service_name const &name, + Parent::Session_args const &args, + Affinity const &affinity) { if (!name.valid_string() || !args.valid_string() || _pd.closed()) - throw Service_denied(); + return Session_error::DENIED; char argbuf[Parent::Session_args::MAX_SIZE]; @@ -165,7 +165,7 @@ Session_capability Child::session(Parent::Client::Id id, size_t const keep_ram_quota = _session_factory.session_costs(); if (ram_quota.value < keep_ram_quota) - throw Insufficient_ram_quota(); + return Session_error::INSUFFICIENT_RAM_QUOTA; /* ram quota to be forwarded to the server */ Ram_quota const forward_ram_quota { ram_quota.value - keep_ram_quota }; @@ -173,139 +173,143 @@ Session_capability Child::session(Parent::Client::Id id, /* adjust the session information as presented to the server */ Arg_string::set_arg(argbuf, sizeof(argbuf), "ram_quota", (int)forward_ram_quota.value); - /* may throw a 'Service_denied' exception */ - Child_policy::Route route = - _policy.resolve_session_request(name.string(), label, - session_diag_from_args(argbuf)); - - Service &service = route.service; - - /* propagate diag flag */ - Arg_string::set_arg(argbuf, sizeof(argbuf), "diag", route.diag.enabled); - - Session_state &session = - create_session(_policy.name(), service, route.label, route.diag, - _session_factory, _id_space, id, argbuf, filtered_affinity); - - _policy.session_state_changed(); - - session.ready_callback = this; - session.closed_callback = this; - try { - Ram_transfer::Remote_account ref_ram_account { _policy.ref_pd(), _policy.ref_pd_cap() }; - Cap_transfer::Remote_account ref_cap_account { _policy.ref_pd(), _policy.ref_pd_cap() }; + /* may throw a 'Service_denied' exception */ + Child_policy::Route route = + _policy.resolve_session_request(name.string(), label, + session_diag_from_args(argbuf)); - Ram_transfer::Remote_account ram_account { pd(), pd_session_cap() }; - Cap_transfer::Remote_account cap_account { pd(), pd_session_cap() }; + Service &service = route.service; - /* transfer the quota donation from the child's account to ourself */ - Ram_transfer ram_donation_from_child(ram_quota, ram_account, ref_ram_account); - Cap_transfer cap_donation_from_child(cap_quota, cap_account, ref_cap_account); + /* propagate diag flag */ + Arg_string::set_arg(argbuf, sizeof(argbuf), "diag", route.diag.enabled); - /* transfer session quota from ourself to the service provider */ - Ram_transfer ram_donation_to_service(forward_ram_quota, ref_ram_account, service); - Cap_transfer cap_donation_to_service(cap_quota, ref_cap_account, service); + return with_new_session(_policy.name(), service, route.label, route.diag, + _session_factory, _id_space, id, argbuf, filtered_affinity, - /* finish transaction */ - ram_donation_from_child.acknowledge(); - cap_donation_from_child.acknowledge(); - ram_donation_to_service.acknowledge(); - cap_donation_to_service.acknowledge(); + [&] (Session_state &session) -> Session_result { + + _policy.session_state_changed(); + + session.ready_callback = this; + session.closed_callback = this; + + try { + Ram_transfer::Remote_account ref_ram_account { _policy.ref_pd(), _policy.ref_pd_cap() }; + Cap_transfer::Remote_account ref_cap_account { _policy.ref_pd(), _policy.ref_pd_cap() }; + + Ram_transfer::Remote_account ram_account { pd(), pd_session_cap() }; + Cap_transfer::Remote_account cap_account { pd(), pd_session_cap() }; + + /* transfer the quota donation from the child's account to ourself */ + Ram_transfer ram_donation_from_child(ram_quota, ram_account, ref_ram_account); + Cap_transfer cap_donation_from_child(cap_quota, cap_account, ref_cap_account); + + /* transfer session quota from ourself to the service provider */ + Ram_transfer ram_donation_to_service(forward_ram_quota, ref_ram_account, service); + Cap_transfer cap_donation_to_service(cap_quota, ref_cap_account, service); + + /* finish transaction */ + ram_donation_from_child.acknowledge(); + cap_donation_from_child.acknowledge(); + ram_donation_to_service.acknowledge(); + cap_donation_to_service.acknowledge(); + } + /* + * Release session meta data if one of the quota transfers went wrong. + */ + catch (Ram_transfer::Quota_exceeded) { + session.destroy(); + return Session_error::OUT_OF_RAM; + } + catch (Cap_transfer::Quota_exceeded) { + session.destroy(); + return Session_error::OUT_OF_CAPS; + } + + /* try to dispatch session request synchronously */ + service.initiate_request(session); + + if (session.phase == Session_state::SERVICE_DENIED) { + _revert_quota_and_destroy(session); + return Session_error::DENIED; + } + + if (session.phase == Session_state::INSUFFICIENT_RAM_QUOTA) { + _revert_quota_and_destroy(session); + return Session_error::INSUFFICIENT_RAM_QUOTA; + } + + if (session.phase == Session_state::INSUFFICIENT_CAP_QUOTA) { + _revert_quota_and_destroy(session); + return Session_error::INSUFFICIENT_CAP_QUOTA; + } + + /* + * Copy out the session cap before we are potentially kicking off the + * asynchonous request handling at the server to avoid doule-read + * issues with the session.cap, which will be asynchronously assigned + * by the server side. + */ + Session_capability cap = session.cap; + + /* if request was not handled synchronously, kick off async operation */ + if (session.phase == Session_state::CREATE_REQUESTED) + service.wakeup(); + + if (cap.valid()) + session.phase = Session_state::CAP_HANDED_OUT; + + return cap; + } + ); } - /* - * Release session meta data if one of the quota transfers went wrong. - */ - catch (Ram_transfer::Quota_exceeded) { - session.destroy(); - throw Out_of_ram(); - } - catch (Cap_transfer::Quota_exceeded) { - session.destroy(); - throw Out_of_caps(); - } - - /* try to dispatch session request synchronously */ - service.initiate_request(session); - - if (session.phase == Session_state::SERVICE_DENIED) { - _revert_quota_and_destroy(session); - throw Service_denied(); - } - - if (session.phase == Session_state::INSUFFICIENT_RAM_QUOTA) { - _revert_quota_and_destroy(session); - throw Insufficient_ram_quota(); - } - - if (session.phase == Session_state::INSUFFICIENT_CAP_QUOTA) { - _revert_quota_and_destroy(session); - throw Insufficient_cap_quota(); - } - - /* - * Copy out the session cap before we are potentially kicking off the - * asynchonous request handling at the server to avoid doule-read - * issues with the session.cap, which will be asynchronously assigned - * by the server side. - */ - Session_capability cap = session.cap; - - /* if request was not handled synchronously, kick off async operation */ - if (session.phase == Session_state::CREATE_REQUESTED) - service.wakeup(); - - if (cap.valid()) - session.phase = Session_state::CAP_HANDED_OUT; - - return cap; + catch (Service_denied) { return Session_error::DENIED; } } -Session_capability Child::session_cap(Client::Id id) +Parent::Session_cap_result Child::session_cap(Client::Id id) { - Session_capability cap; + return _id_space.apply(id, - auto lamda = [&] (Session_state &session) { + [&] (Session_state &session) -> Session_cap_result { - if (session.phase == Session_state::SERVICE_DENIED - || session.phase == Session_state::INSUFFICIENT_RAM_QUOTA - || session.phase == Session_state::INSUFFICIENT_CAP_QUOTA) { + if (session.phase == Session_state::SERVICE_DENIED + || session.phase == Session_state::INSUFFICIENT_RAM_QUOTA + || session.phase == Session_state::INSUFFICIENT_CAP_QUOTA) { - Session_state::Phase const phase = session.phase; + Session_state::Phase const phase = session.phase; - /* - * Implicity discard the session request when delivering an - * exception because the exception will trigger the deallocation - * of the session ID at the child anyway. - */ - _revert_quota_and_destroy(session); + /* + * Implicity discard the session request when delivering an + * exception because the exception will trigger the deallocation + * of the session ID at the child anyway. + */ + _revert_quota_and_destroy(session); - switch (phase) { - case Session_state::SERVICE_DENIED: throw Service_denied(); - case Session_state::INSUFFICIENT_RAM_QUOTA: throw Insufficient_ram_quota(); - case Session_state::INSUFFICIENT_CAP_QUOTA: throw Insufficient_cap_quota(); - default: break; + switch (phase) { + case Session_state::SERVICE_DENIED: return Session_cap_error::DENIED; + case Session_state::INSUFFICIENT_RAM_QUOTA: return Session_cap_error::INSUFFICIENT_RAM_QUOTA; + case Session_state::INSUFFICIENT_CAP_QUOTA: return Session_cap_error::INSUFFICIENT_CAP_QUOTA; + default: break; + } } + + if (!session.alive()) + warning(_policy.name(), ": attempt to request cap for unavailable session: ", session); + + if (session.cap.valid()) + session.phase = Session_state::CAP_HANDED_OUT; + + _policy.session_state_changed(); + + return session.cap; + }, + [&] /* missing */ { + warning(_policy.name(), " requested session cap for unknown ID"); + return Session_capability(); } - - if (!session.alive()) - warning(_policy.name(), ": attempt to request cap for unavailable session: ", session); - - if (session.cap.valid()) - session.phase = Session_state::CAP_HANDED_OUT; - - cap = session.cap; - }; - - try { - _id_space.apply(id, lamda); } - - catch (Id_space::Unknown_id) { - warning(_policy.name(), " requested session cap for unknown ID"); } - - _policy.session_state_changed(); - return cap; + ); } @@ -313,14 +317,16 @@ Parent::Upgrade_result Child::upgrade(Client::Id id, Parent::Upgrade_args const { if (!args.valid_string()) { warning("no valid session-upgrade arguments"); - return UPGRADE_DONE; + return Upgrade_result::OK; } /* ignore suprious request that may arrive after 'close_all_sessions' */ if (_pd.closed()) - return UPGRADE_PENDING; + return Upgrade_result::PENDING; - Upgrade_result result = UPGRADE_PENDING; + Upgrade_result result = Upgrade_result::PENDING; + + bool session_state_changed = false; auto upgrade_session = [&] (Session_state &session) { @@ -354,6 +360,7 @@ Parent::Upgrade_result Child::upgrade(Client::Id id, Parent::Upgrade_args const session.phase = Session_state::UPGRADE_REQUESTED; session.service().initiate_request(session); + session_state_changed = true; /* finish transaction */ ram_donation_from_child.acknowledge(); @@ -363,26 +370,27 @@ Parent::Upgrade_result Child::upgrade(Client::Id id, Parent::Upgrade_args const } catch (Ram_transfer::Quota_exceeded) { warning(_policy.name(), ": RAM upgrade of ", session.service().name(), " failed"); - throw Out_of_ram(); + result = Upgrade_result::OUT_OF_RAM; + return; } catch (Cap_transfer::Quota_exceeded) { warning(_policy.name(), ": cap upgrade of ", session.service().name(), " failed"); - throw Out_of_caps(); + result = Upgrade_result::OUT_OF_CAPS; + return; } - if (session.phase == Session_state::CAP_HANDED_OUT) { - result = UPGRADE_DONE; + result = Upgrade_result::OK; _policy.session_state_changed(); return; } - session.service().wakeup(); }; - try { _id_space.apply(id, upgrade_session); } - catch (Id_space::Unknown_id) { } + _id_space.apply(id, upgrade_session, [&] /* missing */ { }); + + if (session_state_changed) + _policy.session_state_changed(); - _policy.session_state_changed(); return result; } @@ -445,7 +453,7 @@ Child::Close_result Child::_close(Session_state &session) || session.phase == Session_state::INSUFFICIENT_RAM_QUOTA || session.phase == Session_state::INSUFFICIENT_CAP_QUOTA) { _revert_quota_and_destroy(session); - return CLOSE_DONE; + return Close_result::DONE; } /* close session if alive */ @@ -462,14 +470,14 @@ Child::Close_result Child::_close(Session_state &session) if (session.phase == Session_state::CLOSED) { _revert_quota_and_destroy(session); - return CLOSE_DONE; + return Close_result::DONE; } _policy.session_state_changed(); session.service().wakeup(); - return CLOSE_PENDING; + return Close_result::PENDING; } @@ -477,15 +485,11 @@ Child::Close_result Child::close(Client::Id id) { /* refuse to close the child's initial sessions */ if (Parent::Env::session_id(id)) - return CLOSE_DONE; + return Close_result::DONE; - try { - Close_result result = CLOSE_PENDING; - auto lamda = [&] (Session_state &session) { result = _close(session); }; - _id_space.apply(id, lamda); - return result; - } - catch (Id_space::Unknown_id) { return CLOSE_DONE; } + return _id_space.apply(id, + [&] (Session_state &session) -> Close_result { return _close(session); }, + [&] /* missing */ { return Close_result::DONE; }); } @@ -515,132 +519,127 @@ void Child::session_closed(Session_state &session) void Child::session_response(Server::Id id, Session_response response) { - try { - _policy.server_id_space().apply(id, [&] (Session_state &session) { + _policy.server_id_space().apply(id, [&] (Session_state &session) { - switch (response) { + switch (response) { - case Parent::SESSION_CLOSED: - session.phase = Session_state::CLOSED; + case Parent::SESSION_CLOSED: + session.phase = Session_state::CLOSED; + + /* + * If the client exists, reflect the response to the client + * via the 'closed_callback'. If the client has vanished, + * i.e., if the close request was issued by ourself while + * killing a child, we drop the session state immediately. + */ + if (session.closed_callback) { + session.closed_callback->session_closed(session); + + } else { /* - * If the client exists, reflect the response to the client - * via the 'closed_callback'. If the client has vanished, - * i.e., if the close request was issued by ourself while - * killing a child, we drop the session state immediately. + * The client no longer exists. So we cannot take the + * regular path of executing '_revert_quota_and_destroy' in + * the context of the client. Instead, we immediately + * withdraw the session quota from the server ('this') to + * the reference account, and destroy the session object. */ - if (session.closed_callback) { - session.closed_callback->session_closed(session); + Ram_transfer::Remote_account ref_ram_account(_policy.ref_pd(), _policy.ref_pd_cap()); + Ram_transfer::Account &service_ram_account = session.service(); - } else { + Cap_transfer::Remote_account ref_cap_account(_policy.ref_pd(), _policy.ref_pd_cap()); + Cap_transfer::Account &service_cap_account = session.service(); - /* - * The client no longer exists. So we cannot take the - * regular path of executing '_revert_quota_and_destroy' in - * the context of the client. Instead, we immediately - * withdraw the session quota from the server ('this') to - * the reference account, and destroy the session object. - */ - Ram_transfer::Remote_account ref_ram_account(_policy.ref_pd(), _policy.ref_pd_cap()); - Ram_transfer::Account &service_ram_account = session.service(); + try { + /* transfer session quota from the service to ourself */ + Ram_transfer ram_donation_from_service(session.donated_ram_quota(), + service_ram_account, ref_ram_account); - Cap_transfer::Remote_account ref_cap_account(_policy.ref_pd(), _policy.ref_pd_cap()); - Cap_transfer::Account &service_cap_account = session.service(); + Cap_transfer cap_donation_from_service(session.donated_cap_quota(), + service_cap_account, ref_cap_account); - try { - /* transfer session quota from the service to ourself */ - Ram_transfer ram_donation_from_service(session.donated_ram_quota(), - service_ram_account, ref_ram_account); - - Cap_transfer cap_donation_from_service(session.donated_cap_quota(), - service_cap_account, ref_cap_account); - - ram_donation_from_service.acknowledge(); - cap_donation_from_service.acknowledge(); - } - catch (Ram_transfer::Quota_exceeded) { - warning(_policy.name(), " failed to return session RAM quota " - "(", session.donated_ram_quota(), ")"); } - catch (Cap_transfer::Quota_exceeded) { - warning(_policy.name(), " failed to return session cap quota " - "(", session.donated_cap_quota(), ")"); } - - session.destroy(); - _policy.session_state_changed(); + ram_donation_from_service.acknowledge(); + cap_donation_from_service.acknowledge(); } - break; + catch (Ram_transfer::Quota_exceeded) { + warning(_policy.name(), " failed to return session RAM quota " + "(", session.donated_ram_quota(), ")"); } + catch (Cap_transfer::Quota_exceeded) { + warning(_policy.name(), " failed to return session cap quota " + "(", session.donated_cap_quota(), ")"); } - case Parent::SERVICE_DENIED: - session.phase = Session_state::SERVICE_DENIED; - if (session.ready_callback) - session.ready_callback->session_ready(session); - break; - - case Parent::INSUFFICIENT_RAM_QUOTA: - session.phase = Session_state::INSUFFICIENT_RAM_QUOTA; - if (session.ready_callback) - session.ready_callback->session_ready(session); - break; - - case Parent::INSUFFICIENT_CAP_QUOTA: - session.phase = Session_state::INSUFFICIENT_CAP_QUOTA; - if (session.ready_callback) - session.ready_callback->session_ready(session); - break; - - case Parent::SESSION_OK: - if (session.phase == Session_state::UPGRADE_REQUESTED) { - session.phase = Session_state::CAP_HANDED_OUT; - if (session.ready_callback) - session.ready_callback->session_ready(session); - } - break; + session.destroy(); + _policy.session_state_changed(); } - }); - } - catch (Child_policy::Nonexistent_id_space) { } - catch (Id_space::Unknown_id) { - warning("unexpected session response for unknown session"); } + break; + + case Parent::SERVICE_DENIED: + session.phase = Session_state::SERVICE_DENIED; + if (session.ready_callback) + session.ready_callback->session_ready(session); + break; + + case Parent::INSUFFICIENT_RAM_QUOTA: + session.phase = Session_state::INSUFFICIENT_RAM_QUOTA; + if (session.ready_callback) + session.ready_callback->session_ready(session); + break; + + case Parent::INSUFFICIENT_CAP_QUOTA: + session.phase = Session_state::INSUFFICIENT_CAP_QUOTA; + if (session.ready_callback) + session.ready_callback->session_ready(session); + break; + + case Parent::SESSION_OK: + if (session.phase == Session_state::UPGRADE_REQUESTED) { + session.phase = Session_state::CAP_HANDED_OUT; + if (session.ready_callback) + session.ready_callback->session_ready(session); + } + break; + } + }, + [&] /* missing ID */ { + warning("unexpected session response for unknown session"); + }); } void Child::deliver_session_cap(Server::Id id, Session_capability cap) { - try { - _policy.server_id_space().apply(id, [&] (Session_state &session) { + _policy.server_id_space().apply(id, [&] (Session_state &session) { - /* ignore responses after 'close_all_sessions' of the client */ - if (session.phase != Session_state::CREATE_REQUESTED) - return; + /* ignore responses after 'close_all_sessions' of the client */ + if (session.phase != Session_state::CREATE_REQUESTED) + return; - if (session.cap.valid()) { - _error("attempt to assign session cap twice"); - return; - } + if (session.cap.valid()) { + _error("attempt to assign session cap twice"); + return; + } - /* - * If the client vanished during the session creation, the - * session-close state change must be reflected to the server - * as soon as the session becomes available. This enables the - * server to wind down the session. If we just discarded the - * session, the server's ID space would become inconsistent - * with ours. - */ - if (!session.client_exists()) { - session.phase = Session_state::CLOSE_REQUESTED; - session.service().initiate_request(session); - return; - } + /* + * If the client vanished during the session creation, the + * session-close state change must be reflected to the server + * as soon as the session becomes available. This enables the + * server to wind down the session. If we just discarded the + * session, the server's ID space would become inconsistent + * with ours. + */ + if (!session.client_exists()) { + session.phase = Session_state::CLOSE_REQUESTED; + session.service().initiate_request(session); + return; + } - session.cap = cap; - session.phase = Session_state::AVAILABLE; + session.cap = cap; + session.phase = Session_state::AVAILABLE; - if (session.ready_callback) - session.ready_callback->session_ready(session); - }); - } - catch (Child_policy::Nonexistent_id_space) { } - catch (Id_space::Unknown_id) { } + if (session.ready_callback) + session.ready_callback->session_ready(session); + }, + [&] /* missing ID */ { }); } @@ -731,30 +730,6 @@ void Child::heartbeat_sigh(Signal_context_capability sigh) void Child::heartbeat_response() { _outstanding_heartbeats = 0; } -namespace { - - /** - * Return interface for interacting with the child's address space - * - * Depending on the return value of 'Child_policy::address_space', we - * either interact with a local object of via an RPC client stub. - */ - struct Child_address_space - { - Region_map_client _rm_client; - Region_map &_rm; - - Child_address_space(Pd_session &pd, Child_policy &policy) - : - _rm_client(pd.address_space()), - _rm(policy.address_space(pd) ? *policy.address_space(pd) : _rm_client) - { } - - Region_map ®ion_map() { return _rm; } - }; -} - - void Child::_try_construct_env_dependent_members() { /* check if the environment sessions are complete */ @@ -779,36 +754,40 @@ void Child::_try_construct_env_dependent_members() if (session.phase == Session_state::AVAILABLE) session.phase = Session_state::CAP_HANDED_OUT; }); - if (_process.constructed()) + if (_start_result == Start_result::OK || _start_result == Start_result::INVALID) return; _policy.init(_cpu.session(), _cpu.cap()); - Process::Type const type = _policy.forked() - ? Process::TYPE_FORKED : Process::TYPE_LOADED; try { _initial_thread.construct(_cpu.session(), _pd.cap(), _policy.name()); - _process.construct(type, _linker_dataspace(), _pd.session(), - *_initial_thread, _local_rm, - Child_address_space(_pd.session(), _policy).region_map(), - cap()); } - catch (Out_of_ram) { _error("out of RAM during ELF loading"); } - catch (Out_of_caps) { _error("out of caps during ELF loading"); } - catch (Cpu_session::Thread_creation_failed) { _error("unable to create initial thread"); } - catch (Process::Missing_dynamic_linker) { _error("dynamic linker unavailable"); } - catch (Process::Invalid_executable) { _error("invalid ELF executable"); } - catch (Region_map::Invalid_dataspace) { _error("ELF loading failed (Invalid_dataspace)"); } - catch (Region_map::Region_conflict) { _error("ELF loading failed (Region_conflict)"); } + catch (Out_of_ram) { _error("out of RAM while creating initial child thread"); } + catch (Out_of_caps) { _error("out of caps while creating initial child thread"); } + + _pd.session().assign_parent(cap()); + + if (_policy.forked()) { + _start_result = Start_result::OK; + } else { + _policy.with_address_space(_pd.session(), [&] (Region_map &address_space) { + _start_result = _start_process(_linker_dataspace(), _pd.session(), + *_initial_thread, _initial_thread_start, + _local_rm, address_space, cap()); + }); + } + + if (_start_result == Start_result::OUT_OF_RAM) _error("out of RAM during ELF loading"); + if (_start_result == Start_result::OUT_OF_CAPS) _error("out of caps during ELF loading"); + if (_start_result == Start_result::INVALID) _error("attempt to load an invalid executable"); } void Child::_discard_env_session(Id_space::Id id) { - auto discard_id_fn = [&] (Session_state &s) { s.discard_id_at_client(); }; - - try { _id_space.apply(id, discard_id_fn); } - catch (Id_space::Unknown_id) { } + _id_space.apply(id, + [&] (Session_state &s) { s.discard_id_at_client(); }, + [&] /* missing */ { }); } @@ -874,7 +853,7 @@ void Child::close_all_sessions() Close_result const close_result = close(Parent::Client::Id{id_value}); /* break infinte loop if CPU session is provided by a child */ - if (close_result != CLOSE_DONE) + if (close_result != Close_result::DONE) break; } @@ -899,11 +878,8 @@ void Child::close_all_sessions() * with the server. So the added complexity of reverting the session quotas * would be to no benefit. */ - try { - auto lambda = [&] (Session_state &s) { _revert_quota_and_destroy(s); }; - while (_policy.server_id_space().apply_any(lambda)); - } - catch (Child_policy::Nonexistent_id_space) { } + auto lambda = [&] (Session_state &s) { _revert_quota_and_destroy(s); }; + while (_policy.server_id_space().apply_any(lambda)); /* * Issue close requests to the providers of the environment sessions, @@ -913,7 +889,6 @@ void Child::close_all_sessions() _binary.close(); if (_linker.constructed()) _linker->close(); - _pd.close(); /* * Remove statically created env sessions from the child's ID space. @@ -933,12 +908,14 @@ void Child::close_all_sessions() Close_result const close_result = _close(session); - if (close_result == CLOSE_PENDING) + if (close_result == Close_result::PENDING) session.discard_id_at_client(); }; while (_id_space.apply_any(close_fn)); + _pd.close(); + if (!KERNEL_SUPPORTS_EAGER_CHILD_DESTRUCTION) _cpu._connection.destruct(); } @@ -960,6 +937,4 @@ Child::Child(Region_map &local_rm, Child::~Child() { close_all_sessions(); - _process.destruct(); } - diff --git a/repos/base/src/lib/base/child_process.cc b/repos/base/src/lib/base/child_process.cc index 4eb488879f..89f56ad012 100644 --- a/repos/base/src/lib/base/child_process.cc +++ b/repos/base/src/lib/base/child_process.cc @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2006-2017 Genode Labs GmbH + * Copyright (C) 2006-2024 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -24,33 +24,35 @@ using namespace Genode; -Child::Process::Loaded_executable::Loaded_executable(Type type, - Dataspace_capability ldso_ds, - Ram_allocator &ram, - Region_map &local_rm, - Region_map &remote_rm, - Parent_capability parent_cap) +Child::Load_result Child::_load_static_elf(Dataspace_capability elf_ds, + Ram_allocator &ram, + Region_map &local_rm, + Region_map &remote_rm, + Parent_capability parent_cap) { - /* skip loading when called during fork */ - if (type == TYPE_FORKED) - return; + addr_t const elf_addr = local_rm.attach(elf_ds, Region_map::Attr{}).convert( + [&] (Region_map::Range range) { return range.start; }, + [&] (Region_map::Attach_error const e) -> addr_t { + if (e == Region_map::Attach_error::INVALID_DATASPACE) + error("dynamic linker is an invalid dataspace"); + if (e == Region_map::Attach_error::REGION_CONFLICT) + error("region conflict while attaching dynamic linker"); + return 0; }); - /* locally attach ELF binary of the dynamic linker */ - if (!ldso_ds.valid()) { - error("attempt to start dynamic executable without dynamic linker"); - throw Missing_dynamic_linker(); - } + if (!elf_addr) + return Load_error::INVALID; - addr_t elf_addr = 0; - try { elf_addr = local_rm.attach(ldso_ds); } - catch (Region_map::Invalid_dataspace) { - error("dynamic linker is an invalid dataspace"); throw; } - catch (Region_map::Region_conflict) { - error("region conflict while attaching dynamic linker"); throw; } + /* detach ELF binary from local address space when leaving the scope */ + struct Elf_detach_guard + { + Region_map &local_rm; + addr_t const addr; + ~Elf_detach_guard() { local_rm.detach(addr); } + } elf_detach_guard { .local_rm = local_rm, .addr = elf_addr }; Elf_binary elf(elf_addr); - entry = elf.entry(); + Entry const entry { elf.entry() }; /* setup region map for the new pd */ Elf_segment seg; @@ -66,7 +68,6 @@ Child::Process::Loaded_executable::Loaded_executable(Type type, size_t const size = seg.mem_size(); bool const write = seg.flags().w; - bool const exec = seg.flags().x; if (write) { @@ -83,20 +84,35 @@ Child::Process::Loaded_executable::Loaded_executable(Type type, */ /* alloc dataspace */ - Dataspace_capability ds_cap; - try { ds_cap = ram.alloc(size); } - catch (Out_of_ram) { - error("allocation of read-write segment failed"); throw; }; + Ram_allocator::Alloc_result const alloc_result = ram.try_alloc(size); + + if (alloc_result.failed()) + error("allocation of read-write segment failed"); + + using Alloc_error = Ram_allocator::Alloc_error; + + if (alloc_result == Alloc_error::OUT_OF_RAM) return Load_error::OUT_OF_RAM; + if (alloc_result == Alloc_error::OUT_OF_CAPS) return Load_error::OUT_OF_CAPS; + if (alloc_result.failed()) return Load_error::INVALID; + + Dataspace_capability ds_cap = alloc_result.convert( + [&] (Ram_dataspace_capability cap) { return cap; }, + [&] (Alloc_error) { /* handled above */ return Dataspace_capability(); }); /* attach dataspace */ - void *base; - try { base = local_rm.attach(ds_cap); } - catch (Region_map::Invalid_dataspace) { - error("attempt to attach invalid segment dataspace"); throw; } - catch (Region_map::Region_conflict) { - error("region conflict while locally attaching ELF segment"); throw; } + Region_map::Attr attr { }; + attr.writeable = true; + void * const ptr = local_rm.attach(ds_cap, attr).convert( + [&] (Region_map::Range range) { return (void *)range.start; }, + [&] (Region_map::Attach_error const e) { + if (e == Region_map::Attach_error::INVALID_DATASPACE) + error("attempt to attach invalid segment dataspace"); + if (e == Region_map::Attach_error::REGION_CONFLICT) + error("region conflict while locally attaching ELF segment"); + return nullptr; }); + if (!ptr) + return Load_error::INVALID; - void * const ptr = base; addr_t const laddr = elf_addr + seg.file_offset(); /* copy contents and fill with zeros */ @@ -115,15 +131,21 @@ Child::Process::Loaded_executable::Loaded_executable(Type type, } /* detach dataspace */ - local_rm.detach(base); - - off_t const offset = 0; - try { remote_rm.attach_at(ds_cap, addr, size, offset); } - catch (Region_map::Region_conflict) { - error("region conflict while remotely attaching ELF segment"); - error("addr=", (void *)addr, " size=", (void *)size, " offset=", (void *)offset); - throw; } + local_rm.detach(addr_t(ptr)); + auto remote_attach_result = remote_rm.attach(ds_cap, Region_map::Attr { + .size = size, + .offset = { }, + .use_at = true, + .at = addr, + .executable = false, + .writeable = true + }); + if (remote_attach_result.failed()) { + error("failed to remotely attach writable ELF segment"); + error("addr=", (void *)addr, " size=", (void *)size); + return Load_error::INVALID; + } } else { /* read-only segment */ @@ -131,27 +153,32 @@ Child::Process::Loaded_executable::Loaded_executable(Type type, if (seg.file_size() != seg.mem_size()) warning("filesz and memsz for read-only segment differ"); - off_t const offset = seg.file_offset(); - try { - if (exec) - remote_rm.attach_executable(ldso_ds, addr, size, offset); - else - remote_rm.attach_at(ldso_ds, addr, size, offset); - } - catch (Region_map::Region_conflict) { - error("region conflict while remotely attaching read-only ELF segment"); - error("addr=", (void *)addr, " size=", (void *)size, " offset=", (void *)offset); - throw; - } - catch (Region_map::Invalid_dataspace) { - error("attempt to attach invalid read-only segment dataspace"); - throw; + auto remote_attach_result = remote_rm.attach(elf_ds, Region_map::Attr { + .size = size, + .offset = seg.file_offset(), + .use_at = true, + .at = addr, + .executable = seg.flags().x, + .writeable = false + }); + if (remote_attach_result.failed()) { + error("failed to remotely attach read-only ELF segment"); + error("addr=", (void *)addr, " size=", (void *)size); + return Load_error::INVALID; } } } + return entry; +} - /* detach ELF */ - local_rm.detach((void *)elf_addr); + +static Thread_capability create_thread(auto &pd, auto &cpu, auto const &name) +{ + return cpu.create_thread(pd, name, { }, { }).template convert( + [&] (Thread_capability cap) { return cap; }, + [&] (Cpu_session::Create_thread_error) { + error("failed to create initial thread for new PD"); + return Thread_capability(); }); } @@ -159,8 +186,7 @@ Child::Initial_thread::Initial_thread(Cpu_session &cpu, Pd_session_capability pd, Name const &name) : - _cpu(cpu), - _cap(cpu.create_thread(pd, name, Affinity::Location(), Cpu_session::Weight())) + _cpu(cpu), _cap(create_thread(pd, cpu, name)) { } @@ -170,36 +196,32 @@ Child::Initial_thread::~Initial_thread() } -void Child::Initial_thread::start(addr_t ip) +void Child::Initial_thread::start(addr_t ip, Start &start) { - Cpu_thread_client(_cap).start(ip, 0); + start.start_initial_thread(_cap, ip); } -Child::Process::Process(Type type, - Dataspace_capability ldso_ds, - Pd_session &pd, - Initial_thread_base &initial_thread, - Region_map &local_rm, - Region_map &remote_rm, - Parent_capability parent_cap) -: - loaded_executable(type, ldso_ds, pd, local_rm, remote_rm, parent_cap) +Child::Start_result Child::_start_process(Dataspace_capability ldso_ds, + Pd_session &pd, + Initial_thread_base &initial_thread, + Initial_thread::Start &start, + Region_map &local_rm, + Region_map &remote_rm, + Parent_capability parent_cap) { - /* register parent interface for new protection domain */ - pd.assign_parent(parent_cap); - - /* - * Inhibit start of main thread if the new process happens to be forked - * from another. In this case, the main thread will get manually - * started after constructing the 'Process'. - */ - if (type == TYPE_FORKED) - return; - - /* start main thread */ - initial_thread.start(loaded_executable.entry); + return _load_static_elf(ldso_ds, pd, local_rm, remote_rm, parent_cap).convert( + [&] (Entry entry) { + initial_thread.start(entry.ip, start); + return Start_result::OK; + }, + [&] (Load_error e) { + switch (e) { + case Load_error::OUT_OF_RAM: return Start_result::OUT_OF_RAM; + case Load_error::OUT_OF_CAPS: return Start_result::OUT_OF_CAPS; + case Load_error::INVALID: break; + } + return Start_result::INVALID; + } + ); } - - -Child::Process::~Process() { } diff --git a/repos/base/src/lib/base/component.cc b/repos/base/src/lib/base/component.cc index 82b8642ca7..530df9ae3e 100644 --- a/repos/base/src/lib/base/component.cc +++ b/repos/base/src/lib/base/component.cc @@ -18,15 +18,15 @@ #include #include #include -#include /* base-internal includes */ #include +#include + +namespace Genode { struct Component_env; } + +using namespace Genode; -/* - * XXX remove this pointer once 'Env_deprecated' is removed - */ -static Genode::Env *env_ptr = nullptr; /** * Excecute pending static constructors @@ -37,223 +37,252 @@ static Genode::Env *env_ptr = nullptr; void Genode::exec_static_constructors() __attribute__((weak)); void Genode::exec_static_constructors() { } -namespace { - using namespace Genode; +struct Genode::Component_env : Env +{ + Platform &_platform; - struct Env : Genode::Env + Parent &_parent = _platform.parent; + Pd_session &_pd = _platform.pd; + Cpu_session &_cpu = _platform.cpu; + Region_map &_rm = _platform.rm; + + Capability _pd_cap = _platform.pd.rpc_cap(); + Capability _cpu_cap = _platform.cpu.rpc_cap(); + + Entrypoint &_ep; + + /** + * Mutex for serializing 'session' and 'close' + */ + Mutex _mutex { }; + + /** + * Utility to used block for single signal + */ + struct Blockade { - Genode::Entrypoint &_ep; + Parent &_parent; + Signal_receiver _sig_rec { }; + Signal_context _sig_ctx { }; - Genode::Parent &_parent = *env_deprecated()->parent(); - - /** - * Mutex for serializing 'session' and 'close' - */ - Genode::Mutex _mutex { }; - - /** - * Utility to used block for single signal - */ - struct Blockade + Blockade(Parent &parent) : _parent(parent) { - Parent &_parent; - Genode::Signal_receiver _sig_rec { }; - Genode::Signal_context _sig_ctx { }; - - Blockade(Parent &parent) : _parent(parent) - { - _parent.session_sigh(_sig_rec.manage(&_sig_ctx)); - } - - void block() { _sig_rec.wait_for_signal(); } - }; - - Constructible _session_blockade { }; - - Env(Genode::Entrypoint &ep) : _ep(ep) { env_ptr = this; } - - Genode::Parent &parent() override { return _parent; } - Genode::Cpu_session &cpu() override { return *Genode::env_deprecated()->cpu_session(); } - Genode::Region_map &rm() override { return *Genode::env_deprecated()->rm_session(); } - Genode::Pd_session &pd() override { return *Genode::env_deprecated()->pd_session(); } - Genode::Entrypoint &ep() override { return _ep; } - - Genode::Cpu_session_capability cpu_session_cap() override - { - return Genode::env_deprecated()->cpu_session_cap(); + _parent.session_sigh(_sig_rec.manage(_sig_ctx)); } - Genode::Pd_session_capability pd_session_cap() override - { - return Genode::env_deprecated()->pd_session_cap(); - } - - Genode::Id_space &id_space() override - { - return Genode::env_session_id_space(); - } - - void _block_for_session() - { - /* - * Construct blockade lazily be avoid it being used in core where - * all session requests are immediately answered. - */ - if (!_session_blockade.constructed()) - _session_blockade.construct(_parent); - - _session_blockade->block(); - } - - Session_capability try_session(Parent::Service_name const &name, - Parent::Client::Id id, - Parent::Session_args const &args, - Affinity const &affinity) override - { - if (!args.valid_string()) { - warning(name.string(), " session denied because of truncated arguments"); - throw Service_denied(); - } - - Mutex::Guard guard(_mutex); - - Session_capability cap = _parent.session(id, name, args, affinity); - - if (cap.valid()) - return cap; - - _block_for_session(); - return _parent.session_cap(id); - } - - Session_capability session(Parent::Service_name const &name, - Parent::Client::Id id, - Parent::Session_args const &args, - Affinity const &affinity) override - { - /* - * Since we account for the backing store for session meta data on - * the route between client and server, the session quota provided - * by the client may become successively diminished by intermediate - * components, prompting the server to deny the session request. - */ - - /* extract session quota as specified by the 'Connection' */ - char argbuf[Parent::Session_args::MAX_SIZE]; - copy_cstring(argbuf, args.string(), sizeof(argbuf)); - - Ram_quota ram_quota = ram_quota_from_args(argbuf); - Cap_quota cap_quota = cap_quota_from_args(argbuf); - - unsigned warn_after_attempts = 2; - - for (unsigned cnt = 0;; cnt++) { - - try { - - Arg_string::set_arg(argbuf, sizeof(argbuf), "ram_quota", - String<32>(ram_quota).string()); - - Arg_string::set_arg(argbuf, sizeof(argbuf), "cap_quota", - String<32>(cap_quota).string()); - - return try_session(name, id, Parent::Session_args(argbuf), affinity); - } - - catch (Insufficient_ram_quota) { - ram_quota = Ram_quota { ram_quota.value + 4096 }; } - - catch (Insufficient_cap_quota) { - cap_quota = Cap_quota { cap_quota.value + 4 }; } - - catch (Out_of_ram) { - if (ram_quota.value > pd().avail_ram().value) { - Parent::Resource_args args(String<64>("ram_quota=", ram_quota)); - _parent.resource_request(args); - } - } - - catch (Out_of_caps) { - if (cap_quota.value > pd().avail_caps().value) { - Parent::Resource_args args(String<64>("cap_quota=", cap_quota)); - _parent.resource_request(args); - } - } - - if (cnt == warn_after_attempts) { - warning("re-attempted ", name.string(), " session request ", - cnt, " times (args: ", Cstring(argbuf), ")"); - warn_after_attempts *= 2; - } - } - } - - void upgrade(Parent::Client::Id id, Parent::Upgrade_args const &args) override - { - Mutex::Guard guard(_mutex); - - if (_parent.upgrade(id, args) == Parent::UPGRADE_PENDING) - _block_for_session(); - } - - void close(Parent::Client::Id id) override - { - Mutex::Guard guard(_mutex); - - if (_parent.close(id) == Parent::CLOSE_PENDING) - _block_for_session(); - } - - void exec_static_constructors() override - { - Genode::exec_static_constructors(); - } + void block() { _sig_rec.wait_for_signal(); } }; -} + Constructible _session_blockade { }; -namespace Genode { + Component_env(Platform &platform, Entrypoint &ep) + : + _platform(platform), _ep(ep) + { } - struct Startup; + Parent &parent() override { return _parent; } + Cpu_session &cpu() override { return _cpu; } + Region_map &rm() override { return _rm; } + Pd_session &pd() override { return _pd; } + Entrypoint &ep() override { return _ep; } - extern void bootstrap_component(); + Cpu_session_capability cpu_session_cap() override { return _cpu_cap; } + Pd_session_capability pd_session_cap() override { return _pd_cap; } - Env &internal_env() + Id_space &id_space() override { - class Env_ptr_not_initialized { }; - if (!env_ptr) - throw Env_ptr_not_initialized(); - - return *env_ptr; + return env_session_id_space(); } -} + + void _block_for_session() + { + /* + * Construct blockade lazily be avoid it being used in core where + * all session requests are immediately answered. + */ + if (!_session_blockade.constructed()) + _session_blockade.construct(_parent); + + _session_blockade->block(); + } + + Session_capability try_session(Parent::Service_name const &name, + Parent::Client::Id id, + Parent::Session_args const &args, + Affinity const &affinity) override + { + if (!args.valid_string()) { + warning(name.string(), " session denied because of truncated arguments"); + throw Service_denied(); + } + + Mutex::Guard guard(_mutex); + + return _parent.session(id, name, args, affinity).convert>( + [&] (Capability cap) -> Capability { + if (cap.valid()) + return cap; + + _block_for_session(); + + return _parent.session_cap(id).convert>( + [&] (Capability cap) { return cap; }, + [&] (Parent::Session_cap_error const e) -> Capability { + using Error = Parent::Session_cap_error; + switch (e) { + case Error::INSUFFICIENT_RAM_QUOTA: throw Insufficient_ram_quota(); + case Error::INSUFFICIENT_CAP_QUOTA: throw Insufficient_cap_quota(); + case Error::DENIED: break; + } + throw Service_denied(); } + ); + }, + [&] (Parent::Session_error const e) -> Capability { + using Error = Parent::Session_error; + switch (e) { + case Error::OUT_OF_RAM: throw Out_of_ram(); + case Error::OUT_OF_CAPS: throw Out_of_caps(); + case Error::INSUFFICIENT_RAM_QUOTA: throw Insufficient_ram_quota(); + case Error::INSUFFICIENT_CAP_QUOTA: throw Insufficient_cap_quota(); + case Error::DENIED: break; + } + throw Service_denied(); + }); + } + + Session_capability session(Parent::Service_name const &name, + Parent::Client::Id id, + Parent::Session_args const &args, + Affinity const &affinity) override + { + /* + * Since we account for the backing store for session meta data on + * the route between client and server, the session quota provided + * by the client may become successively diminished by intermediate + * components, prompting the server to deny the session request. + */ + + /* extract session quota as specified by the 'Connection' */ + char argbuf[Parent::Session_args::MAX_SIZE]; + copy_cstring(argbuf, args.string(), sizeof(argbuf)); + + Ram_quota ram_quota = ram_quota_from_args(argbuf); + Cap_quota cap_quota = cap_quota_from_args(argbuf); + + unsigned warn_after_attempts = 2; + + for (unsigned cnt = 0;; cnt++) { + + try { + + Arg_string::set_arg(argbuf, sizeof(argbuf), "ram_quota", + String<32>(ram_quota).string()); + + Arg_string::set_arg(argbuf, sizeof(argbuf), "cap_quota", + String<32>(cap_quota).string()); + + return try_session(name, id, Parent::Session_args(argbuf), affinity); + } + + catch (Insufficient_ram_quota) { + ram_quota = Ram_quota { ram_quota.value + 4096 }; } + + catch (Insufficient_cap_quota) { + cap_quota = Cap_quota { cap_quota.value + 4 }; } + + catch (Out_of_ram) { + if (ram_quota.value > pd().avail_ram().value) { + Parent::Resource_args args(String<64>("ram_quota=", ram_quota)); + _parent.resource_request(args); + } + } + + catch (Out_of_caps) { + if (cap_quota.value > pd().avail_caps().value) { + Parent::Resource_args args(String<64>("cap_quota=", cap_quota)); + _parent.resource_request(args); + } + } + + if (cnt == warn_after_attempts) { + warning("re-attempted ", name.string(), " session request ", + cnt, " times (args: ", Cstring(argbuf), ")"); + warn_after_attempts *= 2; + } + } + } + + void upgrade(Parent::Client::Id id, Parent::Upgrade_args const &args) override + { + Mutex::Guard guard(_mutex); + + if (_parent.upgrade(id, args) == Parent::Upgrade_result::PENDING) + _block_for_session(); + } + + void close(Parent::Client::Id id) override + { + Mutex::Guard guard(_mutex); + + if (_parent.close(id) == Parent::Close_result::PENDING) + _block_for_session(); + } + + void exec_static_constructors() override + { + Genode::exec_static_constructors(); + } +}; -Genode::size_t Component::stack_size() __attribute__((weak)); -Genode::size_t Component::stack_size() { return 64*1024; } +size_t Component::stack_size() __attribute__((weak)); +size_t Component::stack_size() { return 64*1024; } + + +/** + * Init program headers of the dynamic linker + * + * The weak function is used for statically linked binaries. The + * dynamic linker provides an implementation that loads the program + * headers of the linker. This must be done before the first exception + * is thrown. + */ +void Genode::init_ldso_phdr(Env &) __attribute__((weak)); +void Genode::init_ldso_phdr(Env &) { } /* * We need to execute the constructor of the main entrypoint from a * class called 'Startup' as 'Startup' is a friend of 'Entrypoint'. */ +namespace Genode { struct Startup; } + + struct Genode::Startup { - ::Env env { ep }; + Component_env env; - bool const exception_handling = (init_exception_handling(env), true); + /* + * 'init_ldso_phdr' must be called before 'init_exception_handling' because + * the initial exception thrown by 'init_exception_handling' involves the + * linker's 'dl_iterate_phdr' function. + */ + bool const ldso_phdr = (init_ldso_phdr(env), true); + bool const exception = (init_exception_handling(env.ram(), env.rm()), true); /* * The construction of the main entrypoint does never return. */ Entrypoint ep { env }; + + Startup(Platform &platform) : env(platform, ep) { } }; -void Genode::bootstrap_component() +void Genode::bootstrap_component(Platform &platform) { - static Startup startup; + static Startup startup { platform }; /* never reached */ } diff --git a/repos/base/src/lib/base/console.cc b/repos/base/src/lib/base/console.cc deleted file mode 100644 index b3f49fc058..0000000000 --- a/repos/base/src/lib/base/console.cc +++ /dev/null @@ -1,261 +0,0 @@ -/* - * \brief Output of format strings - * \author Norman Feske - * \date 2006-04-07 - * - * NOTE: Support for long long ints is not required by Core. - * Hence, this functionality and further features such - * as floating point numbers should better be placed - * in another 'rich_conole' lib outside of the Genode's - * base repository. - */ - -/* - * Copyright (C) 2006-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -/* Genode includes */ -#include -#include - -/* base-internal includes */ -#include - -using namespace Genode; - - -/** - * Format string command representation - */ -class Format_command -{ - public: - - enum Type { INT, UINT, STRING, CHAR, PTR, PERCENT, INVALID }; - enum Length { DEFAULT, LONG, SIZE_T, LONG_LONG }; - - private: - - /** - * Read decimal value from string - */ - int decode_decimal(const char *str, int *consumed) - { - int res = 0; - while (1) { - char c = str[*consumed]; - - if (!c || c < '0' || c > '0' + 9) - return res; - - res = (res * 10) + c - '0'; - (*consumed)++; - } - } - - public: - - Type type = INVALID; /* format argument type */ - Length length = DEFAULT; /* format argument length */ - int padding = 0; /* min number of characters to print */ - int base = 10; /* base of numeric arguments */ - bool zeropad = false; /* pad with zero instead of space */ - bool uppercase = false; /* use upper case for hex numbers */ - int consumed = 0; /* nb of consumed format string chars */ - - /** - * Constructor - * - * \param format begin of command in format string - */ - explicit Format_command(const char *format) - { - /* check for command begin and eat the character */ - if (format[consumed] != '%') return; - if (!format[++consumed]) return; - - /* heading zero indicates zero-padding */ - zeropad = (format[consumed] == '0'); - - /* read decimal padding value */ - padding = decode_decimal(format, &consumed); - if (!format[consumed]) return; - - /* decode length */ - switch (format[consumed]) { - - case 'l': - { - /* long long ints are marked by a subsequenting 'l' character */ - bool is_long_long = (format[consumed + 1] == 'l'); - - length = is_long_long ? LONG_LONG : LONG; - consumed += is_long_long ? 2 : 1; - break; - } - - case 'z': - - length = SIZE_T; - consumed++; - break; - - case 'p': - - length = LONG; - break; - - default: break; - } - - if (!format[consumed]) return; - - /* decode type */ - switch (format[consumed]) { - - case 'd': - case 'i': type = INT; base = 10; break; - case 'o': type = UINT; base = 8; break; - case 'u': type = UINT; base = 10; break; - case 'x': type = UINT; base = 16; break; - case 'X': type = UINT; base = 16; uppercase = 1; break; - case 'p': type = PTR; base = 16; break; - case 'c': type = CHAR; break; - case 's': type = STRING; break; - case '%': type = PERCENT; break; - - case 0: return; - default: break; - } - - /* eat type character */ - consumed++; - } - - int numeric() - { - return (type == INT || type == UINT || type == PTR); - } -}; - - -void Console::_out_string(const char *str) -{ - if (!str) - _out_string(""); - else - while (*str) _out_char(*str++); -} - - -void Console::printf(const char *format, ...) -{ - va_list list; - va_start(list, format); - vprintf(format, list); - va_end(list); -} - - -void Console::vprintf(const char *format, va_list list) -{ - - while (*format) { - - /* eat and output plain characters */ - if (*format != '%') { - _out_char(*format++); - continue; - } - - /* parse format argument descriptor */ - Format_command cmd(format); - - /* read numeric argument from va_list */ - long long numeric_arg = 0; - if (cmd.numeric()) { - switch (cmd.length) { - - case Format_command::LONG_LONG: - - numeric_arg = va_arg(list, long long); - break; - - case Format_command::LONG: - - numeric_arg = (cmd.type == Format_command::UINT) ? - (long long)va_arg(list, unsigned long) : va_arg(list, long); - break; - - case Format_command::SIZE_T: - - numeric_arg = va_arg(list, size_t); - break; - - case Format_command::DEFAULT: - - numeric_arg = (cmd.type == Format_command::UINT) ? - (long long)va_arg(list, unsigned int) : va_arg(list, int); - break; - } - } - - /* call type-specific output routines */ - switch (cmd.type) { - - case Format_command::INT: - - if (cmd.length == Format_command::LONG_LONG) - out_signed(numeric_arg, cmd.base, - [&] (char c) { _out_char(c); }); - else - out_signed((long)numeric_arg, cmd.base, - [&] (char c) { _out_char(c); }); - break; - - case Format_command::UINT: - - if (cmd.length == Format_command::LONG_LONG) { - out_unsigned(numeric_arg, cmd.base, cmd.padding, - [&] (char c) { _out_char(c); }); - break; - } - - /* fall through */ - - case Format_command::PTR: - - out_unsigned((long)numeric_arg, cmd.base, cmd.padding, - [&] (char c) { _out_char(c); }); - break; - - case Format_command::CHAR: - - _out_char((char)va_arg(list, int)); - break; - - case Format_command::STRING: - - _out_string(va_arg(list, const char *)); - break; - - case Format_command::PERCENT: - - _out_char('%'); - break; - - case Format_command::INVALID: - - _out_string(""); - /* consume the argument of the unsupported command */ - va_arg(list, long); - break; - } - - /* proceed with format string after command */ - format += cmd.consumed; - } -} diff --git a/repos/base/src/lib/base/default_log.cc b/repos/base/src/lib/base/default_log.cc index 161b9144cd..ab84657471 100644 --- a/repos/base/src/lib/base/default_log.cc +++ b/repos/base/src/lib/base/default_log.cc @@ -34,8 +34,12 @@ namespace { { Log_session_client _client; - static Session_capability _cap(Parent &parent) { - return parent.session_cap(Parent::Env::log()); } + static Session_capability _cap(Parent &parent) + { + return parent.session_cap(Parent::Env::log()).convert>( + [&] (Capability cap) { return cap; }, + [&] (Parent::Session_cap_error) { return Capability(); }); + } Back_end(Parent &parent) : _client(reinterpret_cap_cast(_cap(parent))) { } @@ -105,8 +109,7 @@ void Genode::init_log(Parent &parent) } }; - typedef Buffered_output - Buffered_log_output; + using Buffered_log_output = Buffered_output; static Buffered_log_output *buffered_log_output = unmanaged_singleton(Write_fn()); diff --git a/repos/base/src/lib/base/entrypoint.cc b/repos/base/src/lib/base/entrypoint.cc index 827f304009..fae5c53aa9 100644 --- a/repos/base/src/lib/base/entrypoint.cc +++ b/repos/base/src/lib/base/entrypoint.cc @@ -31,7 +31,6 @@ namespace Genode { extern bool inhibit_tracing; void call_global_static_constructors(); - void destroy_signal_thread(); } @@ -72,6 +71,12 @@ void Entrypoint::Signal_proxy_component::signal() } +void Entrypoint::Signal_proxy_thread::entry() +{ + ep._process_incoming_signals(); +} + + void Entrypoint::_dispatch_signal(Signal &sig) { Signal_dispatcher_base *dispatcher = 0; @@ -117,64 +122,28 @@ void Entrypoint::_process_incoming_signals() { for (;;) { - do { - { - /* see documentation in 'wait_and_dispatch_one_io_signal()' */ - Mutex::Guard guard { _block_for_signal_mutex }; + { + /* see documentation in 'wait_and_dispatch_one_io_signal()' */ + Mutex::Guard guard { _block_for_signal_mutex }; - _signal_proxy_delivers_signal = true; + _signal_proxy_delivers_signal = true; - _sig_rec->block_for_signal(); - } - - /* - * It might happen that we try to forward a signal to the - * entrypoint, while the context of that signal is already - * destroyed. In that case we will get an ipc error exception - * as result, which has to be caught. - */ - try { - retry( - [&] () { _signal_proxy_cap.call(); }, - [] () { warning("blocking canceled during signal processing"); }); - } catch (Genode::Ipc_error) { /* ignore - context got destroyed in meantime */ } - - /* entrypoint destructor requested to stop signal handling */ - if (_stop_signal_proxy) { - return; - } - } while (!_suspended); - - _deferred_signal_handler.destruct(); - _suspend_dispatcher.destruct(); - _sig_rec.destruct(); - dissolve(_signal_proxy); - deinit_heartbeat_monitoring(); - _signal_proxy_cap = Capability(); - _rpc_ep.destruct(); - destroy_signal_thread(); - - /* execute fork magic in noux plugin */ - _suspended_callback(); - - init_signal_thread(_env); - - _rpc_ep.construct(&_env.pd(), Component::stack_size(), initial_ep_name(), Affinity::Location()); - init_heartbeat_monitoring(_env); - _signal_proxy_cap = manage(_signal_proxy); - _sig_rec.construct(); + _sig_rec->block_for_signal(); + } /* - * Before calling the resumed callback, we reset the callback pointer - * as these may be set again in the resumed code to initiate the next - * suspend-resume cycle (e.g., exit()). + * It might happen that we try to forward a signal to the + * entrypoint, while the context of that signal is already + * destroyed. In that case we will get an ipc error exception + * as result, which has to be caught. */ - void (*resumed_callback)() = _resumed_callback; - _suspended_callback = nullptr; - _resumed_callback = nullptr; - _suspended = false; + try { + _signal_proxy_cap.call(); + } catch (Genode::Ipc_error) { /* ignore - context got destroyed in meantime */ } - resumed_callback(); + /* entrypoint destructor requested to stop signal handling */ + if (_stop_signal_proxy) + return; } } @@ -248,26 +217,10 @@ bool Entrypoint::_wait_and_dispatch_one_io_signal(bool const dont_block) } -void Entrypoint::schedule_suspend(void (*suspended)(), void (*resumed)()) -{ - _suspended_callback = suspended; - _resumed_callback = resumed; - - /* - * We always construct the dispatcher when the suspend is scheduled and - * destruct it when the suspend is executed. - */ - _suspend_dispatcher.construct(*this, *this, &Entrypoint::_handle_suspend); - - /* trigger wakeup of the signal-dispatch loop for suspend */ - Signal_transmitter(*_suspend_dispatcher).submit(); -} - - Signal_context_capability Entrypoint::manage(Signal_dispatcher_base &dispatcher) { /* _sig_rec is invalid for a small window in _process_incoming_signals */ - return _sig_rec.constructed() ? _sig_rec->manage(&dispatcher) + return _sig_rec.constructed() ? _sig_rec->manage(dispatcher) : Signal_context_capability(); } @@ -276,7 +229,7 @@ void Genode::Entrypoint::dissolve(Signal_dispatcher_base &dispatcher) { /* _sig_rec is invalid for a small window in _process_incoming_signals */ if (_sig_rec.constructed()) - _sig_rec->dissolve(&dispatcher); + _sig_rec->dissolve(dispatcher); /* also remove context from deferred signal list */ { @@ -345,11 +298,7 @@ Entrypoint::Entrypoint(Env &env) _env.ep().manage(constructor); - try { - invoke_constructor_at_entrypoint(constructor.cap()); - } catch (Blocking_canceled) { - warning("blocking canceled in entrypoint constructor"); - } + invoke_constructor_at_entrypoint(constructor.cap()); _env.ep().dissolve(constructor); diff --git a/repos/base/src/lib/base/env_deprecated.cc b/repos/base/src/lib/base/env_deprecated.cc deleted file mode 100644 index 16f734b390..0000000000 --- a/repos/base/src/lib/base/env_deprecated.cc +++ /dev/null @@ -1,45 +0,0 @@ -/* - * \brief Environment initialization - * \author Norman Feske - * \author Christian Helmuth - * \date 2006-07-27 - */ - -/* - * Copyright (C) 2006-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#include -#include -#include -#include - -namespace Genode { - - /* - * Request pointer to static environment of the Genode application - */ - Env_deprecated *env_deprecated() - { - /* - * By placing the environment as static object here, we ensure that its - * constructor gets called when this function is used the first time. - */ - static Genode::Platform_env _env; - return &_env; - } -} - - -void Genode::init_parent_resource_requests(Genode::Env & env) -{ - /** - * Catch up asynchronous resource request and notification - * mechanism construction of the expanding parent environment - */ - using Parent = Expanding_parent_client; - static_cast(&env.parent())->init_fallback_signal_handling(); -} diff --git a/repos/base/src/lib/base/env_session_id_space.cc b/repos/base/src/lib/base/env_session_id_space.cc index dca120f1bc..4749f42469 100644 --- a/repos/base/src/lib/base/env_session_id_space.cc +++ b/repos/base/src/lib/base/env_session_id_space.cc @@ -38,13 +38,3 @@ Id_space &Genode::env_session_id_space() return id_space; } - - -/* - * \deprecated - */ -Connection_base::Connection_base() -: - _env(internal_env()), - _id_space_element(_parent_client, _env.id_space()) -{ } diff --git a/repos/base/src/lib/base/heap.cc b/repos/base/src/lib/base/heap.cc index 8cf9e45ed8..f2e904ea7d 100644 --- a/repos/base/src/lib/base/heap.cc +++ b/repos/base/src/lib/base/heap.cc @@ -44,7 +44,7 @@ void Heap::Dataspace_pool::remove_and_free(Dataspace &ds) */ Ram_dataspace_capability ds_cap = ds.cap; - void *ds_local_addr = ds.local_addr; + addr_t const at = addr_t(ds.local_addr); remove(&ds); @@ -56,7 +56,7 @@ void Heap::Dataspace_pool::remove_and_free(Dataspace &ds) */ ds.~Dataspace(); - region_map->detach(ds_local_addr); + region_map->detach(at); ram_alloc->free(ds_cap); } @@ -102,22 +102,36 @@ Heap::_allocate_dataspace(size_t size, bool enforce_separate_metadata) struct Attach_guard { Region_map &rm; - struct { void *ptr = nullptr; }; + Region_map::Range range { }; bool keep = false; Attach_guard(Region_map &rm) : rm(rm) { } - ~Attach_guard() { if (!keep && ptr) rm.detach(ptr); } + ~Attach_guard() { if (!keep && range.start) rm.detach(range.start); } } attach_guard(*_ds_pool.region_map); - try { - attach_guard.ptr = _ds_pool.region_map->attach(ds_cap); + Region_map::Attr attr { }; + attr.writeable = true; + Region_map::Attach_result const result = _ds_pool.region_map->attach(ds_cap, attr); + if (result.failed()) { + using Error = Region_map::Attach_error; + return result.convert( + [&] (auto) /* never called */ { return Alloc_error::DENIED; }, + [&] (Error e) { + switch (e) { + case Error::OUT_OF_RAM: return Alloc_error::OUT_OF_RAM; + case Error::OUT_OF_CAPS: return Alloc_error::OUT_OF_CAPS; + case Error::REGION_CONFLICT: break; + case Error::INVALID_DATASPACE: break; + } + return Alloc_error::DENIED; + }); } - catch (Out_of_ram) { return Alloc_error::OUT_OF_RAM; } - catch (Out_of_caps) { return Alloc_error::OUT_OF_CAPS; } - catch (Region_map::Invalid_dataspace) { return Alloc_error::DENIED; } - catch (Region_map::Region_conflict) { return Alloc_error::DENIED; } + + result.with_result( + [&] (Region_map::Range range) { attach_guard.range = range; }, + [&] (auto) { /* handled above */ }); Alloc_result metadata = Alloc_error::DENIED; @@ -128,7 +142,7 @@ Heap::_allocate_dataspace(size_t size, bool enforce_separate_metadata) } else { /* add new local address range to our local allocator */ - _alloc->add_range((addr_t)attach_guard.ptr, size).with_result( + _alloc->add_range(attach_guard.range.start, size).with_result( [&] (Range_allocator::Range_ok) { metadata = _alloc->alloc_aligned(sizeof(Heap::Dataspace), log2(16U)); }, [&] (Alloc_error error) { @@ -138,7 +152,7 @@ Heap::_allocate_dataspace(size_t size, bool enforce_separate_metadata) return metadata.convert( [&] (void *md_ptr) -> Result { Dataspace &ds = *construct_at(md_ptr, ds_cap, - attach_guard.ptr, size); + (void *)attach_guard.range.start, size); _ds_pool.insert(&ds); alloc_guard.keep = attach_guard.keep = true; return &ds; @@ -291,7 +305,7 @@ void Heap::free(void *addr, size_t) break; if (!ds) { - warning("heap could not free memory block: invalid address"); + warning("heap could not free memory block: invalid address ", addr); return; } diff --git a/repos/base/src/lib/base/heartbeat.cc b/repos/base/src/lib/base/heartbeat.cc index cf89434f6a..186cef6f0c 100644 --- a/repos/base/src/lib/base/heartbeat.cc +++ b/repos/base/src/lib/base/heartbeat.cc @@ -59,13 +59,3 @@ void Genode::init_heartbeat_monitoring(Env &env) _heartbeat_handler_ptr = unmanaged_singleton>(); _heartbeat_handler_ptr->construct(env); } - - -void Genode::deinit_heartbeat_monitoring() -{ - if (!_heartbeat_handler_ptr) - return; - - _heartbeat_handler_ptr->destruct(); - _heartbeat_handler_ptr = nullptr; -} diff --git a/repos/base/src/lib/base/main_thread_cap.cc b/repos/base/src/lib/base/main_thread_cap.cc deleted file mode 100644 index 0019920008..0000000000 --- a/repos/base/src/lib/base/main_thread_cap.cc +++ /dev/null @@ -1,24 +0,0 @@ -/* - * \brief Access to the component's initial thread capability - * \author Norman Feske - * \date 2017-05-10 - */ - -/* - * Copyright (C) 2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -/* Genode includes */ -#include - -/* base-internal includes */ -#include -#include - -Genode::Thread_capability Genode::main_thread_cap() -{ - return Genode::env_deprecated()->parent()->main_thread_cap(); -} diff --git a/repos/base/src/lib/base/platform.cc b/repos/base/src/lib/base/platform.cc index 82e843931b..dd7cf1d1c2 100644 --- a/repos/base/src/lib/base/platform.cc +++ b/repos/base/src/lib/base/platform.cc @@ -1,20 +1,43 @@ /* - * \brief Platform dependant hook after binary ready - * \author Stefan Thoeni - * \date 2019-12-13 + * \brief Environment initialization + * \author Norman Feske + * \author Christian Helmuth + * \date 2006-07-27 */ /* - * Copyright (C) 2019 Genode Labs GmbH - * Copyright (C) 2019 gapfruit AG + * Copyright (C) 2006-2023 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. */ +#include + +using namespace Genode; + + +void Genode::init_parent_resource_requests(Genode::Env &env) +{ + using Parent = Expanding_parent_client; + static_cast(&env.parent())->init_fallback_signal_handling(); +} + + +Platform &Genode::init_platform() +{ + static Genode::Platform platform; + + init_log(platform.parent); + init_rpc_cap_alloc(platform.parent); + init_cap_slab(platform.pd, platform.parent); + init_thread(platform.cpu, platform.rm); + init_thread_start(platform.pd.rpc_cap()); + init_thread_bootstrap(platform.cpu, platform.parent.main_thread_cap()); + init_signal_receiver(platform.pd, platform.parent); + + return platform; +} -/* base-internal includes */ -#include void Genode::binary_ready_hook_for_platform() { } - diff --git a/repos/base/src/lib/base/raw_output.cc b/repos/base/src/lib/base/raw_output.cc index a9744e4503..3da8ac8aaf 100644 --- a/repos/base/src/lib/base/raw_output.cc +++ b/repos/base/src/lib/base/raw_output.cc @@ -24,7 +24,7 @@ Genode::Output &Genode::Raw::_output() { struct Write_fn { void operator () (char const *s) { raw_write_string(s); } }; - typedef Buffered_output<256, Write_fn> Buffered_raw_output; + using Buffered_raw_output = Buffered_output<256, Write_fn>; static Buffered_raw_output *buffered_raw_output = unmanaged_singleton(Write_fn()); diff --git a/repos/base/src/lib/base/region_map_client.cc b/repos/base/src/lib/base/region_map_client.cc index 25a675600f..6fcc74c550 100644 --- a/repos/base/src/lib/base/region_map_client.cc +++ b/repos/base/src/lib/base/region_map_client.cc @@ -20,25 +20,23 @@ Region_map_client::Region_map_client(Capability cap) : Rpc_client(cap) { } -Region_map::Local_addr -Region_map_client::attach(Dataspace_capability ds, size_t size, off_t offset, - bool use_local_addr, Local_addr local_addr, - bool executable, bool writeable) +Region_map::Attach_result +Region_map_client::attach(Dataspace_capability ds, Attr const &attr) { - return call(ds, size, offset, use_local_addr, local_addr, - executable, writeable); + return call(ds, attr); } -void Region_map_client::detach(Local_addr local_addr) { - call(local_addr); } +void Region_map_client::detach(addr_t at) { call(at); } -void Region_map_client::fault_handler(Signal_context_capability cap) { - call(cap); } +void Region_map_client::fault_handler(Signal_context_capability cap) +{ + call(cap); +} -Region_map::State Region_map_client::state() { return call(); } +Region_map::Fault Region_map_client::fault() { return call(); } Dataspace_capability Region_map_client::dataspace() { return call(); } diff --git a/repos/base/src/lib/base/rm_session_client.cc b/repos/base/src/lib/base/rm_session_client.cc index 835b7399d1..25b4c74d26 100644 --- a/repos/base/src/lib/base/rm_session_client.cc +++ b/repos/base/src/lib/base/rm_session_client.cc @@ -20,7 +20,7 @@ Rm_session_client::Rm_session_client(Capability cap) : Rpc_client(cap) { } -Capability Rm_session_client::create(size_t size) { +Rm_session::Create_result Rm_session_client::create(size_t size) { return call(size); } diff --git a/repos/base/src/lib/base/root_proxy.cc b/repos/base/src/lib/base/root_proxy.cc index 9d55b9e295..6edd08deda 100644 --- a/repos/base/src/lib/base/root_proxy.cc +++ b/repos/base/src/lib/base/root_proxy.cc @@ -25,7 +25,7 @@ namespace { struct Service { - typedef Session_state::Name Name; + using Name = Session_state::Name; Name name; Capability root; @@ -72,8 +72,7 @@ namespace { /** * Call functor 'fn' with root capability for a given service name */ - template - void apply(Service::Name const &name, FUNC const &fn) + void apply(Service::Name const &name, auto const &fn) { /* * Protect '_services' but execute 'fn' with the mutex released. @@ -160,14 +159,14 @@ void Root_proxy::_handle_session_request(Xml_node request, char const *type) Parent::Server::Id const id { request.attribute_value("id", 0UL) }; - typedef Service::Session Session; + using Session = Service::Session; if (request.has_type("create")) { if (!request.has_sub_node("args")) return; - typedef Session_state::Args Args; + using Args = Session_state::Args; Args const args = request.sub_node("args").decoded_content(); /* construct session */ diff --git a/repos/base/src/lib/base/rpc_cap_alloc.cc b/repos/base/src/lib/base/rpc_cap_alloc.cc index 8d5bd3365e..bf620ffa47 100644 --- a/repos/base/src/lib/base/rpc_cap_alloc.cc +++ b/repos/base/src/lib/base/rpc_cap_alloc.cc @@ -16,11 +16,27 @@ #include #include #include -#include + +/* base-internal includes */ +#include using namespace Genode; +static Parent *_parent_ptr; +static Parent &_parent() +{ + if (_parent_ptr) + return *_parent_ptr; + + error("missing call of init_rpc_cap_alloc"); + for (;;); +} + + +void Genode::init_rpc_cap_alloc(Parent &parent) { _parent_ptr = &parent; } + + Native_capability Rpc_entrypoint::_alloc_rpc_cap(Pd_session &pd, Native_capability, addr_t) { @@ -29,13 +45,25 @@ Native_capability Rpc_entrypoint::_alloc_rpc_cap(Pd_session &pd, Ram_quota ram_upgrade { 0 }; Cap_quota cap_upgrade { 0 }; - try { return pd.alloc_rpc_cap(_cap); } - catch (Out_of_ram) { ram_upgrade = Ram_quota { 2*1024*sizeof(long) }; } - catch (Out_of_caps) { cap_upgrade = Cap_quota { 4 }; } + using Error = Pd_session::Alloc_rpc_cap_error; - env_deprecated()->parent()->upgrade(Parent::Env::pd(), - String<100>("ram_quota=", ram_upgrade, ", " - "cap_quota=", cap_upgrade).string()); + Native_capability result { }; + + pd.alloc_rpc_cap(_cap).with_result( + [&] (Native_capability cap) { result = cap; }, + [&] (Error e) { + switch (e) { + case Error::OUT_OF_RAM: ram_upgrade = { 2*1024*sizeof(long) }; break; + case Error::OUT_OF_CAPS: cap_upgrade = { 4 }; break; + } + }); + + if (result.valid()) + return result; + + _parent().upgrade(Parent::Env::pd(), + String<100>("ram_quota=", ram_upgrade, ", " + "cap_quota=", cap_upgrade).string()); } } diff --git a/repos/base/src/lib/base/rpc_dispatch_loop.cc b/repos/base/src/lib/base/rpc_dispatch_loop.cc index 5fc801983d..50f21b37a2 100644 --- a/repos/base/src/lib/base/rpc_dispatch_loop.cc +++ b/repos/base/src/lib/base/rpc_dispatch_loop.cc @@ -67,9 +67,8 @@ void Rpc_entrypoint::entry() apply(request.badge, [&] (Rpc_object_base *obj) { - if (!obj) { return;} - try { exc = obj->dispatch(opcode, unmarshaller, _snd_buf); } - catch(Blocking_canceled&) { } + if (obj) + exc = obj->dispatch(opcode, unmarshaller, _snd_buf); }); } diff --git a/repos/base/src/lib/base/rpc_entrypoint.cc b/repos/base/src/lib/base/rpc_entrypoint.cc index 8ad8cceedb..57c6ae4758 100644 --- a/repos/base/src/lib/base/rpc_entrypoint.cc +++ b/repos/base/src/lib/base/rpc_entrypoint.cc @@ -14,7 +14,6 @@ /* Genode includes */ #include #include -#include #include /* base-internal includes */ diff --git a/repos/base/src/lib/base/session_state.cc b/repos/base/src/lib/base/session_state.cc index 9e775bdef2..204a27cf23 100644 --- a/repos/base/src/lib/base/session_state.cc +++ b/repos/base/src/lib/base/session_state.cc @@ -27,7 +27,7 @@ struct Formatted_phase void print(Output &output) const { using Genode::print; - typedef Genode::Session_state State; + using State = Genode::Session_state; switch (_phase) { case State::CREATE_REQUESTED: print(output, "CREATE_REQUESTED"); break; @@ -63,19 +63,19 @@ void Session_state::generate_session_request(Xml_generator &xml) const case CREATE_REQUESTED: - xml.node("create", [&] () { + xml.node("create", [&] { xml.attribute("id", id_at_server->id().value); xml.attribute("service", _service.name()); xml.attribute("label", _label); - xml.node("args", [&] () { + xml.node("args", [&] { xml.append_sanitized(Server_args(*this).string()); }); - xml.node("affinity", [&] () { - xml.node("space", [&] () { + xml.node("affinity", [&] { + xml.node("space", [&] { xml.attribute("width", _affinity.space().width()); xml.attribute("height", _affinity.space().height()); }); - xml.node("location", [&] () { + xml.node("location", [&] { xml.attribute("xpos", _affinity.location().xpos()); xml.attribute("ypos", _affinity.location().ypos()); xml.attribute("width", _affinity.location().width()); @@ -87,7 +87,7 @@ void Session_state::generate_session_request(Xml_generator &xml) const case UPGRADE_REQUESTED: - xml.node("upgrade", [&] () { + xml.node("upgrade", [&] { xml.attribute("id", id_at_server->id().value); xml.attribute("ram_quota", ram_upgrade.value); xml.attribute("cap_quota", cap_upgrade.value); @@ -96,7 +96,7 @@ void Session_state::generate_session_request(Xml_generator &xml) const case CLOSE_REQUESTED: - xml.node("close", [&] () { + xml.node("close", [&] { xml.attribute("id", id_at_server->id().value); }); break; @@ -120,7 +120,7 @@ void Session_state::generate_client_side_info(Xml_generator &xml, Detail detail) xml.attribute("caps", String<32>(_donated_cap_quota)); if (detail.args == Detail::ARGS) - xml.node("args", [&] () { xml.append_sanitized(_args.string()); }); + xml.node("args", [&] { xml.append_sanitized(_args.string()); }); } diff --git a/repos/base/src/lib/base/signal.cc b/repos/base/src/lib/base/signal.cc index 03adbb1f91..2fbe929f29 100644 --- a/repos/base/src/lib/base/signal.cc +++ b/repos/base/src/lib/base/signal.cc @@ -19,7 +19,6 @@ #include #include #include -#include /* base-internal includes */ #include @@ -28,10 +27,14 @@ using namespace Genode; + class Signal_handler_thread : Thread, Blockade { private: + Pd_session &_pd; + Cpu_session &_cpu; + /** * Actual signal source * @@ -43,12 +46,15 @@ class Signal_handler_thread : Thread, Blockade void entry() override { - _signal_source.construct(env_deprecated()->pd_session()->alloc_signal_source()); - wakeup(); - Signal_receiver::dispatch_signals(&(*_signal_source)); + _pd.signal_source().with_result([&] (Capability source) { + _signal_source.construct(_cpu, source); + wakeup(); + Signal_receiver::dispatch_signals(*_signal_source); }, + [&] (Pd_session::Signal_source_error) { + error("failed to initialize signal-source interface"); }); } - enum { STACK_SIZE = 4*1024*sizeof(addr_t) }; + static constexpr size_t STACK_SIZE = 4*1024*sizeof(addr_t); public: @@ -56,7 +62,8 @@ class Signal_handler_thread : Thread, Blockade * Constructor */ Signal_handler_thread(Env &env) - : Thread(env, "signal handler", STACK_SIZE) + : + Thread(env, "signal handler", STACK_SIZE), _pd(env.pd()), _cpu(env.cpu()) { start(); @@ -70,7 +77,7 @@ class Signal_handler_thread : Thread, Blockade ~Signal_handler_thread() { - env_deprecated()->pd_session()->free_signal_source(_signal_source->rpc_cap()); + _pd.free_signal_source(_signal_source->rpc_cap()); } }; @@ -102,11 +109,6 @@ namespace Genode { { signal_handler_thread().construct(env); } - - void destroy_signal_thread() - { - signal_handler_thread().destruct(); - } } @@ -117,6 +119,7 @@ namespace Genode { void Signal_context::local_submit() { if (_receiver) { + Mutex::Guard guard(_mutex); /* construct and locally submit signal object */ Signal::Data signal(this, 1); _receiver->local_submit(signal); @@ -201,46 +204,74 @@ Genode::Signal_context_registry *signal_context_registry() ** Signal receiver ** *********************/ -Signal_receiver::Signal_receiver() { } +static Pd_session *_pd_ptr; +static Parent *_parent_ptr; -Signal_context_capability Signal_receiver::manage(Signal_context *context) +Signal_receiver::Signal_receiver() : _pd(*_pd_ptr) { - if (context->_receiver) - throw Context_already_in_use(); + if (!_pd_ptr) { + struct Missing_call_of_init_signal_receiver { }; + throw Missing_call_of_init_signal_receiver(); + } +} - context->_receiver = this; + +Signal_context_capability Signal_receiver::manage(Signal_context &context) +{ + if (context._receiver) { + error("ill-attempt to manage an already managed signal context"); + return context._cap; + } + + context._receiver = this; Mutex::Guard contexts_guard(_contexts_mutex); /* insert context into context list */ - _contexts.insert_as_tail(context); + _contexts.insert_as_tail(&context); /* register context at process-wide registry */ - signal_context_registry()->insert(&context->_registry_le); + signal_context_registry()->insert(&context._registry_le); for (;;) { Ram_quota ram_upgrade { 0 }; Cap_quota cap_upgrade { 0 }; - try { - /* use signal context as imprint */ - context->_cap = env_deprecated()->pd_session()->alloc_context(_cap, (long)context); + using Error = Pd_session::Alloc_context_error; + + /* use pointer to signal context as imprint */ + Pd_session::Imprint const imprint { addr_t(&context) }; + + _pd.alloc_context(_cap, imprint).with_result( + [&] (Capability cap) { context._cap = cap; }, + [&] (Error e) { + switch (e) { + case Error::OUT_OF_RAM: + ram_upgrade = Ram_quota { 1024*sizeof(long) }; + break; + case Error::OUT_OF_CAPS: + cap_upgrade = Cap_quota { 4 }; + break; + case Error::INVALID_SIGNAL_SOURCE: + error("ill-attempt to create context for invalid signal source"); + sleep_forever(); + break; + } + }); + + if (context._cap.valid()) break; - } - catch (Out_of_ram) { ram_upgrade = Ram_quota { 1024*sizeof(long) }; } - catch (Out_of_caps) { cap_upgrade = Cap_quota { 4 }; } log("upgrading quota donation for PD session " "(", ram_upgrade, " bytes, ", cap_upgrade, " caps)"); - env_deprecated()->parent()->upgrade(Parent::Env::pd(), - String<100>("ram_quota=", ram_upgrade, ", " - "cap_quota=", cap_upgrade).string()); + _parent_ptr->upgrade(Parent::Env::pd(), + String<100>("ram_quota=", ram_upgrade, ", " + "cap_quota=", cap_upgrade).string()); } - - return context->_cap; + return context._cap; } @@ -261,7 +292,7 @@ Signal Signal_receiver::pending_signal() _contexts.head(context._next); context._pending = false; result = context._curr_signal; - context._curr_signal = Signal::Data(0, 0); + context._curr_signal = Signal::Data(); Trace::Signal_received trace_event(context, result.num); return true; @@ -312,10 +343,10 @@ void Signal_receiver::local_submit(Signal::Data data) } -void Signal_receiver::dispatch_signals(Signal_source *signal_source) +void Signal_receiver::dispatch_signals(Signal_source &signal_source) { for (;;) { - Signal_source::Signal source_signal = signal_source->wait_for_signal(); + Signal_source::Signal source_signal = signal_source.wait_for_signal(); /* look up context as pointed to by the signal imprint */ Signal_context *context = (Signal_context *)(source_signal.imprint()); @@ -344,18 +375,25 @@ void Signal_receiver::dispatch_signals(Signal_source *signal_source) } -void Signal_receiver::_platform_begin_dissolve(Signal_context *context) +void Signal_receiver::_platform_begin_dissolve(Signal_context &context) { /* * Because the 'remove' operation takes the registry mutex, the context * must not be acquired when calling this method. See the comment in * 'Signal_receiver::dissolve'. */ - signal_context_registry()->remove(&context->_registry_le); + signal_context_registry()->remove(&context._registry_le); } -void Signal_receiver::_platform_finish_dissolve(Signal_context *) { } +void Signal_receiver::_platform_finish_dissolve(Signal_context &) { } void Signal_receiver::_platform_destructor() { } + + +void Genode::init_signal_receiver(Pd_session &pd, Parent &parent) +{ + _pd_ptr = &pd; + _parent_ptr = &parent; +} diff --git a/repos/base/src/lib/base/signal_common.cc b/repos/base/src/lib/base/signal_common.cc index e1eb8bc1a9..567c2dbb54 100644 --- a/repos/base/src/lib/base/signal_common.cc +++ b/repos/base/src/lib/base/signal_common.cc @@ -17,7 +17,6 @@ #include #include #include -#include using namespace Genode; @@ -165,34 +164,36 @@ Signal_receiver::~Signal_receiver() Mutex::Guard contexts_guard(_contexts_mutex); /* disassociate contexts from the receiver */ - while (Signal_context *context = _contexts.head()) { - _platform_begin_dissolve(context); - _unsynchronized_dissolve(context); - _platform_finish_dissolve(context); + while (Signal_context *context_ptr = _contexts.head()) { + _platform_begin_dissolve(*context_ptr); + _unsynchronized_dissolve(*context_ptr); + _platform_finish_dissolve(*context_ptr); } _platform_destructor(); } -void Signal_receiver::_unsynchronized_dissolve(Signal_context * const context) +void Signal_receiver::_unsynchronized_dissolve(Signal_context &context) { /* tell core to stop sending signals referring to the context */ - env_deprecated()->pd_session()->free_context(context->_cap); + _pd.free_context(context._cap); /* restore default initialization of signal context */ - context->_receiver = nullptr; - context->_cap = Signal_context_capability(); + context._receiver = nullptr; + context._cap = Signal_context_capability(); /* remove context from context list */ - _contexts.remove(context); + _contexts.remove(&context); } -void Signal_receiver::dissolve(Signal_context *context) +void Signal_receiver::dissolve(Signal_context &context) { - if (context->_receiver != this) - throw Context_not_associated(); + if (context._receiver != this) { + error("ill-attempt to dissolve unmanaged signal context"); + return; + } { /* @@ -208,14 +209,14 @@ void Signal_receiver::dissolve(Signal_context *context) _platform_begin_dissolve(context); - Mutex::Guard context_guard(context->_mutex); + Mutex::Guard context_guard(context._mutex); _unsynchronized_dissolve(context); } _platform_finish_dissolve(context); - Mutex::Guard context_destroy_guard(context->_destroy_mutex); + Mutex::Guard context_destroy_guard(context._destroy_mutex); } diff --git a/repos/base/src/lib/base/slab.cc b/repos/base/src/lib/base/slab.cc index cf088b7e2d..3d7f26feec 100644 --- a/repos/base/src/lib/base/slab.cc +++ b/repos/base/src/lib/base/slab.cc @@ -219,12 +219,14 @@ Slab::Slab(size_t slab_size, size_t block_size, void *initial_sb, */ _entries_per_block((_block_size - sizeof(Block) - sizeof(umword_t)) / (_slab_size + sizeof(Entry) + 1)), - _initial_sb((Block *)initial_sb), _nested(false), _curr_sb((Block *)initial_sb), _backing_store(backing_store) { + static_assert(sizeof(Slab::Block) <= overhead_per_block()); + static_assert(sizeof(Slab::Entry) <= overhead_per_entry()); + /* if no initial slab block was specified, try to get one */ if (!_curr_sb && _backing_store) _new_slab_block().with_result( diff --git a/repos/base/src/lib/base/sliced_heap.cc b/repos/base/src/lib/base/sliced_heap.cc index c4e00cf247..9a90984952 100644 --- a/repos/base/src/lib/base/sliced_heap.cc +++ b/repos/base/src/lib/base/sliced_heap.cc @@ -63,28 +63,42 @@ Allocator::Alloc_result Sliced_heap::try_alloc(size_t size) struct Attach_guard { Region_map &rm; - struct { void *ptr = nullptr; }; + Region_map::Range range { }; bool keep = false; Attach_guard(Region_map &rm) : rm(rm) { } - ~Attach_guard() { if (!keep && ptr) rm.detach(ptr); } + ~Attach_guard() { if (!keep && range.start) rm.detach(range.start); } } attach_guard(_region_map); - try { - attach_guard.ptr = _region_map.attach(ds_cap); + Region_map::Attr attr { }; + attr.writeable = true; + Region_map::Attach_result const result = _region_map.attach(ds_cap, attr); + if (result.failed()) { + using Error = Region_map::Attach_error; + return result.convert( + [&] (auto) /* never called */ { return Alloc_error::DENIED; }, + [&] (Error e) { + switch (e) { + case Error::OUT_OF_RAM: return Alloc_error::OUT_OF_RAM; + case Error::OUT_OF_CAPS: return Alloc_error::OUT_OF_CAPS; + case Error::REGION_CONFLICT: break; + case Error::INVALID_DATASPACE: break; + } + return Alloc_error::DENIED; + }); } - catch (Out_of_ram) { return Alloc_error::OUT_OF_RAM; } - catch (Out_of_caps) { return Alloc_error::OUT_OF_CAPS; } - catch (Region_map::Invalid_dataspace) { return Alloc_error::DENIED; } - catch (Region_map::Region_conflict) { return Alloc_error::DENIED; } + + result.with_result( + [&] (Region_map::Range range) { attach_guard.range = range; }, + [&] (auto) { /* handled above */ }); /* serialize access to block list */ Mutex::Guard guard(_mutex); - Block * const block = construct_at(attach_guard.ptr, ds_cap, size); - + Block * const block = construct_at((void *)attach_guard.range.start, + ds_cap, size); _consumed += size; _blocks.insert(block); @@ -126,7 +140,7 @@ void Sliced_heap::free(void *addr, size_t) block->~Block(); } - _region_map.detach(local_addr); + _region_map.detach(addr_t(local_addr)); _ram_alloc.free(ds_cap); } diff --git a/repos/base/src/lib/base/thread.cc b/repos/base/src/lib/base/thread.cc index b7ee561a44..b8ebd7d83b 100644 --- a/repos/base/src/lib/base/thread.cc +++ b/repos/base/src/lib/base/thread.cc @@ -18,8 +18,6 @@ #include #include #include -#include -#include /* base-internal includes */ #include @@ -28,6 +26,10 @@ using namespace Genode; +static Region_map *local_rm_ptr; +static Cpu_session *cpu_session_ptr; + + void Stack::size(size_t const size) { /* check if the stack needs to be enhanced */ @@ -47,19 +49,35 @@ void Stack::size(size_t const size) /* allocate and attach backing store for the stack enhancement */ addr_t const ds_addr = _base - ds_size - stack_area_virtual_base(); - try { - Ram_allocator * const ram = env_stack_area_ram_allocator; - Ram_dataspace_capability const ds_cap = ram->alloc(ds_size); - Region_map * const rm = env_stack_area_region_map; - void * const attach_addr = rm->attach_at(ds_cap, ds_addr, ds_size); - if (ds_addr != (addr_t)attach_addr) - throw Thread::Out_of_stack_space(); - } - catch (Out_of_ram) { throw Thread::Stack_alloc_failed(); } + Ram_allocator &ram = *env_stack_area_ram_allocator; + Region_map &rm = *env_stack_area_region_map; - /* update stack information */ - _base -= ds_size; + ram.try_alloc(ds_size).with_result( + [&] (Ram_dataspace_capability ds_cap) { + + rm.attach(ds_cap, Region_map::Attr { + .size = ds_size, + .offset = 0, + .use_at = true, + .at = ds_addr, + .executable = { }, + .writeable = true, + }).with_result( + [&] (Region_map::Range r) { + if (r.start != ds_addr) + throw Thread::Stack_alloc_failed(); + + /* update stack information */ + _base -= ds_size; + }, + [&] (Region_map::Attach_error) { + throw Thread::Stack_alloc_failed(); } + ); + }, + [&] (Ram_allocator::Alloc_error) { + throw Thread::Stack_alloc_failed(); } + ); } @@ -91,27 +109,53 @@ Thread::_alloc_stack(size_t stack_size, char const *name, bool main_thread) if (sizeof(Native_utcb) >= (1 << PAGE_SIZE_LOG2)) ds_addr -= sizeof(Native_utcb); + Ram_allocator &ram = *env_stack_area_ram_allocator; + /* allocate and attach backing store for the stack */ - Ram_dataspace_capability ds_cap; - try { - ds_cap = env_stack_area_ram_allocator->alloc(ds_size); - addr_t attach_addr = ds_addr - stack_area_virtual_base(); - if (attach_addr != (addr_t)env_stack_area_region_map->attach_at(ds_cap, attach_addr, ds_size)) - throw Stack_alloc_failed(); - } - catch (Out_of_ram) { throw Stack_alloc_failed(); } + return ram.try_alloc(ds_size).convert( - /* - * Now the stack is backed by memory, so it is safe to access its members. - * - * We need to initialize the stack object's memory with zeroes, otherwise - * the ds_cap isn't invalid. That would cause trouble when the assignment - * operator of Native_capability is used. - */ - construct_at(stack, name, *this, ds_addr, ds_cap); + [&] (Ram_dataspace_capability const ds_cap) + { + addr_t const attach_addr = ds_addr - stack_area_virtual_base(); - Abi::init_stack(stack->top()); - return stack; + return env_stack_area_region_map->attach(ds_cap, Region_map::Attr { + .size = ds_size, + .offset = { }, + .use_at = true, + .at = attach_addr, + .executable = { }, + .writeable = true + }).convert( + + [&] (Region_map::Range const range) -> Stack * { + if (range.start != attach_addr) { + ram.free(ds_cap); + throw Stack_alloc_failed(); + } + + /* + * Now the stack is backed by memory, it is safe to access + * its members. + * + * We need to initialize the stack object's memory with + * zeroes, otherwise the ds_cap isn't invalid. That would + * cause trouble when the assignment operator of + * Native_capability is used. + */ + construct_at(stack, name, *this, ds_addr, ds_cap); + + Abi::init_stack(stack->top()); + return stack; + }, + [&] (Region_map::Attach_error) -> Stack * { + ram.free(ds_cap); + throw Stack_alloc_failed(); + } + ); + }, + [&] (Ram_allocator::Alloc_error) -> Stack * { + throw Stack_alloc_failed(); } + ); } @@ -123,7 +167,7 @@ void Thread::_free_stack(Stack *stack) /* call de-constructor explicitly before memory gets detached */ stack->~Stack(); - Genode::env_stack_area_region_map->detach((void *)ds_addr); + Genode::env_stack_area_region_map->detach(ds_addr); Genode::env_stack_area_ram_allocator->free(ds_cap); /* stack ready for reuse */ @@ -133,7 +177,7 @@ void Thread::_free_stack(Stack *stack) void Thread::name(char *dst, size_t dst_len) { - snprintf(dst, dst_len, "%s", _stack->name().string()); + copy_cstring(dst, name().string(), dst_len); } @@ -212,31 +256,48 @@ Thread::Thread(size_t weight, const char *name, size_t stack_size, void Thread::_init_cpu_session_and_trace_control() { + if (!cpu_session_ptr || !local_rm_ptr) { + error("missing call of init_thread"); + return; + } + /* if no CPU session is given, use it from the environment */ if (!_cpu_session) { - _cpu_session = env_deprecated()->cpu_session(); } + _cpu_session = cpu_session_ptr; } /* initialize trace control now that the CPU session must be valid */ Dataspace_capability ds = _cpu_session->trace_control(); if (ds.valid()) { - _trace_control = env_deprecated()->rm_session()->attach(ds); } + Region_map::Attr attr { }; + attr.writeable = true; + local_rm_ptr->attach(ds, attr).with_result( + [&] (Region_map::Range range) { + _trace_control = reinterpret_cast(range.start); }, + [&] (Region_map::Attach_error) { + error("failed to initialize trace control for new thread"); } + ); + } } Thread::Thread(size_t weight, const char *name, size_t stack_size, Type type, Affinity::Location affinity) -: Thread(weight, name, stack_size, type, nullptr, affinity) { } +: + Thread(weight, name, stack_size, type, cpu_session_ptr, affinity) +{ } -Thread::Thread(Env &env, Name const &name, size_t stack_size, Location location, +Thread::Thread(Env &, Name const &name, size_t stack_size, Location location, Weight weight, Cpu_session &cpu) -: Thread(weight.value, name.string(), stack_size, NORMAL, - &cpu == &env.cpu() ? nullptr : &cpu, location) +: + Thread(weight.value, name.string(), stack_size, NORMAL, &cpu, location) { } Thread::Thread(Env &env, Name const &name, size_t stack_size) -: Thread(env, name, stack_size, Location(), Weight(), env.cpu()) { } +: + Thread(env, name, stack_size, Location(), Weight(), env.cpu()) +{ } Thread::~Thread() @@ -258,6 +319,13 @@ Thread::~Thread() * from here and any following RPC call will stumple upon the * detached trace control dataspace. */ - if (_trace_control) - env_deprecated()->rm_session()->detach(_trace_control); + if (_trace_control && local_rm_ptr) + local_rm_ptr->detach(addr_t(_trace_control)); +} + + +void Genode::init_thread(Cpu_session &cpu_session, Region_map &local_rm) +{ + local_rm_ptr = &local_rm; + cpu_session_ptr = &cpu_session; } diff --git a/repos/base/src/lib/base/thread_start.cc b/repos/base/src/lib/base/thread_start.cc index cdc4f1fe6a..5b6d619850 100644 --- a/repos/base/src/lib/base/thread_start.cc +++ b/repos/base/src/lib/base/thread_start.cc @@ -17,14 +17,21 @@ #include #include #include -#include /* base-internal includes */ #include +#include using namespace Genode; +static Capability pd_session_cap(Capability pd_cap = { }) +{ + static Capability cap = pd_cap; /* defined once by 'init_thread_start' */ + return cap; +} + + /** * Entry point entered by new threads */ @@ -59,24 +66,38 @@ void Thread::_thread_start() void Thread::_deinit_platform_thread() { - if (!_cpu_session) - _cpu_session = env_deprecated()->cpu_session(); + if (!_cpu_session) { + error("Thread::_cpu_session unexpectedly not defined"); + return; + } - _cpu_session->kill_thread(_thread_cap); + _thread_cap.with_result( + [&] (Thread_capability cap) { _cpu_session->kill_thread(cap); }, + [&] (auto) { }); } -void Thread::start() +Thread::Start_result Thread::start() { _init_cpu_session_and_trace_control(); /* create thread at core */ addr_t const utcb = (addr_t)&_stack->utcb(); - _thread_cap = _cpu_session->create_thread(env_deprecated()->pd_session_cap(), name(), - _affinity, Weight(), utcb); - if (!_thread_cap.valid()) - throw Cpu_session::Thread_creation_failed(); - /* start execution at initial instruction pointer and stack pointer */ - Cpu_thread_client(_thread_cap).start((addr_t)_thread_start, _stack->top()); + _thread_cap = _cpu_session->create_thread(pd_session_cap(), name(), _affinity, + Weight(), utcb); + return _thread_cap.convert( + [&] (Thread_capability cap) { + + /* start execution at initial instruction pointer and stack pointer */ + Cpu_thread_client(cap).start((addr_t)_thread_start, _stack->top()); + return Start_result::OK; + }, + [&] (Cpu_session::Create_thread_error) { return Start_result::DENIED; }); +} + + +void Genode::init_thread_start(Capability pd_cap) +{ + pd_session_cap(pd_cap); } diff --git a/repos/base/src/lib/base/trace.cc b/repos/base/src/lib/base/trace.cc index d3d72321cb..c0183529bb 100644 --- a/repos/base/src/lib/base/trace.cc +++ b/repos/base/src/lib/base/trace.cc @@ -60,13 +60,13 @@ bool Trace::Logger::_evaluate_control() /* unload policy */ if (policy_module) { - _env().rm().detach(policy_module); + _env().rm().detach(addr_t(policy_module)); policy_module = 0; } /* unmap trace buffer */ if (buffer) { - _env().rm().detach(buffer); + _env().rm().detach(addr_t(buffer)); buffer = 0; } @@ -97,29 +97,31 @@ bool Trace::Logger::_evaluate_control() return false; } - try { - max_event_size = 0; - policy_module = 0; + max_event_size = 0; + policy_module = nullptr; - enum { - MAX_SIZE = 0, NO_OFFSET = 0, ANY_LOCAL_ADDR = false, - EXECUTABLE = true - }; + _env().rm().attach(policy_ds, { + .size = { }, .offset = { }, + .use_at = { }, .at = { }, + .executable = true, .writeable = true, + }).with_result( + [&] (Region_map::Range range) { + policy_module = reinterpret_cast(range.start); }, + [&] (Region_map::Attach_error) { error("failed to attach trace policy"); } + ); - policy_module = _env().rm().attach(policy_ds, MAX_SIZE, NO_OFFSET, - ANY_LOCAL_ADDR, nullptr, EXECUTABLE); + if (!policy_module) + return false; - /* relocate function pointers of policy callback table */ - for (unsigned i = 0; i < sizeof(Trace::Policy_module)/sizeof(void *); i++) { - ((addr_t *)policy_module)[i] += (addr_t)(policy_module); - } + /* relocate function pointers of policy callback table */ + for (unsigned i = 0; i < sizeof(Trace::Policy_module)/sizeof(void *); i++) { + ((addr_t *)policy_module)[i] += (addr_t)(policy_module); + } - max_event_size = policy_module->max_event_size(); - - } catch (...) { } + max_event_size = policy_module->max_event_size(); /* obtain buffer */ - buffer = 0; + buffer = nullptr; Dataspace_capability buffer_ds = Cpu_thread_client(thread_cap).trace_buffer(); if (!buffer_ds.valid()) { @@ -129,11 +131,16 @@ bool Trace::Logger::_evaluate_control() return false; } - try { - buffer = _env().rm().attach(buffer_ds); - buffer->init(Dataspace_client(buffer_ds).size()); - } catch (...) { } + Region_map::Attr attr { }; + attr.writeable = true; + _env().rm().attach(buffer_ds, attr).with_result( + [&] (Region_map::Range range) { + buffer = reinterpret_cast(range.start); }, + [&] (Region_map::Attach_error) { error("failed to attach trace buffer"); }); + if (!buffer) + return false; + buffer->init(Dataspace_client(buffer_ds).size()); policy_version = control->policy_version(); } @@ -222,20 +229,31 @@ Trace::Logger *Thread::_logger() if (!logger.initialized()) { logger.init_pending(true); - Thread_capability thread_cap = myself ? myself->_thread_cap - : _env().parent().main_thread_cap(); + using Create_result = Cpu_session::Create_thread_result; + Create_result const thread_cap = + myself ? myself->_thread_cap + : Create_result(_env().parent().main_thread_cap()); Cpu_session &cpu = myself ? *myself->_cpu_session : _env().cpu(); - if (!myself) - if (!main_trace_control) { - Dataspace_capability ds = _env().cpu().trace_control(); - if (ds.valid()) - main_trace_control = _env().rm().attach(ds); + if (!myself && !main_trace_control) { + Dataspace_capability ds = _env().cpu().trace_control(); + if (ds.valid()) { + Region_map::Attr attr { }; + attr.writeable = true; + _env().rm().attach(ds, attr).with_result( + [&] (Region_map::Range range) { + main_trace_control = reinterpret_cast(range.start); }, + [&] (Region_map::Attach_error) { + error("failed to attach trace control"); }); } + } - logger.init(thread_cap, &cpu, - myself ? myself->_trace_control : main_trace_control); + thread_cap.with_result( + [&] (Thread_capability cap) { + logger.init(cap, &cpu, myself ? myself->_trace_control + : main_trace_control); }, + [&] (Cpu_session::Create_thread_error) { }); } return &logger; diff --git a/repos/base/src/lib/base/trace_buffer.cc b/repos/base/src/lib/base/trace_buffer.cc index 9e3badfe00..30fbe37148 100644 --- a/repos/base/src/lib/base/trace_buffer.cc +++ b/repos/base/src/lib/base/trace_buffer.cc @@ -81,7 +81,7 @@ Trace::Simple_buffer &Trace::Partitioned_buffer::_switch_producer() * consumer may still switch partitions at this point but not continue * reading until we set the new head entry */ - _lost_entries += _producer()._num_entries; + _lost_entries = _lost_entries + _producer()._num_entries; switched = true; } } @@ -92,7 +92,7 @@ Trace::Simple_buffer &Trace::Partitioned_buffer::_switch_producer() /* XXX _wrapped only needed for testing */ if (State::Producer::get(_state) == PRIMARY) - _wrapped++; + _wrapped = _wrapped + 1; Genode::memory_barrier(); _consumer_lock = SPINLOCK_UNLOCKED; @@ -110,4 +110,4 @@ char *Trace::Partitioned_buffer::reserve(size_t len) void Trace::Partitioned_buffer::commit(size_t len) { - _producer()._commit(len, [&] () { _switch_producer(); }); } + _producer()._commit(len, [&] { _switch_producer(); }); } diff --git a/repos/base/src/lib/base/vm.cc b/repos/base/src/lib/base/vm.cc index 1e2aa96a66..fa2c76f49d 100644 --- a/repos/base/src/lib/base/vm.cc +++ b/repos/base/src/lib/base/vm.cc @@ -2,11 +2,12 @@ * \brief Generic VM-connection implementation * \author Alexander Boettcher * \author Christian Helmuth + * \author Benjamin Lamowski * \date 2018-08-27 */ /* - * Copyright (C) 2018-2021 Genode Labs GmbH + * Copyright (C) 2018-2023 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -21,22 +22,9 @@ struct Vm_session::Native_vcpu { }; static Vm_session::Native_vcpu dummy; - -void Vm_connection::Vcpu::run() { } - - -void Vm_connection::Vcpu::pause() { } - - struct Genode::Vcpu_state { }; -Vcpu_state & Vm_connection::Vcpu::state() -{ - static char dummy[sizeof(Vcpu_state)]; - - return *(Vcpu_state *)dummy; -} - +void Vm_connection::Vcpu::_with_state(Call_with_state &) {}; Vm_connection::Vcpu::Vcpu(Vm_connection &, Allocator &, Vcpu_handler_base &, Exit_config const &) diff --git a/repos/base/src/lib/cxx/exception.cc b/repos/base/src/lib/cxx/exception.cc index 5adec5c989..20afd9bd78 100644 --- a/repos/base/src/lib/cxx/exception.cc +++ b/repos/base/src/lib/cxx/exception.cc @@ -51,11 +51,7 @@ extern "C" int dl_iterate_phdr(int (*) (void *, unsigned long, void *), void *) return -1; } -/* - * Terminate handler - */ - -void terminate_handler() +static void terminate_handler() { std::type_info *t = __cxxabiv1::__cxa_current_exception_type(); @@ -74,25 +70,9 @@ void terminate_handler() } -/** - * Init program headers of the dynamic linker - * - * The weak function is used for statically linked binaries. The - * dynamic linker provides an implementation that loads the program - * headers of the linker. This must be done before the first exception - * is thrown. - */ -void Genode::init_ldso_phdr(Env &) __attribute__((weak)); -void Genode::init_ldso_phdr(Env &) { } - - -/* - * Initialization - */ -void Genode::init_exception_handling(Env &env) +void Genode::init_exception_handling(Ram_allocator &ram, Region_map &rm) { - init_ldso_phdr(env); - init_cxx_heap(env); + init_cxx_heap(ram, rm); __register_frame(__eh_frame_start__); diff --git a/repos/base/src/lib/cxx/guard.cc b/repos/base/src/lib/cxx/guard.cc index 4c8c599fda..55324eaec5 100644 --- a/repos/base/src/lib/cxx/guard.cc +++ b/repos/base/src/lib/cxx/guard.cc @@ -21,7 +21,7 @@ #include -typedef Genode::Registry > Blockers; +using Blockers = Genode::Registry >; static Blockers *blockers_ptr; @@ -53,7 +53,7 @@ namespace __cxxabiv1 * registry and will be woken up by the thread releasing a guard. */ - typedef int __guard; + using __guard = int; extern "C" int __cxa_guard_acquire(__guard *guard) { diff --git a/repos/base/src/lib/cxx/malloc_free.cc b/repos/base/src/lib/cxx/malloc_free.cc index a5191dc96e..7b744c5545 100644 --- a/repos/base/src/lib/cxx/malloc_free.cc +++ b/repos/base/src/lib/cxx/malloc_free.cc @@ -15,7 +15,6 @@ */ /* Genode includes */ -#include #include #include #include @@ -33,8 +32,11 @@ static Heap *cxx_heap_ptr; Heap &cxx_heap() { class Cxx_heap_uninitialized : Exception { }; - if (!cxx_heap_ptr) + if (!cxx_heap_ptr) { + raw("Cxx_heap_uninitialized"); + for (;;); throw Cxx_heap_uninitialized(); + } return *cxx_heap_ptr; } @@ -47,7 +49,7 @@ Heap &cxx_heap() * '__cxa_allocate_exception', which, in turn, calls 'malloc'. The cxx library * uses a local implementation of 'malloc' using a dedicated heap instance. */ -void Genode::init_cxx_heap(Env &env) +void Genode::init_cxx_heap(Ram_allocator &ram, Region_map &rm) { /* * Exception frames are small. Hence, a small static backing store suffices @@ -56,12 +58,12 @@ void Genode::init_cxx_heap(Env &env) */ static char initial_block[1024*sizeof(long)]; - cxx_heap_ptr = unmanaged_singleton(&env.ram(), &env.rm(), Heap::UNLIMITED, + cxx_heap_ptr = unmanaged_singleton(&ram, &rm, Heap::UNLIMITED, initial_block, sizeof(initial_block)); } -typedef unsigned long Block_header; +using Block_header = unsigned long; extern "C" void *malloc(size_t size) diff --git a/repos/base/src/lib/ldso/dependency.cc b/repos/base/src/lib/ldso/dependency.cc index cb30c0c624..3ef42b37c7 100644 --- a/repos/base/src/lib/ldso/dependency.cc +++ b/repos/base/src/lib/ldso/dependency.cc @@ -84,6 +84,16 @@ void Linker::Dependency::preload(Env &env, Allocator &alloc, void Linker::Dependency::load_needed(Env &env, Allocator &md_alloc, Fifo &deps, Keep keep) { + /* + * Load 'posix.lib.so' first, if it is a dependency, to satisfy + * the invariant of the libc fork/execve mechanism that this + * library and its dependencies are always loaded in the same + * order. + */ + _obj.dynamic().for_each_dependency([&] (char const *path) { + if (strcmp(path, "posix.lib.so") == 0) + _load(env, md_alloc, path, deps, keep); }); + _obj.dynamic().for_each_dependency([&] (char const *path) { _load(env, md_alloc, path, deps, keep); }); } diff --git a/repos/base/src/lib/ldso/include/config.h b/repos/base/src/lib/ldso/include/config.h index 2ad11c87a2..d4d9c3d8b5 100644 --- a/repos/base/src/lib/ldso/include/config.h +++ b/repos/base/src/lib/ldso/include/config.h @@ -58,15 +58,14 @@ class Linker::Config : Noncopyable bool verbose() const { return _verbose; } bool check_ctors() const { return _check_ctors; } - typedef String<100> Rom_name; + using Rom_name = String<100>; /** * Call fn for each library specified in the configuration * * The functor 'fn' is called with 'Rom_name', 'Keep' as arguments. */ - template - void for_each_library(FN const &fn) const + void for_each_library(auto const &fn) const { _config.with_optional_sub_node("ld", [&] (Xml_node ld) { diff --git a/repos/base/src/lib/ldso/include/dynamic.h b/repos/base/src/lib/ldso/include/dynamic.h index 94ee9e8be0..d31247a70f 100644 --- a/repos/base/src/lib/ldso/include/dynamic.h +++ b/repos/base/src/lib/ldso/include/dynamic.h @@ -72,9 +72,9 @@ class Linker::Dynamic struct Needed : Fifo::Element { - off_t offset; + addr_t offset; - Needed(off_t offset) : offset(offset) { } + Needed(addr_t offset) : offset(offset) { } char const *path(char const *strtab) { @@ -307,8 +307,7 @@ class Linker::Dynamic /** * Call functor for each dependency, passing the path as argument */ - template - void for_each_dependency(FUNC const &fn) const + void for_each_dependency(auto const &fn) const { _needed.for_each([&] (Needed &n) { fn(n.path(_strtab)); }); diff --git a/repos/base/src/lib/ldso/include/elf.h b/repos/base/src/lib/ldso/include/elf.h index 1c908bca3b..2b59bf559c 100644 --- a/repos/base/src/lib/ldso/include/elf.h +++ b/repos/base/src/lib/ldso/include/elf.h @@ -23,36 +23,36 @@ namespace Linker { /* standard ELF types. */ /* type for a 16-bit quantity. */ - typedef genode_uint16_t Elf32_Half; - typedef genode_uint16_t Elf64_Half; + using Elf32_Half = genode_uint16_t; + using Elf64_Half = genode_uint16_t; /* types for signed and unsigned 32-bit quantities */ - typedef genode_uint32_t Elf32_Word; - typedef genode_int32_t Elf32_Sword; - typedef genode_uint32_t Elf64_Word; - typedef genode_int32_t Elf64_Sword; + using Elf32_Word = genode_uint32_t; + using Elf32_Sword = genode_int32_t; + using Elf64_Word = genode_uint32_t; + using Elf64_Sword = genode_int32_t; /* types for signed and unsigned 64-bit quantities */ - typedef genode_uint64_t Elf32_Xword; - typedef genode_int64_t Elf32_Sxword; - typedef genode_uint64_t Elf64_Xword; - typedef genode_int64_t Elf64_Sxword; + using Elf32_Xword = genode_uint64_t; + using Elf32_Sxword = genode_int64_t; + using Elf64_Xword = genode_uint64_t; + using Elf64_Sxword = genode_int64_t; /* type of addresses */ - typedef genode_uint32_t Elf32_Addr; - typedef genode_uint64_t Elf64_Addr; + using Elf32_Addr = genode_uint32_t; + using Elf64_Addr = genode_uint64_t; /* type of file offsets */ - typedef genode_uint32_t Elf32_Off; - typedef genode_uint64_t Elf64_Off; + using Elf32_Off = genode_uint32_t; + using Elf64_Off = genode_uint64_t; /* type for section indices, which are 16-bit quantities */ - typedef genode_uint16_t Elf32_Section; - typedef genode_uint16_t Elf64_Section; + using Elf32_Section = genode_uint16_t; + using Elf64_Section = genode_uint16_t; /* type for version symbol information */ - typedef Elf32_Half Elf32_Versym; - typedef Elf64_Half Elf64_Versym; + using Elf32_Versym = Elf32_Half; + using Elf64_Versym = Elf64_Half; /** * Fields in the e_ident array of ELF file header The EI_* macros are indices @@ -210,10 +210,10 @@ namespace Linker { namespace Elf32 { - typedef Elf32_Addr Addr; - typedef Elf32_Word Hashelt; - typedef Elf32_Word Size; - typedef Elf32_Half Half; + using Addr = Elf32_Addr; + using Hashelt = Elf32_Word; + using Size = Elf32_Word; + using Half = Elf32_Half; /** * The ELF file header @@ -329,10 +329,10 @@ namespace Linker { namespace Elf64 { - typedef Elf64_Addr Addr; - typedef Elf64_Word Hashelt; - typedef Elf64_Xword Size; - typedef Elf64_Half Half; + using Addr = Elf64_Addr; + using Hashelt = Elf64_Word; + using Size = Elf64_Xword; + using Half = Elf64_Half; /** * ELF header diff --git a/repos/base/src/lib/ldso/include/file.h b/repos/base/src/lib/ldso/include/file.h index cee8fed73e..d9bab80e37 100644 --- a/repos/base/src/lib/ldso/include/file.h +++ b/repos/base/src/lib/ldso/include/file.h @@ -74,8 +74,7 @@ struct Linker::File unsigned elf_phdr_count() const { return phdr.count; } - template - void with_rw_phdr(FN const &fn) const + void with_rw_phdr(auto const &fn) const { for (unsigned i = 0; i < phdr.count; i++) { if (is_rw(phdr.phdr[i])) { @@ -98,23 +97,27 @@ struct Linker::Elf_file : File Ram_dataspace_capability ram_cap[Phdr::MAX_PHDR]; bool const loaded; - typedef String<64> Name; + using Name = String<64>; Rom_dataspace_capability _rom_dataspace(Name const &name) { /* request the linker and binary from the component environment */ - Session_capability cap; + Parent::Session_cap_result cap = Parent::Session_cap_error::DENIED; if (name == binary_name()) cap = env.parent().session_cap(Parent::Env::binary()); if (name == linker_name()) cap = env.parent().session_cap(Parent::Env::linker()); - if (cap.valid()) { - Rom_session_client client(reinterpret_cap_cast(cap)); - return client.dataspace(); - } - rom_connection.construct(env, name.string()); - return rom_connection->dataspace(); + return cap.convert( + [&] (Capability cap) { + Rom_session_client client(reinterpret_cap_cast(cap)); + return client.dataspace(); + }, + [&] (Parent::Session_cap_error) { + rom_connection.construct(env, name.string()); + return rom_connection->dataspace(); + } + ); } void _allocate_region_within_linker_area(Name const &name) @@ -137,8 +140,17 @@ struct Linker::Elf_file : File || (name == "posix.lib.so") || (strcmp(name.string(), "vfs", 3) == 0); - reloc_base = resident ? Region_map::r()->alloc_region_at_end(size) - : Region_map::r()->alloc_region(size); + Region_map::Alloc_region_result const allocated_region = + resident ? Region_map::r()->alloc_region_at_end(size) + : Region_map::r()->alloc_region(size); + + reloc_base = allocated_region.convert( + [&] (addr_t base) { return base; }, + [&] (Region_map::Alloc_region_error) { return 0UL; }); + + if (!reloc_base) + error("failed to allocate region within linker area"); + start = 0; } @@ -292,10 +304,15 @@ struct Linker::Elf_file : File */ void load_segment_rx(Elf::Phdr const &p) { - Region_map::r()->attach_executable(rom_cap, - trunc_page(p.p_vaddr) + reloc_base, - round_page(p.p_memsz), - trunc_page(p.p_offset)); + if (Region_map::r()->attach(rom_cap, Region_map::Attr { + .size = round_page(p.p_memsz), + .offset = trunc_page(p.p_offset), + .use_at = true, + .at = trunc_page(p.p_vaddr) + reloc_base, + .executable = true, + .writeable = false + }).failed()) + error("failed to load RX segment"); } /** @@ -303,19 +320,46 @@ struct Linker::Elf_file : File */ void load_segment_rw(Elf::Phdr const &p, int nr) { - void *src = env.rm().attach(rom_cap, 0, p.p_offset); - addr_t dst = p.p_vaddr + reloc_base; + void * const src = env.rm().attach(rom_cap, Region_map::Attr { + .size = { }, + .offset = p.p_offset, + .use_at = { }, + .at = { }, + .executable = { }, + .writeable = true + }).convert( + [&] (Genode::Region_map::Range range) { return (void *)range.start; }, + [&] (Genode::Region_map::Attach_error) { return nullptr; } + ); + if (!src) { + error("dynamic linker failed to locally map RW segment ", nr); + return; + } + + addr_t const dst = p.p_vaddr + reloc_base; ram_cap[nr] = env.ram().alloc(p.p_memsz); - Region_map::r()->attach_at(ram_cap[nr], dst); - memcpy((void*)dst, src, p.p_filesz); + Region_map::r()->attach(ram_cap[nr], Region_map::Attr { + .size = { }, + .offset = { }, + .use_at = true, + .at = dst, + .executable = { }, + .writeable = true + }).with_result( + [&] (Genode::Region_map::Range) { - /* clear if file size < memory size */ - if (p.p_filesz < p.p_memsz) - memset((void *)(dst + p.p_filesz), 0, p.p_memsz - p.p_filesz); + memcpy((void*)dst, src, p.p_filesz); - env.rm().detach(src); + /* clear if file size < memory size */ + if (p.p_filesz < p.p_memsz) + memset((void *)(dst + p.p_filesz), 0, p.p_memsz - p.p_filesz); + }, + [&] (Genode::Region_map::Attach_error) { + error("dynamic linker failed to copy RW segment"); } + ); + env.rm().detach(addr_t(src)); } /** diff --git a/repos/base/src/lib/ldso/include/linker.h b/repos/base/src/lib/ldso/include/linker.h index 05a2b5cc45..afacac9de9 100644 --- a/repos/base/src/lib/ldso/include/linker.h +++ b/repos/base/src/lib/ldso/include/linker.h @@ -145,7 +145,7 @@ class Linker::Object : private Fifo::Element, public: - typedef String<128> Name; + using Name = String<128>; class Object_list; protected: @@ -162,10 +162,11 @@ class Linker::Object : private Fifo::Element, public: - void init(Name const &name, Elf::Addr reloc_base) + void init(char const *name, Elf::Addr reloc_base) { - _name = name; _reloc_base = reloc_base; + + if (name) _name = name; } void init(Name const &name, File const &file) @@ -196,18 +197,16 @@ class Linker::Object : private Fifo::Element, _fifo.remove(obj); } - template - void for_each(FUNC const &func) + void for_each(auto const &fn) { Mutex::Guard guard(_mutex); - _fifo.for_each(func); + _fifo.for_each(fn); } }; - template - static void with_object_list(FUNC const func) + static void with_object_list(auto const &fn) { - func(_object_list()); + fn(_object_list()); } virtual ~Object() { } @@ -266,11 +265,10 @@ namespace Linker { /** * Apply func to each object */ - template - void for_each_object(FUNC const &func) + void for_each_object(auto const &fn) { Object::with_object_list([&] (Object::Object_list &list) { - list.for_each(func); }); + list.for_each(fn); }); } } diff --git a/repos/base/src/lib/ldso/include/region_map.h b/repos/base/src/lib/ldso/include/region_map.h index 3078e5b41d..bbec312610 100644 --- a/repos/base/src/lib/ldso/include/region_map.h +++ b/repos/base/src/lib/ldso/include/region_map.h @@ -39,11 +39,6 @@ namespace Linker { */ class Linker::Region_map { - public: - - typedef Region_map_client::Local_addr Local_addr; - typedef Region_map_client::Region_conflict Region_conflict; - private: Env &_env; @@ -56,80 +51,84 @@ class Linker::Region_map Region_map(Env &env, Allocator &md_alloc, addr_t base) : - _env(env), _range(&md_alloc), - _base((addr_t)_env.rm().attach_at(_rm.dataspace(), base)) + _env(env), _range(&md_alloc), _base(base) { - _range.add_range(base, Pd_session::LINKER_AREA_SIZE); + _env.rm().attach(_rm.dataspace(), Genode::Region_map::Attr { + .size = 0, + .offset = 0, + .use_at = true, + .at = _base, + .executable = true, + .writeable = true + }).with_result( + [&] (Genode::Region_map::Range) { + _range.add_range(base, Pd_session::LINKER_AREA_SIZE); - if (Linker::verbose) - log(" ", Hex(base), - " .. ", Hex(base + Pd_session::LINKER_AREA_SIZE - 1), - ": linker area"); + if (Linker::verbose) + log(" ", Hex(base), + " .. ", Hex(base + Pd_session::LINKER_AREA_SIZE - 1), + ": linker area"); + }, + [&] (Genode::Region_map::Attach_error) { + error("failed to locally attach linker area"); } + ); } public: - typedef Constructible Constructible_region_map; + using Constructible_region_map = Constructible; static Constructible_region_map &r(); + using Alloc_region_error = Ram_allocator::Alloc_error; + using Alloc_region_result = Attempt; + using Attach_result = Genode::Region_map::Attach_result; + using Attr = Genode::Region_map::Attr; + /** * Allocate region anywhere within the region map - * - * XXX propagate OUT_OF_RAM, OUT_OF_CAPS */ - addr_t alloc_region(size_t size) + Alloc_region_result alloc_region(size_t size) { - return _range.alloc_aligned(size, get_page_size_log2()).convert( - [&] (void *ptr) { return (addr_t)ptr; }, - [&] (Allocator::Alloc_error) -> addr_t { throw Region_conflict(); }); + return _range.alloc_aligned(size, get_page_size_log2()).convert( + [&] (void *ptr) { return (addr_t)ptr; }, + [&] (Allocator::Alloc_error e) { return e; }); } /** * Allocate region at specified 'vaddr' */ - void alloc_region_at(size_t size, addr_t vaddr) + Alloc_region_result alloc_region_at(size_t size, addr_t vaddr) { - if (_range.alloc_addr(size, vaddr).failed()) - throw Region_conflict(); + return _range.alloc_addr(size, vaddr).convert( + [&] (void *ptr) { return (addr_t)ptr; }, + [&] (Allocator::Alloc_error e) { return e; }); } - addr_t alloc_region_at_end(size_t size) + Alloc_region_result alloc_region_at_end(size_t size) { _end -= align_addr(size, get_page_size_log2()); - alloc_region_at(size, _end); - return _end; + return alloc_region_at(size, _end); } void free_region(addr_t vaddr) { _range.free((void *)vaddr); } - /** - * Overwritten from 'Region_map_client' - */ - Local_addr attach_at(Dataspace_capability ds, addr_t local_addr, - size_t size = 0, off_t offset = 0) + Attach_result attach(Dataspace_capability ds, Attr attr) { - return retry( - [&] () { - return _rm.attach_at(ds, local_addr - _base, size, offset); + if (!attr.use_at) + error("unexpected arguments of Linker::Region_map::attach"); + + attr.at -= _base; + return _rm.attach(ds, attr).convert( + [&] (Genode::Region_map::Range range) { + range.start += _base; + return range; }, - [&] () { _env.upgrade(Parent::Env::pd(), "ram_quota=8K"); }); + [&] (Genode::Region_map::Attach_error e) { return e; } + ); } - /** - * Overwritten from 'Region_map_client' - */ - Local_addr attach_executable(Dataspace_capability ds, addr_t local_addr, - size_t size = 0, off_t offset = 0) - { - return retry( - [&] () { - return _rm.attach_executable(ds, local_addr - _base, size, offset); - }, - [&] () { _env.upgrade(Parent::Env::pd(), "ram_quota=8K"); }); - } - - void detach(Local_addr local_addr) { _rm.detach((addr_t)local_addr - _base); } + void detach(addr_t local_addr) { _rm.detach(local_addr - _base); } }; #endif /* _INCLUDE__REGION_MAP_H_ */ diff --git a/repos/base/src/lib/ldso/include/relocation_generic.h b/repos/base/src/lib/ldso/include/relocation_generic.h index 4ba6a707bf..c20ad2da56 100644 --- a/repos/base/src/lib/ldso/include/relocation_generic.h +++ b/repos/base/src/lib/ldso/include/relocation_generic.h @@ -16,6 +16,9 @@ #include +/* the R__NONE relocation is 0 for all supported architectures */ +static constexpr int R_NONE = 0; + constexpr bool verbose_relocation = false; static inline bool verbose_reloc(Linker::Dependency const &d) @@ -66,7 +69,9 @@ struct Linker::Reloc_plt_generic Elf::Rel const *start, unsigned long size) { if (type != TYPE) { - error("LD: Unsupported PLT relocation type: ", (int)type); + error("LD: Unsupported translation table address format.", + " Expected ", TYPE, " got ", unsigned(type), ".", + " Type can only be DT_REL or DT_RELA not both."); throw Incompatible(); } @@ -74,6 +79,9 @@ struct Linker::Reloc_plt_generic REL const *end = rel + (size / sizeof(REL)); for (; rel < end; rel++) { + /* do nothing */ + if (rel->type() == R_NONE) continue; + if (rel->type() != JMPSLOT) { error("LD: Unsupported PLT relocation ", (int)rel->type()); throw Incompatible(); @@ -98,8 +106,7 @@ class Linker::Reloc_non_plt_generic * safely here since all other DSO are loaded, relocated, and constructed at * this point */ - template - void _copy(REL const *rel, Elf::Addr *addr) + void _copy(auto const *rel, Elf::Addr *addr) { if (!_dep.obj().is_binary()) { error("LD: copy relocation in DSO " diff --git a/repos/base/src/lib/ldso/main.cc b/repos/base/src/lib/ldso/main.cc index 1b3d9d2906..c9b21c3d52 100644 --- a/repos/base/src/lib/ldso/main.cc +++ b/repos/base/src/lib/ldso/main.cc @@ -107,7 +107,7 @@ class Linker::Elf_object : public Object, private Fifo::Element Constructible _elf_file { }; - bool _object_init(Object::Name const &name, Elf::Addr reloc_base) + bool _object_init(char const *name, Elf::Addr reloc_base) { Object::init(name, reloc_base); return true; @@ -126,7 +126,7 @@ class Linker::Elf_object : public Object, private Fifo::Element public: - Elf_object(Dependency const &dep, Object::Name const &name, + Elf_object(Dependency const &dep, char const *name, Elf::Addr reloc_base) SELF_RELOC : _elf_object_initialized(_object_init(name, reloc_base)), @@ -261,9 +261,9 @@ class Linker::Elf_object : public Object, private Fifo::Element */ struct Linker::Ld : private Dependency, Elf_object { - Ld() SELF_RELOC : + Ld(bool use_name = true) SELF_RELOC : Dependency(*this, nullptr), - Elf_object(*this, linker_name(), relocation_address()) + Elf_object(*this, use_name ? linker_name() : nullptr, relocation_address()) { } void setup_link_map() @@ -337,18 +337,6 @@ Linker::Ld &Linker::Ld::linker() } -/* - * Defined in the startup library, passed to legacy main functions. - */ -extern char **genode_argv; -extern int genode_argc; -extern char **genode_envp; - -static int exit_status; - -static void exit_on_suspended() { genode_exit(exit_status); } - - /** * The dynamic binary to load */ @@ -452,29 +440,6 @@ struct Linker::Binary : private Root_object, public Elf_object return; } - /* - * The 'Component::construct' function is missing. This may be the - * case for legacy components that still implement a 'main' function. - * - * \deprecated the handling of legacy 'main' functions will be removed - */ - if (Elf::Addr addr = lookup_symbol("main")) { - warning("using legacy main function, please convert to 'Component::construct'"); - - /* execute static constructors before calling legacy 'main' */ - finish_static_construction(); - - exit_status = ((int (*)(int, char **, char **))addr)(genode_argc, - genode_argv, - genode_envp); - - /* trigger suspend in the entry point */ - env.ep().schedule_suspend(exit_on_suspended, nullptr); - - /* return to entrypoint and exit via exit_on_suspended() */ - return; - } - error("dynamic linker: component-entrypoint lookup failed"); throw Fatal(); } @@ -656,7 +621,7 @@ extern "C" void init_rtld() * type relocation might produce a wrong vtable pointer (at least on ARM), do * not call any virtual funtions of this object. */ - Ld linker_on_stack; + Ld linker_on_stack { false }; linker_on_stack.relocate(BIND_LAZY); /* init cxa guard mechanism before any local static variables are used */ @@ -687,25 +652,32 @@ void Genode::init_ldso_phdr(Env &env) { struct Not_implemented : Exception { }; - Local_addr attach(Dataspace_capability ds, size_t, off_t, - bool, Local_addr, bool, bool) override + Attach_result attach(Dataspace_capability ds, Attr const &) override { size_t const size = Dataspace_client(ds).size(); Linker::Region_map &linker_area = *Linker::Region_map::r(); - addr_t const at = linker_area.alloc_region_at_end(size); - - (void)linker_area.attach_at(ds, at, size, 0UL); - - return at; + return linker_area.alloc_region_at_end(size).convert( + [&] (addr_t const at) { + return linker_area.attach(ds, Region_map::Attr { + .size = size, + .offset = { }, + .use_at = true, + .at = at, + .executable = { }, + .writeable = true }); + }, + [&] (Linker::Region_map::Alloc_region_error) { + return Attach_error::REGION_CONFLICT; } + ); } - void detach(Local_addr) override { throw Not_implemented(); } + void detach(addr_t) override { throw Not_implemented(); } void fault_handler(Signal_context_capability) override { } - State state() override { throw Not_implemented(); } + Fault fault() override { throw Not_implemented(); } Dataspace_capability dataspace() override { throw Not_implemented(); } diff --git a/repos/base/src/lib/ldso/spec/arm/relocation.h b/repos/base/src/lib/ldso/spec/arm/relocation.h index 1b4ffebb92..66a42d55ca 100644 --- a/repos/base/src/lib/ldso/spec/arm/relocation.h +++ b/repos/base/src/lib/ldso/spec/arm/relocation.h @@ -29,10 +29,10 @@ namespace Linker { class Reloc_non_plt; - typedef Plt_got_generic<2> Plt_got; - typedef Reloc_plt_generic Reloc_plt; - typedef Reloc_jmpslot_generic Reloc_jmpslot; - typedef Reloc_bind_now_generic Reloc_bind_now; + using Plt_got = Plt_got_generic<2>; + using Reloc_plt = Reloc_plt_generic; + using Reloc_jmpslot = Reloc_jmpslot_generic; + using Reloc_bind_now = Reloc_bind_now_generic; }; diff --git a/repos/base/src/lib/ldso/spec/arm_64/jmp_slot.s b/repos/base/src/lib/ldso/spec/arm_64/jmp_slot.s index 7dcccfe2ae..68b1c5cb3c 100644 --- a/repos/base/src/lib/ldso/spec/arm_64/jmp_slot.s +++ b/repos/base/src/lib/ldso/spec/arm_64/jmp_slot.s @@ -35,6 +35,12 @@ _jmp_slot: stp x6, x7, [sp, #-16]! stp x8, xzr, [sp, #-16]! + /* save floating-point arguments */ + stp q0, q1, [sp, #-32]! + stp q2, q3, [sp, #-32]! + stp q4, q5, [sp, #-32]! + stp q6, q7, [sp, #-32]! + /* GOT[1] = Dependency */ ldr x0, [x16, #-8] /* arg 0 */ @@ -52,6 +58,10 @@ _jmp_slot: mov x17, x0 /* restore arguments */ + ldp q6, q7, [sp], #32 + ldp q4, q5, [sp], #32 + ldp q2, q3, [sp], #32 + ldp q0, q1, [sp], #32 ldp x8, xzr, [sp], #16 ldp x6, x7, [sp], #16 ldp x4, x5, [sp], #16 diff --git a/repos/base/src/lib/ldso/spec/arm_64/relocation.h b/repos/base/src/lib/ldso/spec/arm_64/relocation.h index e423491f47..3cc0e45dbd 100644 --- a/repos/base/src/lib/ldso/spec/arm_64/relocation.h +++ b/repos/base/src/lib/ldso/spec/arm_64/relocation.h @@ -33,10 +33,10 @@ namespace Linker { class Reloc_non_plt; - typedef Plt_got_generic<2> Plt_got; - typedef Reloc_plt_generic Reloc_plt; - typedef Reloc_jmpslot_generic Reloc_jmpslot; - typedef Reloc_bind_now_generic Reloc_bind_now; + using Plt_got = Plt_got_generic<2>; + using Reloc_plt = Reloc_plt_generic; + using Reloc_jmpslot = Reloc_jmpslot_generic; + using Reloc_bind_now = Reloc_bind_now_generic; }; class Linker::Reloc_non_plt : public Reloc_non_plt_generic diff --git a/repos/base/src/lib/ldso/spec/riscv/relocation.h b/repos/base/src/lib/ldso/spec/riscv/relocation.h index ca86d2fcf1..8e5fdb0f58 100644 --- a/repos/base/src/lib/ldso/spec/riscv/relocation.h +++ b/repos/base/src/lib/ldso/spec/riscv/relocation.h @@ -38,10 +38,10 @@ namespace Linker { class Reloc_non_plt; - typedef Plt_got_generic<0> Plt_got; - typedef Reloc_plt_generic Reloc_plt; - typedef Reloc_jmpslot_generic Reloc_jmpslot; - typedef Reloc_bind_now_generic Reloc_bind_now; + using Plt_got = Plt_got_generic<0>; + using Reloc_plt = Reloc_plt_generic; + using Reloc_jmpslot = Reloc_jmpslot_generic; + using Reloc_bind_now = Reloc_bind_now_generic; }; class Linker::Reloc_non_plt : public Reloc_non_plt_generic diff --git a/repos/base/src/lib/ldso/spec/x86_32/relocation.h b/repos/base/src/lib/ldso/spec/x86_32/relocation.h index 0b01cf2934..68c48a6af9 100644 --- a/repos/base/src/lib/ldso/spec/x86_32/relocation.h +++ b/repos/base/src/lib/ldso/spec/x86_32/relocation.h @@ -29,10 +29,10 @@ namespace Linker { class Reloc_non_plt; - typedef Plt_got_generic<2> Plt_got; - typedef Reloc_plt_generic Reloc_plt; - typedef Reloc_jmpslot_generic Reloc_jmpslot; - typedef Reloc_bind_now_generic Reloc_bind_now; + using Plt_got = Plt_got_generic<2>; + using Reloc_plt = Reloc_plt_generic; + using Reloc_jmpslot = Reloc_jmpslot_generic; + using Reloc_bind_now = Reloc_bind_now_generic; } diff --git a/repos/base/src/lib/ldso/spec/x86_64/relocation.h b/repos/base/src/lib/ldso/spec/x86_64/relocation.h index a95f15c08f..f28966ffe4 100644 --- a/repos/base/src/lib/ldso/spec/x86_64/relocation.h +++ b/repos/base/src/lib/ldso/spec/x86_64/relocation.h @@ -32,10 +32,10 @@ namespace Linker { class Reloc_non_plt; - typedef Plt_got_generic<2> Plt_got; - typedef Reloc_plt_generic Reloc_plt; - typedef Reloc_jmpslot_generic Reloc_jmpslot; - typedef Reloc_bind_now_generic Reloc_bind_now; + using Plt_got = Plt_got_generic<2>; + using Reloc_plt = Reloc_plt_generic; + using Reloc_jmpslot = Reloc_jmpslot_generic; + using Reloc_bind_now = Reloc_bind_now_generic; }; class Linker::Reloc_non_plt : public Reloc_non_plt_generic diff --git a/repos/base/src/lib/startup/_main.cc b/repos/base/src/lib/startup/_main.cc index 3e8657d0c0..60abdd11c7 100644 --- a/repos/base/src/lib/startup/_main.cc +++ b/repos/base/src/lib/startup/_main.cc @@ -4,53 +4,102 @@ * \author Christian Prochaska * \author Norman Feske * \date 2006-04-12 - * - * The startup code calls constructors for static objects before calling - * main(). Furthermore, this file contains the support of exit handlers - * and destructors. */ /* - * Copyright (C) 2006-2017 Genode Labs GmbH + * Copyright (C) 2006-2023 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. */ /* Genode includes */ -#include -#include -#include -#include +#include /* platform-specific local helper functions */ -#include +#include #include -void * __dso_handle = 0; +using namespace Genode; + + +addr_t init_main_thread_result; + +static Platform *platform_ptr; /** - * Dummy default arguments for main function + * Satisfy crt0.s in static programs, LDSO overrides this symbol */ -static char argv0[] = { '_', 'm', 'a', 'i', 'n', 0}; -static char *argv[1] = { argv0 }; +extern "C" void init_rtld() __attribute__((weak)); +void init_rtld() +{ + /* init cxa guard mechanism before any local static variables are used */ + init_cxx_guard(); +} + +/** + * Lower bound of the stack, solely used for sanity checking + */ +extern unsigned char __initial_stack_base[]; /** - * Arguments for main function + * Create a thread object for the main thread * - * These global variables may be initialized by a constructor provided by an - * external library. + * \return stack pointer of the new environment via init_main_thread_result + * + * This function must be called only once per program and before the _main + * function. It can be called as soon as a temporary environment provides + * some stack space and inter-process communication. At this stage, global + * static objects are not registered for implicit destruction at program exit. */ -char **genode_argv = argv; -int genode_argc = 1; -char **genode_envp = 0; +extern "C" void init_main_thread() +{ + prepare_init_main_thread(); + platform_ptr = &init_platform(); -/****************************************************** - ** C entry function called by the crt0 startup code ** - ******************************************************/ + /* + * Create a 'Thread' object for the main thread + */ + static constexpr size_t STACK_SIZE = 16*1024; + + struct Main_thread : Thread + { + Main_thread() + : + Thread(Weight::DEFAULT_WEIGHT, "main", STACK_SIZE, Type::MAIN) + { } + + void entry() override { /* never executed */ } + }; + + static Main_thread main_thread { }; + + /* + * The new stack pointer enables the caller to switch from its current + * environment to the those that the thread object provides. + */ + addr_t const sp = reinterpret_cast(main_thread.stack_top()); + init_main_thread_result = sp; + + /* + * Sanity check for the usage of the initial stack + * + * Because the initial stack is located in the BSS, it is zero-initialized. + * We check that the stack still contains zeros at its lower boundary after + * executing all the initialization code. + */ + enum { STACK_PAD = 256U }; + for (unsigned i = 0; i < STACK_PAD; i++) { + if (__initial_stack_base[i] == 0) + continue; + + error("initial stack overflow detected"); + for (;;); + } +} namespace Genode { @@ -69,28 +118,13 @@ namespace Genode { void (**func)(); for (func = &_ctors_end; func != &_ctors_start; (*--func)()); } - - /* XXX move to base-internal header */ - extern void bootstrap_component(); } -extern "C" int _main() +extern "C" int _main() /* executed with the stack within the stack area */ { - Genode::bootstrap_component(); + bootstrap_component(*platform_ptr); /* never reached */ return 0; } - - -extern int main(int argc, char **argv, char **envp); - - -void Component::construct(Genode::Env &env) __attribute__((weak)); -void Component::construct(Genode::Env &) -{ - /* call real main function */ - main(genode_argc, genode_argv, genode_envp); -} - diff --git a/repos/base/src/lib/startup/init_main_thread.cc b/repos/base/src/lib/startup/init_main_thread.cc deleted file mode 100644 index fcd7209eaa..0000000000 --- a/repos/base/src/lib/startup/init_main_thread.cc +++ /dev/null @@ -1,128 +0,0 @@ -/* - * \brief Setup the thread environment of a programs first thread - * \author Christian Helmuth - * \author Christian Prochaska - * \author Martin Stein - * \date 2013-12-04 - */ - -/* - * Copyright (C) 2013-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -/* Genode includes */ -#include -#include -#include -#include - -/* base-internal includes */ -#include - -using namespace Genode; - - -addr_t init_main_thread_result; - -extern void init_exception_handling(); - -namespace Genode { extern Region_map * env_stack_area_region_map; } - -void prepare_init_main_thread(); - -enum { MAIN_THREAD_STACK_SIZE = 16*1024 }; - - -/** - * Satisfy crt0.s in static programs, LDSO overrides this symbol - */ -extern "C" void init_rtld() __attribute__((weak)); -void init_rtld() -{ - /* init cxa guard mechanism before any local static variables are used */ - init_cxx_guard(); -} - - -/** - * Lower bound of the stack, solely used for sanity checking - */ -extern unsigned char __initial_stack_base[]; - - -/** - * The first thread in a program - */ -struct Main_thread : Thread -{ - Main_thread() - : - Thread(Weight::DEFAULT_WEIGHT, "main", MAIN_THREAD_STACK_SIZE, Type::MAIN) - { } - - /********************** - ** Thread interface ** - **********************/ - - void entry() override { } -}; - - -Main_thread * main_thread() -{ - static Main_thread s { }; - return &s; -} - - -/** - * Create a thread object for the main thread - * - * \return stack pointer of the new environment via init_main_thread_result - * - * This function must be called only once per program and before the _main - * function. It can be called as soon as a temporary environment provides - * some stack space and inter-process communication. At this stage, global - * static objects are not registered for implicit destruction at program exit. - */ -extern "C" void init_main_thread() -{ - /* do platform specific preparation */ - prepare_init_main_thread(); - - /* - * Explicitly setup program environment at this point to ensure that its - * destructor won't be registered for the atexit routine. - */ - (void)env_deprecated(); - init_log(*env_deprecated()->parent()); - - /* create a thread object for the main thread */ - main_thread(); - - /** - * The new stack pointer enables the caller to switch from its current - * environment to the those that the thread object provides. - */ - addr_t const sp = reinterpret_cast(main_thread()->stack_top()); - init_main_thread_result = sp; - - /* - * Sanity check for the usage of the initial stack - * - * Because the initial stack is located in the BSS, it is zero-initialized. - * We check that the stack still contains zeros at its lower boundary after - * executing all the initialization code. - */ - enum { STACK_PAD = 256U }; - for (unsigned i = 0; i < STACK_PAD; i++) { - if (__initial_stack_base[i] == 0) - continue; - - error("initial stack overflow detected"); - for (;;); - } -} diff --git a/repos/base/src/lib/timeout/timer_connection.cc b/repos/base/src/lib/timeout/timer_connection.cc index 8d90e56459..c38718e711 100644 --- a/repos/base/src/lib/timeout/timer_connection.cc +++ b/repos/base/src/lib/timeout/timer_connection.cc @@ -120,12 +120,9 @@ void Timer::Connection::set_timeout(Microseconds duration, } -Timer::Connection::Connection(Genode::Env &env, Genode::Entrypoint &ep, - char const *label) +Timer::Connection::Connection(Env &env, Entrypoint &ep, Label const &label) : - Genode::Connection(env, session(env.parent(), - "ram_quota=10K, cap_quota=%u, label=\"%s\"", - CAP_QUOTA, label)), + Genode::Connection(env, label, Ram_quota { 10*1024 }, Args()), Session_client(cap()), _signal_handler(ep, *this, &Connection::_handle_timeout) { @@ -134,10 +131,6 @@ Timer::Connection::Connection(Genode::Env &env, Genode::Entrypoint &ep, } -Timer::Connection::Connection(Genode::Env &env, char const *label) -: Timer::Connection(env, env.ep(), label) {} - - Timeout_scheduler &Timer::Connection::_switch_to_timeout_framework_mode() { if (_mode == TIMEOUT_FRAMEWORK) { @@ -148,7 +141,6 @@ Timeout_scheduler &Timer::Connection::_switch_to_timeout_framework_mode() _timeout_scheduler._enable(); - /* do initial calibration burst to make interpolation available earlier */ for (unsigned i = 0; i < NR_OF_INITIAL_CALIBRATIONS; i++) { _update_real_time(); diff --git a/repos/base/src/lib/timeout/timer_connection_time.cc b/repos/base/src/lib/timeout/timer_connection_time.cc index b433afdaed..74e5ad24ff 100644 --- a/repos/base/src/lib/timeout/timer_connection_time.cc +++ b/repos/base/src/lib/timeout/timer_connection_time.cc @@ -66,6 +66,7 @@ void Timer::Connection::_update_real_time() if (new_latency_us < latency_us) { us = new_us; ts = new_ts; + latency_us = new_latency_us; /* take the results if the latency fulfills the given maximum */ if (latency_us < MAX_REMOTE_TIME_LATENCY_US) { diff --git a/repos/base/src/test/alarm/main.cc b/repos/base/src/test/alarm/main.cc new file mode 100644 index 0000000000..35d1b80e81 --- /dev/null +++ b/repos/base/src/test/alarm/main.cc @@ -0,0 +1,242 @@ +/* + * \brief Alarm data-structure test + * \author Norman Feske + * \date 2024-03-06 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* Genode includes */ +#include +#include +#include + +/* base-internal includes */ +#include +#include + + +namespace Test { + + using namespace Genode; + + struct Clock + { + unsigned _value; + + static constexpr unsigned LIMIT_LOG2 = 4, + LIMIT = 1 << LIMIT_LOG2, + MASK = LIMIT - 1; + + unsigned value() const { return _value & MASK; } + + void print(Genode::Output &out) const { Genode::print(out, _value); } + }; + + struct Alarm; + using Alarms = Alarm_registry; + + struct Alarm : Alarms::Element + { + using Name = String<64>; + + Name const name; + + Alarm(auto ®istry, Name const &name, Clock time) + : + Alarms::Element(registry, *this, time), + name(name) + { } + + void print(Output &out) const + { + Genode::print(out, name); + } + }; +} + + +void Component::construct(Genode::Env &env) +{ + using namespace Test; + + struct Panic { }; + + Xoroshiro_128_plus random { 0 }; + + Alarms alarms { }; + + /* + * Test searching alarms defined for a circular clock, and the + * searching for the alarm scheduled next from a given time. + */ + { + Alarm a0 { alarms, "a0", Clock { 0 } }, + a1 { alarms, "a1", Clock { 1 } }, + a2 { alarms, "a2", Clock { 2 } }, + a3 { alarms, "a3", Clock { 3 } }; + + log(alarms); + + { + Alarm a4 { alarms, "a4", Clock { 4 } }; + log(alarms); + + alarms.for_each_in_range({ 1 }, { 3 }, [&] (Alarm const &alarm) { + log("in range [1...3]: ", alarm); }); + + alarms.for_each_in_range({ 3 }, { 1 }, [&] (Alarm const &alarm) { + log("in range [3...1]: ", alarm); }); + + for (unsigned i = 0; i < 6; i++) + alarms.soonest(Clock { i }).with_result( + [&] (Clock const &time) { + log("soonest(", i, ") -> ", time); }, + [&] (Alarms::None) { + log("soonest(", i, ") -> none"); + } + ); + + /* a4 removed */ + } + log(alarms); + + /* a0...a3 removed */ + } + + auto check_no_alarms_present = [&] + { + alarms.soonest(Clock { }).with_result( + [&] (Clock const &time) { + error("soonest exepectedly returned ", time); }, + [&] (Alarms::None) { + log("soonest expectedly returned None"); + } + ); + }; + + check_no_alarms_present(); + + /* + * Create random alarms, in particular featuring the same time values. + * This stress-tests the AVL tree's ability to handle duplicated keys. + */ + { + unsigned const N = 100; + Constructible array[N] { }; + + auto check_consistency = [&] (unsigned const expected_count) + { + Clock time { }; + unsigned count = 0; + alarms.for_each_in_range({ 0 }, { Clock::MASK }, [&] (Alarm const &alarm) { + count++; + if (alarm.time.value() < time.value()) { + error("alarms are unexpectedly not ordered"); + throw Panic { }; + } + time = alarm.time; + }); + + if (count != expected_count) { + error("foreach visited ", count, " alarms, expected ", expected_count); + throw Panic { }; + } + }; + + /* construct alarms with random times */ + for (unsigned total = 0; total < N; ) { + Clock const time { unsigned(random.value()) % Clock::MASK }; + array[total++].construct(alarms, Alarm::Name("a", total), time); + check_consistency(total); + } + + log(alarms); + + /* destruct alarms in random order */ + for (unsigned total = N; total > 0; total--) { + + check_consistency(total); + + /* pick Nth still existing element */ + unsigned const nth = (total*uint16_t(random.value())) >> 16; + + for (unsigned count = 0, i = 0; i < N; i++) { + if (array[i].constructed()) { + if (count == nth) { + array[i].destruct(); + break; + } + count++; + } + } + } + + check_no_alarms_present(); + } + + /* + * Test the purging of all alarms in a given time window + */ + { + Heap heap { env.ram(), env.rm() }; + + unsigned const N = 1000; + + /* schedule alarms for the whole time range */ + for (unsigned total = 0; total < N; total++) { + Clock const time { unsigned(random.value()) % Clock::MASK }; + new (heap) Alarm(alarms, Alarm::Name("a", total), time); + } + + auto histogram_of_scheduled_alarms = [&] (unsigned expected_total) + { + unsigned total = 0; + for (unsigned i = 0; i < Clock::MASK; i++) { + unsigned count = 0; + alarms.for_each_in_range({ i }, { i }, [&] (Alarm const &) { + count++; }); + log("time ", i, ": ", count, " alarms"); + total += count; + } + if (total != expected_total) { + error("total number of ", total, " alarms, expected ", expected_total); + throw Panic { }; + } + }; + + histogram_of_scheduled_alarms(N); + + unsigned triggered = 0; + while (alarms.with_any_in_range({ 12 }, { 3 }, [&] (Alarm &alarm) { + triggered++; + destroy(heap, &alarm); + })); + + log("after purging all alarms in time window 12...3:"); + histogram_of_scheduled_alarms(N - triggered); + + /* check absence of any alarms in purged range */ + { + unsigned count = 0; + alarms.for_each_in_range({ 12 }, { 3 }, [&] (Alarm const &) { + count++; }); + + if (count != 0) { + error("range of purged alarms unexpectedly not empty"); + throw Panic { }; + } + } + + /* clear up heap */ + while (alarms.with_any_in_range({ 0 }, { Clock::MASK }, [&] (Alarm &alarm) { + destroy(heap, &alarm); })); + } + + log("Test succeeded."); +} diff --git a/repos/base/src/test/alarm/target.mk b/repos/base/src/test/alarm/target.mk new file mode 100644 index 0000000000..d11b1141a3 --- /dev/null +++ b/repos/base/src/test/alarm/target.mk @@ -0,0 +1,4 @@ +TARGET = test-alarm +SRC_CC = main.cc +LIBS = base +INC_DIR += $(REP_DIR)/src/include diff --git a/repos/base/src/test/ds_ownership/main.cc b/repos/base/src/test/ds_ownership/main.cc index 301461e763..557f7e306c 100644 --- a/repos/base/src/test/ds_ownership/main.cc +++ b/repos/base/src/test/ds_ownership/main.cc @@ -36,7 +36,7 @@ void Component::construct(Genode::Env &env) pd_2.free(ds); log("try to attach dataspace to see if it still exists"); - env.rm().attach(ds); + env.rm().attach(ds, { }); log("attach operation succeeded"); diff --git a/repos/base/src/test/log/main.cc b/repos/base/src/test/log/main.cc index a07a36a781..c3a4d97328 100644 --- a/repos/base/src/test/log/main.cc +++ b/repos/base/src/test/log/main.cc @@ -30,7 +30,7 @@ void Component::construct(Genode::Env &env) log("floating point: ", 1700.0 / 1000); - typedef String<128> Label; + using Label = String<128>; log("multiarg string: ", Label(Char('"'), "parent -> child.", 7, Char('"'))); String<32> hex(Hex(3)); diff --git a/repos/base/src/test/migrate/main.cc b/repos/base/src/test/migrate/main.cc index 440c1e4c8b..e9879f0d5a 100644 --- a/repos/base/src/test/migrate/main.cc +++ b/repos/base/src/test/migrate/main.cc @@ -59,8 +59,7 @@ struct Migrate Timer::Connection timer { env }; Migrate_thread thread { env }; Trace::Connection trace { env, 15 * 4096 /* RAM quota */, - 11 * 4096 /* ARG_BUFFER RAM quota */, - 0 /* parent levels */ }; + 11 * 4096 /* ARG_BUFFER RAM quota */ }; Signal_handler timer_handler { env.ep(), *this, &Migrate::check_traces }; diff --git a/repos/base/src/test/mmio/main.cc b/repos/base/src/test/mmio/main.cc index 1738ae3322..a94f9947f2 100644 --- a/repos/base/src/test/mmio/main.cc +++ b/repos/base/src/test/mmio/main.cc @@ -58,9 +58,9 @@ struct Cpu_state : Register<16> /** * Exemplary MMIO region type */ -struct Test_mmio : public Mmio +struct Test_mmio : public Mmio { - Test_mmio(addr_t const base) : Mmio(base) { } + Test_mmio(addr_t const base) : Mmio({(char *)base, Mmio::SIZE}) { } struct Reg_64 : Register<0x00, 64> { @@ -71,8 +71,8 @@ struct Test_mmio : public Mmio struct Bits_4 : Bitfield<60,4> { }; struct Bits_5 : Bitfield<0,64> { }; struct Bits_6 : Bitfield<16,64> { }; - struct Bits_7 : Bitfield<12,90> { }; - struct Bits_8 : Bitfield<0,72> { }; + struct Bits_7 : Bitfield<12,64> { }; + struct Bits_8 : Bitfield<0,64> { }; }; struct Bitset_64_0 : Bitset_2 { }; struct Bitset_64_1 : Bitset_3 { }; @@ -129,7 +129,7 @@ struct Test_mmio : public Mmio struct Simple_array_1 : Register_array<0x0, 32, 2, 32> { }; - struct Simple_array_2 : Register_array<0x2, 16, 4, 16> { }; + struct Simple_array_2 : Register_array<0x2, 16, 3, 16> { }; struct Strict_reg : Register<0x0, 32, true> { @@ -439,7 +439,7 @@ void Component::construct(Genode::Env &env) **********************************/ { /* whole register */ - typedef Test_mmio::Reg_64 Reg; + using Reg = Test_mmio::Reg_64; enum { REG = 0x0123456789abcdef }; static uint8_t cmp_mem[MMIO_SIZE] = { 0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01 }; @@ -506,7 +506,7 @@ void Component::construct(Genode::Env &env) } /* bitsets */ - typedef Test_mmio::Bitset_64 Bitset; + using Bitset = Test_mmio::Bitset_64; enum { BITSET = 0x4abcdef056789123 }; zero_mem(mmio_mem, MMIO_SIZE); mmio.write(BITSET); diff --git a/repos/base/src/test/registry/main.cc b/repos/base/src/test/registry/main.cc index fe519cf817..1b9ae4db5c 100644 --- a/repos/base/src/test/registry/main.cc +++ b/repos/base/src/test/registry/main.cc @@ -28,7 +28,7 @@ static void test_exception_during_for_each() struct Item : Interface { - typedef String<10> Name; + using Name = String<10>; Name const name; Item(Name const &name) : name(name) { } @@ -48,7 +48,7 @@ static void test_exception_during_for_each() Registered second(items, "second"); Registered third (items, "third"); - auto num_items = [&] () { + auto num_items = [&] { unsigned cnt = 0; items.for_each([&] (Item &) { cnt++; }); return cnt; diff --git a/repos/base/src/test/rm_fault/main.cc b/repos/base/src/test/rm_fault/main.cc index f1a87e7317..b558bc4797 100644 --- a/repos/base/src/test/rm_fault/main.cc +++ b/repos/base/src/test/rm_fault/main.cc @@ -40,11 +40,11 @@ enum { SHUTDOWN = EXEC_TEST - 1 }; -static char const *state_name(Region_map::State &state) +static char const *fault_name(Region_map::Fault const &fault) { - return state.type == Region_map::State::READ_FAULT ? "READ_FAULT" : - state.type == Region_map::State::WRITE_FAULT ? "WRITE_FAULT" : - state.type == Region_map::State::EXEC_FAULT ? "EXEC_FAULT" : "READY"; + return fault.type == Region_map::Fault::Type::READ ? "READ_FAULT" : + fault.type == Region_map::Fault::Type::WRITE ? "WRITE_FAULT" : + fault.type == Region_map::Fault::Type::EXEC ? "EXEC_FAULT" : "READY"; } @@ -63,7 +63,9 @@ bool modify_at(addr_t addr) return false; if (value != READ_TEST + 1) { - addr_t value_mod = ++(*(addr_t volatile *)(addr)); + + (*(addr_t volatile *)(addr)) = (*(addr_t volatile *)(addr)) + 1; + addr_t value_mod = (*(addr_t volatile *)(addr)); /* if we are get told to stop, do so */ if (*(addr_t volatile *)(addr + sizeof(addr)) == STOP_TEST) @@ -165,13 +167,14 @@ class Test_child_policy : public Child_policy { public: - typedef Registered Parent_service; - typedef Registry Parent_services; + using Parent_service = Registered; + using Parent_services = Registry; private: Env &_env; Parent_services &_parent_services; + Id_space _server_ids { }; Signal_context_capability const _fault_handler_sigh; Signal_context_capability const _fault_handler_stack_sigh; @@ -237,6 +240,8 @@ class Test_child_policy : public Child_policy .label = label, .diag = diag }; } + + Id_space &server_id_space() override { return _server_ids; } }; @@ -290,6 +295,15 @@ struct Main_parent long volatile &_child_value() { return *_ds.local_addr(); } long volatile &_child_stop() { return *(_ds.local_addr() + 1); } + void _attach_at(Dataspace_capability ds, addr_t at) + { + if (_address_space.attach(ds, { + .size = { }, .offset = { }, + .use_at = true, .at = at, + .executable = { }, .writeable = true + }).failed()) error("_attach_at unexpectedly failed"); + } + void _test_read_fault(addr_t const child_virt_addr) { /* allocate dataspace to resolve the fault */ @@ -297,7 +311,7 @@ struct Main_parent _child_value() = READ_TEST; - _address_space.attach_at(_ds.cap(), child_virt_addr); + _attach_at(_ds.cap(), child_virt_addr); /* poll until our child modifies the dataspace content */ while (_child_value() == READ_TEST); @@ -306,7 +320,7 @@ struct Main_parent Hex(_child_value())); log("revoke dataspace from child"); - _address_space.detach((void *)child_virt_addr); + _address_space.detach(child_virt_addr); } void _test_write_fault(addr_t const child_virt_addr, unsigned round) @@ -317,7 +331,7 @@ struct Main_parent _child_value() = WRITE_TEST; - _address_space.attach_at(_binary.dataspace(), child_virt_addr); + _attach_at(_binary.dataspace(), child_virt_addr); return; } @@ -332,36 +346,35 @@ struct Main_parent : " unknown"); /* detach region where fault happened */ - _address_space.detach((void *)child_virt_addr); + _address_space.detach(child_virt_addr); if (round == ROUND_FAULT_ON_ROM_BINARY) { /* attach a RAM dataspace read-only */ - enum { - SIZE = 4096, OFFSET = 0, ATTACH_AT = true, NON_EXEC = false, - READONLY = false - }; + if (_address_space.attach(_ds.cap(), { + .size = 4096, .offset = { }, + .use_at = true, .at = child_virt_addr, + .executable = { }, .writeable = { } + }).failed()) error("attach of ROUND_FAULT_ON_ROM_BINARY failed"); - _address_space.attach(_ds.cap(), SIZE, OFFSET, ATTACH_AT, - child_virt_addr, NON_EXEC, READONLY); } else if (round == ROUND_FAULT_ON_RO_RAM) { /* let client continue by attaching RAM dataspace writeable */ - _address_space.attach_at(_ds.cap(), child_virt_addr); + _attach_at(_ds.cap(), child_virt_addr); } } - void _test_exec_fault(Region_map::State &state) + void _test_exec_fault(Region_map::Fault const &fault) { if (_child_value() == WRITE_TEST) { _child_value() = EXEC_TEST; return; } - if (state.type != Region_map::State::EXEC_FAULT || - state.addr != MANAGED_ADDR) + if (fault.type != Region_map::Fault::Type::EXEC || + fault.addr != MANAGED_ADDR) { - error("exec test failed ", (int)state.type, - " addr=", Hex(state.addr)); + error("exec test failed ", (int)fault.type, + " addr=", Hex(fault.addr)); return; } @@ -376,17 +389,17 @@ struct Main_parent log("received region-map fault signal, request fault state"); - Region_map::State state = _address_space.state(); + Region_map::Fault const fault = _address_space.fault(); - log("rm session state is ", state_name(state), ", pf_addr=", Hex(state.addr)); + log("rm session state is ", fault_name(fault), ", pf_addr=", Hex(fault.addr)); /* ignore spurious fault signal */ - if (state.type == Region_map::State::READY) { + if (fault.type == Region_map::Fault::Type::NONE) { log("ignoring spurious fault signal"); return; } - addr_t child_virt_addr = state.addr & ~(4096 - 1); + addr_t child_virt_addr = fault.addr & ~(4096 - 1); if (_fault_cnt < FAULT_CNT_READ) _test_read_fault(child_virt_addr); @@ -399,7 +412,7 @@ struct Main_parent _handle_fault_stack(); if (_fault_cnt > FAULT_CNT_WRITE) - _test_exec_fault(state); + _test_exec_fault(fault); _fault_cnt++; } @@ -408,9 +421,9 @@ struct Main_parent { /* sanity check that we got exec fault */ if (_config.xml().attribute_value("executable_fault_test", true)) { - Region_map::State state = _address_space.state(); - if (state.type != Region_map::State::EXEC_FAULT) { - error("unexpected state ", state_name(state)); + Region_map::Fault const fault = _address_space.fault(); + if (fault.type != Region_map::Fault::Type::EXEC) { + error("unexpected state ", fault_name(fault)); return; } diff --git a/repos/base/src/test/rm_nested/main.cc b/repos/base/src/test/rm_nested/main.cc index 07f438e517..662fa3449c 100644 --- a/repos/base/src/test/rm_nested/main.cc +++ b/repos/base/src/test/rm_nested/main.cc @@ -46,19 +46,22 @@ class Local_fault_handler : public Entrypoint void _handle_fault() { - Region_map::State state = _region_map.state(); + Region_map::Fault fault = _region_map.fault(); - _fault_cnt ++; + _fault_cnt = _fault_cnt + 1; - log("region-map state is ", - state.type == Region_map::State::READ_FAULT ? "READ_FAULT" : - state.type == Region_map::State::WRITE_FAULT ? "WRITE_FAULT" : - state.type == Region_map::State::EXEC_FAULT ? "EXEC_FAULT" : "READY", - ", pf_addr=", Hex(state.addr, Hex::PREFIX)); + log("region-map fault is ", + fault.type == Region_map::Fault::Type::READ ? "READ_FAULT" : + fault.type == Region_map::Fault::Type::WRITE ? "WRITE_FAULT" : + fault.type == Region_map::Fault::Type::EXEC ? "EXEC_FAULT" : "READY", + ", pf_addr=", Hex(fault.addr, Hex::PREFIX)); log("allocate dataspace and attach it to sub region map"); Dataspace_capability ds = _env.ram().alloc(PAGE_SIZE); - _region_map.attach_at(ds, state.addr & ~(PAGE_SIZE - 1)); + _region_map.attach(ds, { + .size = { }, .offset = { }, + .use_at = true, .at = fault.addr & ~(PAGE_SIZE - 1), + .executable = { }, .writeable = true }); log("returning from handle_fault"); } @@ -83,6 +86,25 @@ class Local_fault_handler : public Entrypoint }; +static void *ptr_from_attach_result(Region_map::Attach_result const &result) +{ + return result.convert( + [&] (Region_map::Range range) { return (void *)range.start; }, + [&] (Region_map::Attach_error) { + error("read-only attach unexpectedly failed"); + return nullptr; }); +} + + +static void *attach_rw(Region_map &rm, Dataspace_capability ds) +{ + return ptr_from_attach_result(rm.attach(ds, { + .size = { }, .offset = { }, + .use_at = { }, .at = { }, + .executable = { }, .writeable = true })); +} + + void nested_regions(Genode::Env &env) { enum { @@ -98,7 +120,7 @@ void nested_regions(Genode::Env &env) Region_map_client rm_top(rm.create(MANAGED_REGION_TOP_SIZE)); Dataspace_client rm_top_client(rm_top.dataspace()); - void *ptr_top = env.rm().attach(rm_top.dataspace()); + void *ptr_top = attach_rw(env.rm(), rm_top.dataspace()); addr_t const addr_top = reinterpret_cast(ptr_top); log(" region top ", Hex_range(addr_top, rm_top_client.size())); @@ -106,13 +128,13 @@ void nested_regions(Genode::Env &env) /* shim region 1 */ Region_map_client rm_shim1(rm.create(MANAGED_REGION_SHIM1_SIZE)); Dataspace_client rm_shim1_client(rm_shim1.dataspace()); - void *ptr_shim1 = rm_top.attach(rm_shim1.dataspace()); + void *ptr_shim1 = attach_rw(rm_top, rm_shim1.dataspace()); addr_t const addr_shim1 = reinterpret_cast(ptr_shim1); /* shim region 2 */ Region_map_client rm_shim2(rm.create(MANAGED_REGION_SHIM2_SIZE)); Dataspace_client rm_shim2_client(rm_shim2.dataspace()); - void *ptr_shim2 = rm_top.attach(rm_shim2.dataspace()); + void *ptr_shim2 = attach_rw(rm_top, rm_shim2.dataspace()); addr_t const addr_shim2 = reinterpret_cast(ptr_shim2); log(" region shim ", @@ -122,16 +144,12 @@ void nested_regions(Genode::Env &env) /* attach some memory to region 2 as readonly and touch/map it */ size_t const shim2_ram_size = PAGE_SIZE * 2; Dataspace_capability shim2_ram_ds = env.ram().alloc(shim2_ram_size); - enum { - COMPLETE_SIZE = 0, OFFSET_0 = 0, OFFSET_1000 = 0x1000, - USE_LOCAL_ADDR = true, LOCAL_ADDR_0 = 0, LOCAL_ADDR_1000 = 0x1000, - NON_EXECUTABLE = false, - READONLY = false, WRITEABLE = true - }; - void * ptr_shim2_ram = rm_shim2.attach(shim2_ram_ds, COMPLETE_SIZE, - OFFSET_0, USE_LOCAL_ADDR, - LOCAL_ADDR_1000, NON_EXECUTABLE, - READONLY); + void * const ptr_shim2_ram = + ptr_from_attach_result(rm_shim2.attach(shim2_ram_ds, { + .size = { }, .offset = { }, + .use_at = true, .at = 0x1000, + .executable = { }, .writeable = { } })); + addr_t const addr_shim2_ram = reinterpret_cast(ptr_shim2_ram); addr_t const read_shim2 = addr_top + addr_shim2 + addr_shim2_ram; @@ -148,7 +166,13 @@ void nested_regions(Genode::Env &env) Region_map_client rm_bottom(rm.create(MANAGED_REGION_BOTTOM_SIZE)); Dataspace_client rm_bottom_client(rm_bottom.dataspace()); size_t const size_bottom = MANAGED_REGION_BOTTOM_SIZE - MANAGED_REGION_SHIM2_SIZE; - void const *ptr_bottom = rm_shim1.attach(rm_bottom.dataspace(), size_bottom); + + void const * const ptr_bottom = + ptr_from_attach_result(rm_shim1.attach(rm_bottom.dataspace(), { + .size = size_bottom, .offset = { }, + .use_at = { }, .at = { }, + .executable = { }, .writeable = { } })); + addr_t const addr_bottom = reinterpret_cast(ptr_bottom); log(" bottom shim (r) ", @@ -159,14 +183,17 @@ void nested_regions(Genode::Env &env) /* attach some memory to bottom as writeable */ Dataspace_capability bottom_ram_ds = env.ram().alloc(MANAGED_REGION_BOTTOM_SIZE); { - void * base_rw = env.rm().attach(bottom_ram_ds); + void * base_rw = attach_rw(env.rm(), bottom_ram_ds); memset(base_rw, 0xff, MANAGED_REGION_BOTTOM_SIZE); - env.rm().detach(base_rw); + env.rm().detach(addr_t(base_rw)); } - void * ptr_bottom_ram = rm_bottom.attach(bottom_ram_ds, COMPLETE_SIZE, - OFFSET_0, USE_LOCAL_ADDR, - LOCAL_ADDR_0, NON_EXECUTABLE, - WRITEABLE); + + void const * const ptr_bottom_ram = + ptr_from_attach_result(rm_bottom.attach(bottom_ram_ds, { + .size = { }, .offset = { }, + .use_at = true, .at = 0, + .executable = { }, .writeable = true })); + addr_t const addr_bottom_ram = reinterpret_cast(ptr_bottom_ram); addr_t const write_bottom = addr_top + addr_shim1 + addr_bottom + addr_bottom_ram; @@ -212,7 +239,7 @@ void Component::construct(Genode::Env & env) /* * Attach region map as dataspace to the local address space. */ - void *addr = env.rm().attach(region_map.dataspace()); + void *addr = attach_rw(env.rm(), region_map.dataspace()); log("attached sub dataspace at local address ", addr); Dataspace_client client(region_map.dataspace()); diff --git a/repos/base/src/test/rm_stress/main.cc b/repos/base/src/test/rm_stress/main.cc index 7b66fac0c2..c04a9c00e9 100644 --- a/repos/base/src/test/rm_stress/main.cc +++ b/repos/base/src/test/rm_stress/main.cc @@ -52,17 +52,27 @@ void Component::construct(Env &env) for (unsigned r = 0; r < ROUNDS; ++r) { for (unsigned i = 0; i < sizeof(page)/sizeof(*page); ++i) { - off_t const offset = 0; + addr_t const offset = 0; - unsigned char volatile const *v = - env.rm().attach(page[i].cap(), page[i].size(), offset); + uint8_t volatile const *v = + env.rm().attach(page[i].cap(), { + .size = page[i].size(), + .offset = offset, + .use_at = { }, + .at = { }, + .executable = false, + .writeable = true + }).convert( + [&] (Region_map::Range range) { return (uint8_t *)range.start; }, + [&] (Region_map::Attach_error) { return nullptr; } + ); if (page[i].color != *v) { error("value @ ", v, " ", X(*v), " != ", X(page[i].color), " in round ", r); env.parent().exit(-1); } - env.rm().detach(Region_map::Local_addr(v)); + env.rm().detach(addr_t(v)); } } diff --git a/repos/base/src/test/segfault/target.mk b/repos/base/src/test/segfault/target.mk index 1153d546b2..2521192720 100644 --- a/repos/base/src/test/segfault/target.mk +++ b/repos/base/src/test/segfault/target.mk @@ -1,3 +1,4 @@ -TARGET = test-segfault -SRC_CC = main.cc -LIBS = base +TARGET = test-segfault +SRC_CC = main.cc +LIBS = base +CC_WARN = -Wno-array-bounds diff --git a/repos/base/src/test/smp/main.cc b/repos/base/src/test/smp/main.cc index 53ada8a743..8880bfa0cb 100644 --- a/repos/base/src/test/smp/main.cc +++ b/repos/base/src/test/smp/main.cc @@ -19,7 +19,9 @@ #include #include #include +#include #include +#include namespace Genode { @@ -71,7 +73,7 @@ namespace Mp_server_test { Genode::Native_capability test_cap_reply(Genode::Native_capability); }; - typedef Genode::Capability Capability; + using Capability = Genode::Capability; struct Cpu_compound { @@ -112,7 +114,8 @@ namespace Mp_server_test { log("RPC: --- test started ---"); - Cpu_compound ** compounds = new (heap) Cpu_compound*[cpus.total()]; + Cpu_compound * compounds[cpus.total()] { }; + for (unsigned i = 0; i < cpus.total(); i++) compounds[i] = new (heap) Cpu_compound(cpus.location_of_index(i), env); @@ -140,7 +143,6 @@ namespace Mp_server_test { /* clean up */ for (unsigned i = 0; i < cpus.total(); i++) destroy(heap, compounds[i]); - destroy(heap, compounds); log("RPC: --- test finished ---"); } @@ -165,7 +167,7 @@ namespace Affinity_test { Genode::log("Affinity: thread started on CPU ", location, " spinning..."); - for (;;) cnt++; + for (;;) cnt = cnt + 1; } Spinning_thread(Genode::Env &env, Location location) @@ -182,9 +184,8 @@ namespace Affinity_test { log("Affinity: --- test started ---"); - /* get some memory for the thread objects */ - Spinning_thread ** threads = new (heap) Spinning_thread*[cpus.total()]; - uint64_t * thread_cnt = new (heap) uint64_t[cpus.total()]; + Spinning_thread * threads[cpus.total()] { }; + uint64_t thread_cnt[cpus.total()] { }; /* construct the thread objects */ for (unsigned i = 0; i < cpus.total(); i++) @@ -203,46 +204,62 @@ namespace Affinity_test { volatile uint64_t cnt = 0; unsigned round = 0; - char const text_cpu[] = "Affinity: CPU: "; - char const text_round[] = "Affinity: Round %2u: "; - char * output_buffer = new (heap) char [sizeof(text_cpu) + 3 * cpus.total()]; + static char const text_cpu[] = "Affinity: CPU: "; for (; round < 11;) { - cnt++; + cnt = cnt + 1; /* try to get a life sign by the main thread from the remote threads */ if (cnt % COUNT_VALUE == 0) { - char * output = output_buffer; - snprintf(output, sizeof(text_cpu), text_cpu); - output += sizeof(text_cpu) - 1; - for (unsigned i = 0; i < cpus.total(); i++) { - snprintf(output, 4, "%2u ", i); - output += 3; - } - log(Cstring(output_buffer)); - output = output_buffer; - snprintf(output, sizeof(text_round), text_round, round); - output += sizeof(text_round) - 2; + struct Table_header + { + unsigned num_cpus; - for (unsigned i = 0; i < cpus.total(); i++) { - snprintf(output, 4, "%s ", - thread_cnt[i] == threads[i]->cnt ? " D" : " A"); - output += 3; + void print(Output &out) const + { + using Genode::print; + + print(out, text_cpu); + for (unsigned i = 0; i < num_cpus; i++) + print(out, Right_aligned(2, i), " "); + } + }; + + struct Table_entries + { + unsigned num_cpus; + unsigned round; + Spinning_thread **threads; + uint64_t *thread_cnt; + + void print(Output &out) const + { + using Genode::print; + + print(out, "Affinity: Round ", Right_aligned(2, round), ": "); + + for (unsigned i = 0; i < num_cpus; i++) + print(out, thread_cnt[i] == threads[i]->cnt ? " D " : " A "); + } + }; + + log(Table_header { .num_cpus = cpus.total() }); + log(Table_entries { .num_cpus = cpus.total(), + .round = round, + .threads = threads, + .thread_cnt = thread_cnt }); + + for (unsigned i = 0; i < cpus.total(); i++) thread_cnt[i] = threads[i]->cnt; - } - log(Cstring(output_buffer)); round ++; } } - destroy(heap, output_buffer); - for (unsigned i = 0; i < cpus.total(); i++) destroy(heap, threads[i]); - destroy(heap, threads); - destroy(heap, thread_cnt); + log("Affinity: --- test finished ---"); } } @@ -294,8 +311,7 @@ namespace Tlb_shootdown_test { new (heap) Genode::Attached_ram_dataspace(env.ram(), env.rm(), DS_SIZE); - /* get some memory for the thread objects */ - Thread ** threads = new (heap) Thread*[cpus.total()]; + Thread * threads[cpus.total()] { }; /* construct the thread objects */ for (unsigned i = 1; i < cpus.total(); i++) @@ -316,10 +332,10 @@ namespace Tlb_shootdown_test { * We have to wait here, for some time so that all fault * messages are received before the test finishes. */ - for (volatile unsigned i = 0; i < (0x2000000 * cpus.total()); i++) ; + for (unsigned i = 0; i < (0x2000000 * cpus.total()); ++i) + memory_barrier(); for (unsigned i = 1; i < cpus.total(); i++) destroy(heap, threads[i]); - destroy(heap, threads); log("TLB: --- test finished ---"); } @@ -349,7 +365,7 @@ namespace Tsc_test { barrier.wakeup(); while (loop) { - while (spin && loop) cnt++; + while (spin && loop) cnt = cnt + 1; measure(); spin = true; @@ -405,7 +421,7 @@ namespace Tsc_test { log("TSC: --- test started ---"); /* get some memory for the thread objects */ - Tsc_thread ** threads = new (heap) Tsc_thread*[cpus.total()]; + Tsc_thread * threads[cpus.total()] { }; /* construct the thread objects */ for (unsigned i = 0; i < cpus.total(); i++) { @@ -500,7 +516,6 @@ namespace Tsc_test { /* cleanup */ for (unsigned i = 0; i < cpus.total(); i++) destroy(heap, threads[i]); - destroy(heap, threads); log("TSC: --- test finished ---"); } diff --git a/repos/base/src/test/sub_rm/main.cc b/repos/base/src/test/sub_rm/main.cc index 1dad1106d1..7cceaacdca 100644 --- a/repos/base/src/test/sub_rm/main.cc +++ b/repos/base/src/test/sub_rm/main.cc @@ -39,12 +39,11 @@ static char const *test_pattern_2() { static void fill_ds_with_test_pattern(Env &env, char const *pattern, - Dataspace_capability ds, size_t offset) + Dataspace_capability ds_cap, size_t offset) { log("fill dataspace with information"); - char *content = env.rm().attach(ds); - copy_cstring(content + offset, pattern, ~0); - env.rm().detach(content); + Attached_dataspace ds { env.rm(), ds_cap }; + copy_cstring(ds.local_addr() + offset, pattern, ~0); } @@ -62,7 +61,7 @@ void Component::construct(Env &env) log("--- sub-rm test ---"); log("create RM connection"); - enum { SUB_RM_SIZE = 1024*1024 }; + size_t const SUB_RM_SIZE = 1024*1024; Rm_connection rm(env); /* @@ -80,7 +79,7 @@ void Component::construct(Env &env) */ log("create managed dataspace"); Region_map_client sub_rm(rm.create(SUB_RM_SIZE)); - enum { DS_SIZE = 4*4096 }; + size_t const DS_SIZE = 4*4096; Ram_dataspace_capability ds = env.ram().alloc(DS_SIZE); /* @@ -91,19 +90,32 @@ void Component::construct(Env &env) if (!config.xml().attribute_value("support_attach_sub_any", true)) { log("attach RAM ds to any position at sub rm - this should fail"); - try { - sub_rm.attach(ds, 0, 0, false, (addr_t)0); - fail("sub rm attach_any unexpectedly did not fail"); - } - catch (Region_map::Region_conflict) { - log("attach failed as expected"); } + sub_rm.attach(ds, { + .size = { }, .offset = { }, + .use_at = { }, .at = { }, + .executable = { }, .writeable = true + }).with_result( + [&] (Region_map::Range) { + fail("sub rm attach_any unexpectedly did not fail"); }, + [&] (Region_map::Attach_error e) { + if (e == Region_map::Attach_error::REGION_CONFLICT) + log("attach failed as expected"); } + ); } log("attach RAM ds to a fixed position at sub rm"); - enum { DS_SUB_OFFSET = 4096 }; - if ((addr_t)sub_rm.attach_at(ds, DS_SUB_OFFSET, 0, 0) != DS_SUB_OFFSET) - fail("attach_at return-value mismatch"); + addr_t const DS_SUB_OFFSET = 4096; + sub_rm.attach(ds, { + .size = { }, .offset = { }, + .use_at = true, .at = DS_SUB_OFFSET, + .executable = { }, .writeable = { } + }).with_result( + [&] (Region_map::Range const range) { + if (range.start != DS_SUB_OFFSET) + fail("attach-at return-value mismatch"); }, + [&] (Region_map::Attach_error) { } + ); log("attach sub rm at local address space"); @@ -117,8 +129,15 @@ void Component::construct(Env &env) */ addr_t const local_attach_addr = config.xml().attribute_value("local_attach_addr", (addr_t)0); - char *sub_rm_base = env.rm().attach_at(sub_rm.dataspace(), - local_attach_addr); + + char * const sub_rm_base = env.rm().attach(sub_rm.dataspace(), { + .size = { }, .offset = { }, + .use_at = true, .at = local_attach_addr, + .executable = { }, .writeable = true + }).convert( + [&] (Region_map::Range const range) { return (char *)range.start; }, + [&] (Region_map::Attach_error) { return nullptr; } + ); log("validate pattern in sub rm"); validate_pattern_at(test_pattern(), sub_rm_base + DS_SUB_OFFSET); @@ -129,9 +148,17 @@ void Component::construct(Env &env) */ log("attach RAM ds at another fixed position at sub rm"); - enum { DS_SUB_OFFSET_2 = 0x40000 }; - if ((addr_t)sub_rm.attach_at(ds, DS_SUB_OFFSET_2, 0, 0) != DS_SUB_OFFSET_2) - fail("attach_at return-value mismatch"); + addr_t const DS_SUB_OFFSET_2 = 0x40000; + sub_rm.attach(ds, { + .size = { }, .offset = { }, + .use_at = true, .at = DS_SUB_OFFSET_2, + .executable = { }, .writeable = { } + }).with_result( + [&] (Region_map::Range const range) { + if (range.start != DS_SUB_OFFSET_2) + fail("attach-at return-value mismatch"); }, + [&] (Region_map::Attach_error) { } + ); log("validate pattern in second mapping in sub rm"); validate_pattern_at(test_pattern(), sub_rm_base + DS_SUB_OFFSET_2); @@ -140,35 +167,50 @@ void Component::construct(Env &env) * Try to cross the boundaries of the sub RM session. This should * produce an error. */ - try { - sub_rm.attach_at(ds, SUB_RM_SIZE - 4096, 0, 0); - fail("undetected boundary conflict\n"); - } - catch (Region_map::Region_conflict) { - log("attaching beyond sub RM boundary failed as expected"); } + sub_rm.attach(ds, { + .size = { }, .offset = { }, + .use_at = true, .at = SUB_RM_SIZE - 4096, + .executable = { }, .writeable = true + }).with_result( + [&] (Region_map::Range) { + fail("undetected boundary conflict\n"); }, + [&] (Region_map::Attach_error e) { + if (e == Region_map::Attach_error::REGION_CONFLICT) + log("attaching beyond sub RM boundary failed as expected"); } + ); /* * Check for working region - conflict detection */ log("attaching RAM ds to a conflicting region"); - try { - sub_rm.attach_at(ds, DS_SUB_OFFSET + 4096, 0, 0); - fail("region conflict went undetected\n"); - } - catch (Region_map::Region_conflict) { - log("attaching conflicting region failed as expected"); } + sub_rm.attach(ds, { + .size = { }, .offset = { }, + .use_at = true, .at = DS_SUB_OFFSET + 4096, + .executable = { }, .writeable = true + }).with_result( + [&] (Region_map::Range) { + fail("region conflict went undetected"); }, + [&] (Region_map::Attach_error e) { + if (e == Region_map::Attach_error::REGION_CONFLICT) + log("attaching conflicting region failed as expected"); } + ); if (config.xml().attribute_value("attach_twice_forbidden", false)) { /* * Try to double-attach the same sub RM session. This should fail */ log("attach sub rm again at local address space"); - try { - env.rm().attach(sub_rm.dataspace()); - fail("double attachment of sub RM session went undetected\n"); - } - catch (Region_map::Region_conflict) { - log("doubly attaching sub RM session failed as expected"); } + sub_rm.attach(ds, { + .size = { }, .offset = { }, + .use_at = { }, .at = { }, + .executable = { }, .writeable = true + }).with_result( + [&] (Region_map::Range) { + fail("double attachment of sub RM session went undetected"); }, + [&] (Region_map::Attach_error e) { + if (e == Region_map::Attach_error::REGION_CONFLICT) + log("doubly attaching sub RM session failed as expected"); } + ); } /* @@ -178,8 +220,12 @@ void Component::construct(Env &env) * page. */ log("attach RAM ds with offset"); - enum { DS_SUB_OFFSET_3 = 0x80000 }; - sub_rm.attach_at(ds, DS_SUB_OFFSET_3, 0, 4096); + addr_t const DS_SUB_OFFSET_3 = 0x80000; + sub_rm.attach(ds, { + .size = { }, .offset = 4096, + .use_at = true, .at = DS_SUB_OFFSET_3, + .executable = { }, .writeable = true + }); validate_pattern_at(test_pattern_2(), sub_rm_base + DS_SUB_OFFSET_3); /* @@ -187,15 +233,19 @@ void Component::construct(Env &env) * starting with the second page. */ log("attach RAM ds with offset and size"); - enum { DS_SUB_OFFSET_4 = 0xc0000 }; - sub_rm.attach_at(ds, DS_SUB_OFFSET_4, 2*4096, 4096); + addr_t const DS_SUB_OFFSET_4 = 0xc0000; + sub_rm.attach(ds, { + .size = 2*4096, .offset = 4096, + .use_at = true, .at = DS_SUB_OFFSET_4, + .executable = { }, .writeable = true + }); validate_pattern_at(test_pattern_2(), sub_rm_base + DS_SUB_OFFSET_4); /* * Detach the first attachment (to be validated by the run script by * inspecting '/proc/pid/maps' after running the test. */ - sub_rm.detach((void *)DS_SUB_OFFSET); + sub_rm.detach(DS_SUB_OFFSET); log("--- end of sub-rm test ---"); diff --git a/repos/base/src/test/thread/main.cc b/repos/base/src/test/thread/main.cc index 786777b060..b5b7bf60c9 100644 --- a/repos/base/src/test/thread/main.cc +++ b/repos/base/src/test/thread/main.cc @@ -25,6 +25,9 @@ #include #include +/* compiler includes */ +#include + using namespace Genode; @@ -194,7 +197,7 @@ struct Cpu_helper : Thread { Env &_env; - Cpu_helper(Env &env, const char * name, Cpu_session &cpu) + Cpu_helper(Env &env, Name const &name, Cpu_session &cpu) : Thread(env, name, STACK_SIZE, Thread::Location(), Thread::Weight(), cpu), _env(env) @@ -245,11 +248,11 @@ struct Pause_helper : Thread * other threads of this task trying to print log messages will * block - looks like a deadlock. */ - loop ++; + loop = loop + 1; if (beep) { log("beep"); beep = false; - loop ++; + loop = loop + 1; return; } } @@ -266,7 +269,7 @@ static void test_pause_resume(Env &env) while (thread.loop < 1) { } - Thread_state state; + Thread_state state { }; Cpu_thread_client thread_client(thread.cap()); log("--- pausing ---"); @@ -275,11 +278,10 @@ static void test_pause_resume(Env &env) log("--- paused ---"); log("--- reading thread state ---"); - try { - state = thread_client.state(); - } catch (Cpu_thread::State_access_failed) { + state = thread_client.state(); + if (state.state == Thread_state::State::UNAVAILABLE) throw -10; - } + if (loop_paused != thread.loop) throw -11; @@ -306,32 +308,37 @@ static void test_create_as_many_threads(Env &env) Thread::stack_virtual_size(); Cpu_helper * threads[max]; - static char thread_name[8]; Heap heap(env.ram(), env.rm()); unsigned i = 0; - try { - for (; i < max; i++) { - try { - snprintf(thread_name, sizeof(thread_name), "%u", i + 1); - threads[i] = new (heap) Cpu_helper(env, thread_name, env.cpu()); - threads[i]->start(); - threads[i]->join(); - } catch (Cpu_session::Thread_creation_failed) { - throw "Thread_creation_failed"; - } catch (Thread::Out_of_stack_space) { - throw "Out_of_stack_space"; - } catch (Genode::Native_capability::Reference_count_overflow) { - throw "Native_capability::Reference_count_overflow"; + bool denied = false; + bool out_of_stack_space = false; + for (; i < max; i++) { + try { + threads[i] = new (heap) Cpu_helper(env, Thread::Name(i + 1), env.cpu()); + if (threads[i]->start() == Thread::Start_result::DENIED) { + denied = true; + break; } + threads[i]->join(); + } catch (Thread::Out_of_stack_space) { + out_of_stack_space = true; + break; + } catch (Genode::Native_capability::Reference_count_overflow) { + warning("Native_capability::Reference_count_overflow"); + denied = true; + break; } - } catch (const char * ex) { - log("created ", i, " threads before I got '", ex, "'"); - for (unsigned j = i; j > 0; j--) { - destroy(heap, threads[j - 1]); - threads[j - 1] = nullptr; - } + } + + for (unsigned j = i; j > 0; j--) { + destroy(heap, threads[j - 1]); + threads[j - 1] = nullptr; + } + + if (denied) { + log("created ", i, " threads before thread creation got denied"); return; } @@ -339,7 +346,8 @@ static void test_create_as_many_threads(Env &env) * We have to get a Out_of_stack_space message, because we can't create * up to max threads, because already the main thread is running ... */ - throw -21; + if (!out_of_stack_space) + throw -21; } @@ -416,9 +424,9 @@ static void test_locks(Genode::Env &env) l5.start(); log(" spin for some time"); - for (unsigned volatile i = 0; i < 8000000; ++i) memory_barrier(); + for (unsigned i = 0; i < 8000000; ++i) memory_barrier(); log(" still spinning"); - for (unsigned volatile i = 0; i < 8000000; ++i) memory_barrier(); + for (unsigned i = 0; i < 8000000; ++i) memory_barrier(); log(" spinning done"); lock.block(); diff --git a/repos/base/src/test/timeout_smp/main.cc b/repos/base/src/test/timeout_smp/main.cc index 70d7a1dfea..8946f7da1d 100644 --- a/repos/base/src/test/timeout_smp/main.cc +++ b/repos/base/src/test/timeout_smp/main.cc @@ -42,7 +42,7 @@ class Test_thread Env &env, TYPE &object, Method method, - unsigned long cpu_idx, + int cpu_idx, Affinity::Space affinity_space) : Thread { @@ -80,7 +80,7 @@ class Test_smp_2 unsigned long _count_3 { 0 }; unsigned long _count_4 { 0 }; unsigned long _count_5 { 0 }; - unsigned long _cpu_idx { 1 }; + int _cpu_idx { 1 }; bool volatile _timeouts_discarded { false }; bool _done_called { false }; Mutex _done_mutex { }; @@ -211,7 +211,7 @@ class Test_smp_1 Env &_env; unsigned long &_nr_of_errors; - unsigned long _cpu_idx { 1 }; + int _cpu_idx { 1 }; bool _max_nr_of_handle_calls_reached { false }; Timer::Connection _timeout_timer { _env }; Timer::Connection _sleep_timer { _env }; diff --git a/repos/base/src/test/timeout_smp/target.mk b/repos/base/src/test/timeout_smp/target.mk index e7820bfbd8..e8f4eaf79e 100644 --- a/repos/base/src/test/timeout_smp/target.mk +++ b/repos/base/src/test/timeout_smp/target.mk @@ -1,5 +1,3 @@ TARGET = test-timeout_smp SRC_CC = main.cc LIBS = base - -CC_CXX_WARN_STRICT_CONVERSION = diff --git a/repos/base/src/test/timer/main.cc b/repos/base/src/test/timer/main.cc index 7b5e2c2cc0..747dbd97b3 100644 --- a/repos/base/src/test/timer/main.cc +++ b/repos/base/src/test/timer/main.cc @@ -91,12 +91,12 @@ struct Stress_test struct Slave { - enum { DURATION_US = DURATION_SEC * 1000 * 1000 }; - enum { MIN_TIMER_PERIOD_US = 1000 }; - enum { MAX_CNT_BASE = DURATION_US / MIN_TIMER_PERIOD_US }; - enum { MAX_CNT_TOLERANCE = MAX_CNT_BASE / 9 }; - enum { MAX_CNT = MAX_CNT_BASE + MAX_CNT_TOLERANCE }; - enum { MIN_CNT = DURATION_US / MAX_SLV_PERIOD_US / 2 }; + static constexpr int DURATION_US = DURATION_SEC * 1000 * 1000; + static constexpr int MIN_TIMER_PERIOD_US = 250; + static constexpr int MAX_CNT_BASE = DURATION_US / MIN_TIMER_PERIOD_US; + static constexpr int MAX_CNT_TOLERANCE = MAX_CNT_BASE / 9; + static constexpr int MAX_CNT = MAX_CNT_BASE + MAX_CNT_TOLERANCE; + static constexpr int MIN_CNT = DURATION_US / MAX_SLV_PERIOD_US / 2; Signal_handler timer_handler; Timer::Connection timer; diff --git a/repos/base/src/test/timer_rate/main.cc b/repos/base/src/test/timer_rate/main.cc index 04177043b1..1f3d63dc37 100644 --- a/repos/base/src/test/timer_rate/main.cc +++ b/repos/base/src/test/timer_rate/main.cc @@ -38,7 +38,7 @@ class Measurement void _handle() { - _count++; + _count = _count + 1; if (_count % _nr_of_periods != 1) { return; } diff --git a/repos/base/src/test/token/main.cc b/repos/base/src/test/token/main.cc index 1595e6f9f4..20ffd6fb1a 100644 --- a/repos/base/src/test/token/main.cc +++ b/repos/base/src/test/token/main.cc @@ -38,10 +38,20 @@ static void test_out_of_bounds_access(Env &env) Attached_ram_dataspace buf_ds(env.ram(), env.rm(), BUF_SIZE); /* attach buffer at start of managed dataspace, leave 2nd page as guard */ - sub_rm.attach_at(buf_ds.cap(), 0); + sub_rm.attach(buf_ds.cap(), { + .size = { }, .offset = { }, + .use_at = true, .at = 0, + .executable = { }, .writeable = true }); /* locally attach managed dataspace */ - char * const buf_ptr = env.rm().attach(sub_rm.dataspace()); + char * const buf_ptr = env.rm().attach(sub_rm.dataspace(), { + .size = { }, .offset = { }, + .use_at = { }, .at = { }, + .executable = { }, .writeable = true } + ).convert( + [&] (Region_map::Range range) { return (char *)range.start; }, + [&] (Region_map::Attach_error) { return nullptr; } + ); auto tokenize_two_tokens_at_end_of_buffer = [&] (char const * const input) { @@ -51,7 +61,7 @@ static void test_out_of_bounds_access(Env &env) char * const token_ptr = buf_ptr + BUF_SIZE - input_len; memcpy(token_ptr, input, input_len); - typedef ::Genode::Token Token; + using Token = ::Genode::Token; Token t(token_ptr, input_len); diff --git a/repos/base/src/test/xml_generator/main.cc b/repos/base/src/test/xml_generator/main.cc index f6004df19b..dfdf729bbd 100644 --- a/repos/base/src/test/xml_generator/main.cc +++ b/repos/base/src/test/xml_generator/main.cc @@ -26,32 +26,32 @@ static size_t fill_buffer_with_xml(char *dst, size_t dst_len) xml.attribute("xpos", "27"); xml.attribute("ypos", "34"); - xml.node("box", [&]() + xml.node("box", [&] { xml.attribute("width", "320"); xml.attribute("height", "240"); }); - xml.node("label", [&] () + xml.node("label", [&] { xml.attribute("name", "a test"); xml.node("sub_label"); - xml.node("another_sub_label", [&] () + xml.node("another_sub_label", [&] { xml.node("sub_sub_label"); }); }); - xml.node("bool", [&] () + xml.node("bool", [&] { xml.attribute("true", true); xml.attribute("false", false); }); - xml.node("signed", [&] () + xml.node("signed", [&] { xml.attribute("int", -1); xml.attribute("long", -2L); xml.attribute("longlong", -3LL); }); - xml.node("unsigned", [&] () + xml.node("unsigned", [&] { xml.attribute("int", 1U); xml.attribute("long", 2UL); @@ -67,61 +67,61 @@ static size_t xml_with_exceptions(char *dst, size_t dst_len) { Genode::Xml_generator xml(dst, dst_len, "config", [&] { - xml.node("level1", [&] () + xml.node("level1", [&] { - xml.node("level2", [&] () + xml.node("level2", [&] { xml.attribute("attr1", 0x87654321ULL); for (unsigned i=0; i < 3; i++) { try { - xml.node("level3_exception", [&] () + xml.node("level3_exception", [&] { xml.attribute("attr1", 1234); xml.attribute("attr2", 4321); xml.attribute("attr3", 2143); - xml.node("level4_exception", [&] () + xml.node("level4_exception", [&] { xml.attribute("attr1", "Hallo"); - xml.node("level5_exception_1", [&] () + xml.node("level5_exception_1", [&] { xml.attribute("attr1", true); xml.attribute("attr2", false); }); - xml.node("level5_exception_2", [&] () { }); + xml.node("level5_exception_2", [&] { }); throw 10 + i; }); }); } catch (unsigned error) { Genode::log("exception with value ", error, " on level 4 (expected error)"); } - xml.node("level3", [&] () + xml.node("level3", [&] { xml.attribute("attr1", "Hallo"); xml.attribute("attr2", 123000 + i); - xml.node("level4_1", [&] () { + xml.node("level4_1", [&] { xml.attribute("attr1", true); xml.attribute("attr2", "Welt"); }); try { - xml.node("level4_exception", [&] () + xml.node("level4_exception", [&] { xml.attribute("attr1", "Welt"); xml.attribute("attr2", 2143); xml.attribute("attr3", false); xml.attribute("attr3", 0x12345678ULL); - xml.node("level5_exception_1", [&] () { }); - xml.node("level5_exception_2", [&] () { }); - xml.node("level5_exception_3", [&] () + xml.node("level5_exception_1", [&] { }); + xml.node("level5_exception_2", [&] { }); + xml.node("level5_exception_3", [&] { - xml.node("level6_exception", [&] () + xml.node("level6_exception", [&] { xml.attribute("attr1", 0x12345678ULL); - xml.node("level7_exception_3", [&] () + xml.node("level7_exception_3", [&] { - xml.node("level8_exception_1", [&] () { }); - xml.node("level8_exception_2", [&] () { }); - xml.node("level8_exception_3", [&] () { }); - xml.node("level8_exception_4", [&] () + xml.node("level8_exception_1", [&] { }); + xml.node("level8_exception_2", [&] { }); + xml.node("level8_exception_3", [&] { }); + xml.node("level8_exception_4", [&] { throw 20 + i; }); @@ -132,9 +132,9 @@ static size_t xml_with_exceptions(char *dst, size_t dst_len) } catch (unsigned error) { Genode::log("exception with value ", error, " on level 8 (expected error)"); } - xml.node("level4_2", [&] () { }); + xml.node("level4_2", [&] { }); try { - xml.node("level4_exception", [&] () + xml.node("level4_exception", [&] { xml.attribute("attr1", "Welt"); xml.attribute("attr2", 2143); @@ -147,7 +147,7 @@ static size_t xml_with_exceptions(char *dst, size_t dst_len) } }); try { - xml.node("level2_exception", [&] () + xml.node("level2_exception", [&] { throw 40; }); @@ -205,7 +205,7 @@ void Component::construct(Genode::Env &env) pattern[i] = (char)i; /* generate XML with the pattern as content */ - Xml_generator xml(dst, sizeof(dst), "data", [&] () { + Xml_generator xml(dst, sizeof(dst), "data", [&] { xml.append_sanitized(pattern, sizeof(pattern)); }); /* parse the generated XML data */ @@ -230,7 +230,7 @@ void Component::construct(Genode::Env &env) * Test arbitrary content */ { - Xml_generator xml(dst, sizeof(dst), "data", [&] () { + Xml_generator xml(dst, sizeof(dst), "data", [&] { xml.append_content(" ", 2 + 2, " == 2 + 2 == ", 4.0, " "); }); diff --git a/repos/base/src/test/xml_node/test.cc b/repos/base/src/test/xml_node/test.cc index 4d26d66147..2963aaa380 100644 --- a/repos/base/src/test/xml_node/test.cc +++ b/repos/base/src/test/xml_node/test.cc @@ -243,11 +243,8 @@ struct Formatted_xml_attribute */ static void print_xml_attr_info(Output &output, Xml_node node, int indent = 0) { - try { - for (Xml_node::Attribute a = node.attribute(0U); ; a = a.next()) - print(output, Formatted_xml_attribute(a, indent), "\n"); - - } catch (Xml_node::Nonexistent_attribute) { } + node.for_each_attribute([&] (Xml_attribute const &a) { + print(output, Formatted_xml_attribute(a, indent), "\n"); }); } diff --git a/repos/base/src/timer/epit/imx6/target.inc b/repos/base/src/timer/epit/imx6/target.inc deleted file mode 100644 index 68fea18f9e..0000000000 --- a/repos/base/src/timer/epit/imx6/target.inc +++ /dev/null @@ -1,9 +0,0 @@ -TARGET = imx6_timer_drv -REQUIRES = arm_v7 -GEN_DIR := $(dir $(call select_from_repositories,src/timer/main.cc)) -INC_DIR += $(GEN_DIR)/epit -SRC_CC += epit/time_source.cc epit/imx6/timer.cc - -include $(GEN_DIR)/target.inc - -vpath %.cc $(GEN_DIR) diff --git a/repos/base/src/timer/epit/imx6/timer.cc b/repos/base/src/timer/epit/imx6/timer.cc deleted file mode 100644 index 9747f8e072..0000000000 --- a/repos/base/src/timer/epit/imx6/timer.cc +++ /dev/null @@ -1,33 +0,0 @@ -/* - * \brief Time source for i.MX6 (EPIT2) - * \author Norman Feske - * \author Martin Stein - * \author Stefan Kalkowski - * \author Alexander Boettcher - * \date 2009-06-16 - */ - -/* - * Copyright (C) 2009-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -/* base include */ -#include - -/* local include */ -#include - -using namespace Genode; - -Timer::Time_source::Time_source(Env &env) -: - Attached_mmio(env, Imx6::EPIT_2_MMIO_BASE, Imx6::EPIT_2_MMIO_SIZE), - Signalled_time_source(env), - _timer_irq(env, Imx6::EPIT_2_IRQ) -{ - _timer_irq.sigh(_signal_handler); - while (read()) ; -} diff --git a/repos/base/src/timer/epit/time_source.cc b/repos/base/src/timer/epit/time_source.cc deleted file mode 100644 index f51eb02312..0000000000 --- a/repos/base/src/timer/epit/time_source.cc +++ /dev/null @@ -1,55 +0,0 @@ -/* - * \brief Time source that uses the Enhanced Periodic Interrupt Timer (Freescale) - * \author Norman Feske - * \author Martin Stein - * \author Stefan Kalkowski - * \author Alexander Boettcher - * \date 2009-06-16 - */ - -/* - * Copyright (C) 2009-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -/* local includes */ -#include - -using namespace Genode; - - -void Timer::Time_source::set_timeout(Genode::Microseconds duration, - Genode::Timeout_handler &handler) -{ - unsigned long const ticks = (unsigned long)((1ULL * duration.value * TICKS_PER_MS) / 1000); - _handler = &handler; - _timer_irq.ack_irq(); - _cleared_ticks = 0; - - /* disable timer */ - write(0); - - /* clear interrupt and install timeout */ - write(1); - write(Cr::prepare_one_shot()); - write(Cnt::MAX - ticks); - - /* start timer */ - write(1); -} - - -Duration Timer::Time_source::curr_time() -{ - unsigned long const uncleared_ticks = Cnt::MAX - read() - _cleared_ticks; - unsigned long const uncleared_us = timer_ticks_to_us(uncleared_ticks, TICKS_PER_MS); - - /* update time only on IRQs and if rate is under 1000 per second */ - if (_irq || uncleared_us > 1000) { - _curr_time.add(Genode::Microseconds(uncleared_us)); - _cleared_ticks += uncleared_ticks; - } - return _curr_time; -} diff --git a/repos/base/src/timer/epit/time_source.h b/repos/base/src/timer/epit/time_source.h deleted file mode 100644 index f4fd4a54ea..0000000000 --- a/repos/base/src/timer/epit/time_source.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * \brief Time source that uses the Enhanced Periodic Interrupt Timer (Freescale) - * \author Norman Feske - * \author Martin Stein - * \author Stefan Kalkowski - * \date 2009-06-16 - */ - -/* - * Copyright (C) 2009-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _TIME_SOURCE_H_ -#define _TIME_SOURCE_H_ - -/* Genode includes */ -#include -#include -#include - -/* local includes */ -#include - -namespace Timer { class Time_source; } - - -class Timer::Time_source : private Genode::Attached_mmio, - public Genode::Signalled_time_source -{ - private: - - enum { TICKS_PER_MS = 66000 }; - - struct Cr : Register<0x0, 32> - { - struct En : Bitfield<0, 1> { }; - struct En_mod : Bitfield<1, 1> { enum { RELOAD = 1 }; }; - struct Oci_en : Bitfield<2, 1> { }; - struct Swr : Bitfield<16, 1> { }; - struct Clk_src : Bitfield<24, 2> { enum { HIGH_FREQ_REF_CLK = 2 }; }; - - static access_t prepare_one_shot() - { - access_t cr = 0; - En_mod::set(cr, En_mod::RELOAD); - Oci_en::set(cr, 1); - Clk_src::set(cr, Clk_src::HIGH_FREQ_REF_CLK); - return cr; - } - }; - - struct Sr : Register<0x4, 32> { struct Ocif : Bitfield<0, 1> { }; }; - struct Cmpr : Register<0xc, 32> { }; - struct Cnt : Register<0x10, 32> { enum { MAX = ~(access_t)0 }; }; - - Genode::Irq_connection _timer_irq; - Genode::Duration _curr_time { Genode::Microseconds(0) }; - Genode::Microseconds const _max_timeout { Genode::timer_ticks_to_us(Cnt::MAX / 2, TICKS_PER_MS) }; - unsigned long _cleared_ticks { 0 }; - - public: - - Time_source(Genode::Env &env); - - - /************************* - ** Genode::Time_source ** - *************************/ - - Genode::Duration curr_time() override; - void set_timeout(Genode::Microseconds, Genode::Timeout_handler &) override; - Genode::Microseconds max_timeout() const override { return _max_timeout; }; -}; - -#endif /* _TIME_SOURCE_H_ */ diff --git a/repos/base/src/timer/fiasco/time_source.cc b/repos/base/src/timer/fiasco/time_source.cc deleted file mode 100644 index efa588f775..0000000000 --- a/repos/base/src/timer/fiasco/time_source.cc +++ /dev/null @@ -1,101 +0,0 @@ -/* - * \brief Time source that uses sleeping by the means of the kernel - * \author Christian Helmuth - * \author Norman Feske - * \author Martin Stein - * \date 2006-08-30 - */ - -/* - * Copyright (C) 2006-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -/* Genode includes */ -#include -#include - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wconversion" - -/* Fiasco includes */ -namespace Fiasco { -#include -#include -} - -/* - * On L4/Fiasco, the KIP layout is defined in 'kernel.h', which does not exist - * on Fiasco.OC. We test for 'L4_SYS_KIP_H__' to check for the L4/Fiasco case - * and include 'kernel.h'. This works because the Fiasco.OC headers do not use - * include guards ('L4_SYS_KIP_H__' is undefined on Fiasco.OC). - */ -#ifdef L4_SYS_KIP_H__ -namespace Fiasco { -#include -} -#endif /* L4_SYS_KIP_H__ */ -#pragma GCC diagnostic pop - -/* local includes */ -#include - -using namespace Fiasco; -using Microseconds = Genode::Microseconds; -using Duration = Genode::Duration; -using Genode::uint64_t; - - -static l4_timeout_s mus_to_timeout(uint64_t mus) -{ - if (mus == 0) - return L4_IPC_TIMEOUT_0; - else if (mus == ~(uint64_t)0) - return L4_IPC_TIMEOUT_NEVER; - - long e = Genode::log2((unsigned long)mus) - 7; - - if (e < 0) e = 0; - - uint64_t m = mus / (1UL << e); - - enum { M_MASK = 0x3ff }; - - /* check corner case */ - if ((e > 31 ) || (m > M_MASK)) { - Genode::warning("invalid timeout ", mus, ", using max. values"); - e = 0; - m = M_MASK; - } - return l4_timeout_rel(m & M_MASK, (unsigned)e); -} - - -Microseconds Timer::Time_source::max_timeout() const -{ - Genode::Mutex::Guard lock_guard(_mutex); - return Microseconds(1000 * 1000 * 100); -} - - -Duration Timer::Time_source::curr_time() -{ - Genode::Mutex::Guard mutex_guard(_mutex); - static Genode::Attached_rom_dataspace kip_ds(_env, "l4v2_kip"); - static Fiasco::l4_kernel_info_t * const kip = - kip_ds.local_addr(); - -#ifdef L4_SYS_KIP_H__ - Fiasco::l4_cpu_time_t const clock = kip->clock; -#else - Fiasco::l4_cpu_time_t const clock = Fiasco::l4_kip_clock(kip); -#endif - - return Duration(Microseconds(clock)); -} - - -void Timer::Time_source::_usleep(uint64_t usecs) { - l4_ipc_sleep(l4_timeout(L4_IPC_TIMEOUT_NEVER, mus_to_timeout(usecs))); } diff --git a/repos/base/src/timer/gpt/imx7/target.inc b/repos/base/src/timer/gpt/imx7/target.inc deleted file mode 100644 index 88b3156972..0000000000 --- a/repos/base/src/timer/gpt/imx7/target.inc +++ /dev/null @@ -1,9 +0,0 @@ -TARGET = imx7_timer_drv -REQUIRES = arm_v7 -GEN_DIR := $(BASE_DIR)/src/timer -INC_DIR += $(GEN_DIR)/gpt -SRC_CC += gpt/time_source.cc gpt/imx7/timer.cc - -include $(GEN_DIR)/target.inc - -vpath %.cc $(GEN_DIR) diff --git a/repos/base/src/timer/gpt/imx7/timer.cc b/repos/base/src/timer/gpt/imx7/timer.cc deleted file mode 100644 index b7d841ec54..0000000000 --- a/repos/base/src/timer/gpt/imx7/timer.cc +++ /dev/null @@ -1,29 +0,0 @@ -/* - * \brief Time source for i.MX7 (GPT1) - * \author Stefan Kalkowski - * \date 2019-04-13 - */ - -/* - * Copyright (C) 2019 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -/* local include */ -#include - -using namespace Genode; - -enum { - MMIO_BASE = 0x302d0000, - MMIO_SIZE = 0x1000, - IRQ = 87, -}; - - -Timer::Time_source::Time_source(Env &env) -: Attached_mmio(env, MMIO_BASE, MMIO_SIZE), - Signalled_time_source(env), - _timer_irq(env, IRQ) { _initialize(); } diff --git a/repos/base/src/timer/gpt/time_source.cc b/repos/base/src/timer/gpt/time_source.cc deleted file mode 100644 index 7580152b6f..0000000000 --- a/repos/base/src/timer/gpt/time_source.cc +++ /dev/null @@ -1,75 +0,0 @@ -/* - * \brief Time source that uses the General Purpose Timer (Freescale) - * \author Stefan Kalkowski - * \date 2019-04-13 - */ - -/* - * Copyright (C) 2019 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -/* local includes */ -#include - -using namespace Genode; - - -void Timer::Time_source::set_timeout(Genode::Microseconds duration, - Timeout_handler &handler) -{ - _handler = &handler; - - /* set to minimum ticks value to not miss a too short timeout */ - uint32_t const ticks = - max((uint32_t)1, (uint32_t)((duration.value * TICKS_PER_MS) / 1000)); - - /* clear interrupts */ - if (read()) { - write(0xffffffff); - _timer_irq.ack_irq(); - } - - /* set new timeout */ - write(read() + ticks); -} - - -Duration Timer::Time_source::curr_time() -{ - Cnt::access_t cur_cnt = read(); - Genode::Microseconds us(timer_ticks_to_us(cur_cnt - _last_cnt, TICKS_PER_MS)); - _last_cnt = cur_cnt; - _curr_time.add(us); - return _curr_time; -} - - -Microseconds Timer::Time_source::max_timeout() const -{ - static unsigned long max = timer_ticks_to_us(0xffffffff, TICKS_PER_MS); - return Genode::Microseconds(max); -} - - -void Timer::Time_source::_initialize() -{ - _timer_irq.sigh(_signal_handler); - - write(0); - write(0); - write(0); - write(0); - write(0); - write(0); - write(0); - write(Cr::Clk_src::HIGH_FREQ_REF_CLK); - while (read()) ; - write(0); - write(1); - write(1); - write(1); - write(1); -} diff --git a/repos/base/src/timer/gpt/time_source.h b/repos/base/src/timer/gpt/time_source.h deleted file mode 100644 index 4a5a3d1e50..0000000000 --- a/repos/base/src/timer/gpt/time_source.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * \brief Time source that uses the General Purpose Timer (Freescale) - * \author Stefan Kalkowski - * \date 2019-04-13 - */ - -/* - * Copyright (C) 2019 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _TIME_SOURCE_H_ -#define _TIME_SOURCE_H_ - -/* Genode includes */ -#include -#include -#include - -/* local includes */ -#include - -namespace Timer { class Time_source; } - - -class Timer::Time_source : private Genode::Attached_mmio, - public Genode::Signalled_time_source -{ - private: - - enum { TICKS_PER_MS = 500 }; - - struct Cr : Register<0x0, 32> - { - struct En : Bitfield<0, 1> { }; - struct En_mod : Bitfield<1, 1> { }; - struct Clk_src : Bitfield<6, 3> { enum { HIGH_FREQ_REF_CLK = 2 }; }; - struct Frr : Bitfield<9, 1> { }; - struct Swr : Bitfield<15, 1> { }; - }; - - struct Pr : Register<0x4, 32> { }; - struct Sr : Register<0x8, 32> { }; - struct Ir : Register<0xc, 32> { }; - struct Ocr1 : Register<0x10, 32> { }; - struct Ocr2 : Register<0x14, 32> { }; - struct Ocr3 : Register<0x18, 32> { }; - struct Icr1 : Register<0x1c, 32> { }; - struct Icr2 : Register<0x20, 32> { }; - struct Cnt : Register<0x24, 32> { }; - - - Genode::Irq_connection _timer_irq; - Genode::Duration _curr_time { Genode::Microseconds(0) }; - Cnt::access_t _last_cnt { 0 }; - - void _initialize(); - - public: - - Time_source(Genode::Env &env); - - - /************************* - ** Genode::Time_source ** - *************************/ - - Genode::Duration curr_time() override; - void set_timeout(Genode::Microseconds duration, - Genode::Timeout_handler &handler) override; - Genode::Microseconds max_timeout() const override; -}; - -#endif /* _TIME_SOURCE_H_ */ diff --git a/repos/base/src/timer/include/root_component.h b/repos/base/src/timer/include/root_component.h deleted file mode 100644 index 498dc13156..0000000000 --- a/repos/base/src/timer/include/root_component.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * \brief Root interface to timer service - * \author Norman Feske - * \author Martin Stein - * \date 2006-08-15 - */ - -/* - * Copyright (C) 2006-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _ROOT_COMPONENT_H_ -#define _ROOT_COMPONENT_H_ - -/* Genode includes */ -#include - -/* local includes */ -#include -#include - -namespace Timer { class Root_component; } - - -class Timer::Root_component : public Genode::Root_component -{ - private: - - enum { MIN_TIMEOUT_US = 1000 }; - - Time_source _time_source; - Genode::Timeout_scheduler _timeout_scheduler; - - - /******************** - ** Root_component ** - ********************/ - - Session_component *_create_session(const char *args) override - { - using namespace Genode; - size_t const ram_quota = - Arg_string::find_arg(args, "ram_quota").ulong_value(0); - - if (ram_quota < sizeof(Session_component)) { - throw Insufficient_ram_quota(); } - - return new (md_alloc()) - Session_component(_timeout_scheduler); - } - - public: - - Root_component(Genode::Env &env, Genode::Allocator &md_alloc) - : - Genode::Root_component(&env.ep().rpc_ep(), &md_alloc), - _time_source(env), - _timeout_scheduler(_time_source, Microseconds(MIN_TIMEOUT_US)) - { - _timeout_scheduler._enable(); - } -}; - -#endif /* _ROOT_COMPONENT_H_ */ diff --git a/repos/base/src/timer/include/session_component.h b/repos/base/src/timer/include/session_component.h deleted file mode 100644 index dd9c456355..0000000000 --- a/repos/base/src/timer/include/session_component.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * \brief Instance of the timer session interface - * \author Norman Feske - * \author Markus Partheymueller - * \author Martin Stein - * \date 2006-08-15 - */ - -/* - * Copyright (C) 2006-2017 Genode Labs GmbH - * Copyright (C) 2012 Intel Corporation - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _SESSION_COMPONENT_ -#define _SESSION_COMPONENT_ - -/* Genode includes */ -#include -#include -#include -#include - -namespace Timer { - - using Genode::uint64_t; - using Microseconds = Genode::Microseconds; - using Duration = Genode::Duration; - class Session_component; -} - - -class Timer::Session_component : public Genode::Rpc_object, - private Genode::List::Element, - private Genode::Timeout_handler -{ - private: - - friend class Genode::List; - - Genode::Timeout _timeout; - Genode::Timeout_scheduler &_timeout_scheduler; - Genode::Signal_context_capability _sigh { }; - - uint64_t const _init_time_us = - _timeout_scheduler.curr_time().trunc_to_plain_us().value; - - - /********************* - ** Timeout_handler ** - *********************/ - - void handle_timeout(Duration) override { - Genode::Signal_transmitter(_sigh).submit(); } - - public: - - Session_component(Genode::Timeout_scheduler &timeout_scheduler) - : _timeout(timeout_scheduler), _timeout_scheduler(timeout_scheduler) { } - - - /******************** - ** Timer::Session ** - ********************/ - - void trigger_once(uint64_t us) override - { - /* - * FIXME Workaround for the problem that Alarm scheduler may - * categorize big timeouts into the wrong time counter - * period due to its outdated internal time. This is needed - * only because the Alarm framework solely takes absolute - * time values on one-shot timeouts. and thus As soon as the - * Alarm framework takes solely relative time values, please - * remove this. - */ - Microseconds typed_us((us > ~(uint64_t)0 >> 1) ? ~(uint64_t)0 >> 1 : us); - _timeout.schedule_one_shot(typed_us, *this); - } - - void trigger_periodic(uint64_t us) override - { - if (us) - _timeout.schedule_periodic(Microseconds(us), *this); - else - _timeout.discard(); - } - - void sigh(Signal_context_capability sigh) override - { - _sigh = sigh; - if (!sigh.valid()) - _timeout.discard(); - } - - uint64_t elapsed_ms() const override { - return elapsed_us() / 1000; } - - uint64_t elapsed_us() const override { - return _timeout_scheduler.curr_time().trunc_to_plain_us().value - - _init_time_us; } - - void msleep(uint64_t) override { /* never called at the server side */ } - void usleep(uint64_t) override { /* never called at the server side */ } -}; - -#endif /* _SESSION_COMPONENT_ */ diff --git a/repos/base/src/timer/include/signalled_time_source.h b/repos/base/src/timer/include/signalled_time_source.h deleted file mode 100644 index d2145fbddc..0000000000 --- a/repos/base/src/timer/include/signalled_time_source.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * \brief Time source that handles timeouts via a signal handler - * \author Martin Stein - * \date 2016-11-04 - */ - -/* - * Copyright (C) 2016-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _SIGNALLED_TIME_SOURCE_H_ -#define _SIGNALLED_TIME_SOURCE_H_ - -/* Genode includes */ -#include -#include -#include - -namespace Genode { class Signalled_time_source; } - - -class Genode::Signalled_time_source : public Time_source -{ - private: - - /* - * Noncopyable - */ - Signalled_time_source(Signalled_time_source const &); - Signalled_time_source &operator = (Signalled_time_source const &); - - protected: - - using Signal_handler = Genode::Signal_handler; - - Signal_handler _signal_handler; - Timeout_handler *_handler = nullptr; - bool _irq = false; - - void _handle_timeout() - { - if (_handler) { - _irq = true; - Duration time(curr_time()); - _irq = false; - _handler->handle_timeout(time); - } - } - - public: - - Signalled_time_source(Env &env) - : - _signal_handler(env.ep(), *this, - &Signalled_time_source::_handle_timeout) - { } -}; - -#endif /* _SIGNALLED_TIME_SOURCE_H_ */ diff --git a/repos/base/src/timer/include/threaded_time_source.h b/repos/base/src/timer/include/threaded_time_source.h deleted file mode 100644 index ea604e93be..0000000000 --- a/repos/base/src/timer/include/threaded_time_source.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * \brief Time source that uses an extra thread for timeout handling - * \author Norman Feske - * \author Martin Stein - * \date 2009-06-16 - */ - -/* - * Copyright (C) 2009-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _THREADED_TIME_SOURCE_H_ -#define _THREADED_TIME_SOURCE_H_ - -/* Genode inludes */ -#include -#include -#include - -namespace Timer { - - using Genode::Microseconds; - using Genode::Duration; - using Genode::Timeout_handler; - - class Threaded_time_source; -} - - -class Timer::Threaded_time_source : public Genode::Time_source, - protected Genode::Thread -{ - public: - - enum Result_of_wait_for_irq { IRQ_TRIGGERED, CANCELLED }; - - private: - - struct Irq_dispatcher : Genode::Interface - { - GENODE_RPC(Rpc_do_dispatch, void, do_dispatch); - GENODE_RPC_INTERFACE(Rpc_do_dispatch); - }; - - struct Irq_dispatcher_component : Genode::Rpc_object - { - private: - - /* - * Noncopyable - */ - Irq_dispatcher_component(Irq_dispatcher_component const &); - Irq_dispatcher_component &operator = (Irq_dispatcher_component const &); - - public: - - Timeout_handler *handler = nullptr; - Threaded_time_source &ts; - - Irq_dispatcher_component(Threaded_time_source &ts) : ts(ts) { } - - /******************** - ** Irq_dispatcher ** - ********************/ - - void do_dispatch() - { - /* call curr_time in ep and not in ts (no locks in use!) */ - ts._irq = true; - Duration us = ts.curr_time(); - ts._irq = false; - - if (handler) - handler->handle_timeout(us); - } - - } _irq_dispatcher_component; - - Genode::Capability _irq_dispatcher_cap; - - virtual Result_of_wait_for_irq _wait_for_irq() = 0; - - /************ - ** Thread ** - ************/ - - void entry() override - { - while (true) { - if (_wait_for_irq() == IRQ_TRIGGERED) { - _irq_dispatcher_cap.call(); - } - } - } - - protected: - - bool _irq { false }; - - public: - - Threaded_time_source(Genode::Env &env) - : - Thread(env, "threaded_time_source", 8 * 1024 * sizeof(Genode::addr_t)), - _irq_dispatcher_component(*this), - _irq_dispatcher_cap(env.ep().rpc_ep().manage(&_irq_dispatcher_component)) - { } - - void handler(Timeout_handler &handler) { - _irq_dispatcher_component.handler = &handler; } -}; - -#endif /* _THREADED_TIME_SOURCE_H_ */ diff --git a/repos/base/src/timer/main.cc b/repos/base/src/timer/main.cc deleted file mode 100644 index c8b5250458..0000000000 --- a/repos/base/src/timer/main.cc +++ /dev/null @@ -1,43 +0,0 @@ -/* - * \brief Provides the Timer service to multiple clients - * \author Norman Feske - * \author Martin Stein - * \date 2006-08-15 - */ - -/* - * Copyright (C) 2006-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -/* Genode includes */ -#include -#include - -/* local includes */ -#include - -using namespace Genode; - - -class Main -{ - private: - - Sliced_heap _sliced_heap; - Timer::Root_component _root; - - public: - - Main(Env &env) : _sliced_heap(env.ram(), env.rm()), - _root(env, _sliced_heap) - { - env.parent().announce(env.ep().manage(_root)); - } -}; - - -size_t Component::stack_size() { return 4*1024*sizeof(addr_t); } -void Component::construct(Env &env) { static Main main(env); } diff --git a/repos/base/src/timer/periodic/time_source.cc b/repos/base/src/timer/periodic/time_source.cc deleted file mode 100644 index 46deb0ed45..0000000000 --- a/repos/base/src/timer/periodic/time_source.cc +++ /dev/null @@ -1,54 +0,0 @@ -/* - * \brief Time source that uses sleeping by the means of the kernel - * \author Norman Feske - * \author Martin Stein - * \date 2009-06-16 - */ - -/* - * Copyright (C) 2009-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -/* local includes */ -#include - -using namespace Genode; - - -void Timer::Time_source::set_timeout(Microseconds duration, - Timeout_handler &handler) -{ - Mutex::Guard mutex_guard(_mutex); - Threaded_time_source::handler(handler); - _next_timeout_us = duration.value; -} - - -Timer::Time_source::Result_of_wait_for_irq -Timer::Time_source::_wait_for_irq() -{ - enum { SLEEP_GRANULARITY_US = 1000 }; - uint64_t last_time_us = curr_time().trunc_to_plain_us().value; - _mutex.acquire(); - while (_next_timeout_us > 0) { - _mutex.release(); - - try { _usleep(SLEEP_GRANULARITY_US); } - catch (Blocking_canceled) { } - - uint64_t curr_time_us = curr_time().trunc_to_plain_us().value; - uint64_t sleep_duration_us = curr_time_us - last_time_us; - last_time_us = curr_time_us; - - _mutex.acquire(); - if (_next_timeout_us >= sleep_duration_us) - _next_timeout_us -= sleep_duration_us; - else - break; - } - _mutex.release(); - return IRQ_TRIGGERED; -} diff --git a/repos/base/src/timer/periodic/time_source.h b/repos/base/src/timer/periodic/time_source.h deleted file mode 100644 index eb69db96fd..0000000000 --- a/repos/base/src/timer/periodic/time_source.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * \brief Time source that uses sleeping by the means of the kernel - * \author Norman Feske - * \author Martin Stein - * \date 2009-06-16 - */ - -/* - * Copyright (C) 2009-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _TIME_SOURCE_H_ -#define _TIME_SOURCE_H_ - -/* local includes */ -#include - -namespace Timer { - - using Genode::uint64_t; - class Time_source; -} - - -class Timer::Time_source : public Threaded_time_source -{ - private: - - Genode::Env &_env; - - Genode::Mutex mutable _mutex { }; - uint64_t _curr_time_us = 0; - uint64_t _next_timeout_us = max_timeout().value; - - void _usleep(uint64_t us); - - - /************************** - ** Threaded_time_source ** - **************************/ - - Result_of_wait_for_irq _wait_for_irq() override; - - public: - - Time_source(Genode::Env &env) - : Threaded_time_source(env), _env(env) { start(); } - - - /************************* - ** Genode::Time_source ** - *************************/ - - Duration curr_time() override; - Microseconds max_timeout() const override; - void set_timeout(Microseconds duration, Genode::Timeout_handler &handler) override; -}; - -#endif /* _TIME_SOURCE_H_ */ diff --git a/repos/base/src/timer/pit/main.cc b/repos/base/src/timer/pit/main.cc new file mode 100644 index 0000000000..17e37ccbf2 --- /dev/null +++ b/repos/base/src/timer/pit/main.cc @@ -0,0 +1,426 @@ +/* + * \brief Timer driver for the PIT + * \author Norman Feske + * \author Alexander Boettcher + * \date 2024-05-13 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* Genode includes */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* base-internal includes */ +#include + +namespace Timer { + + using namespace Genode; + + struct Clock; + struct Device; + struct Alarm; + struct Root; + struct Session_component; + struct Main; + + using Alarms = Alarm_registry; +} + + +struct Timer::Clock +{ + uint64_t us; + + static constexpr uint64_t MASK = uint64_t(-1); + + uint64_t value() const { return us; } + + void print(Output &out) const { Genode::print(out, us/1000); } +}; + + +class Timer::Device : Noncopyable +{ + private: + + enum { + PIT_TICKS_PER_SECOND = 1193182, + PIT_MAX_COUNT = 65535, + PIT_MAX_USEC = (1000ull * 1000 * PIT_MAX_COUNT) / + (PIT_TICKS_PER_SECOND), + + PIT_DATA_PORT_0 = 0x40, /* data port for PIT channel 0, + connected to the PIC */ + PIT_CMD_PORT = 0x43, /* PIT command port */ + IRQ_PIT = 0, /* timer interrupt at the PIC */ + + /* + * Bit definitions for accessing the PIT command port + */ + PIT_CMD_SELECT_CHANNEL_0 = 0 << 6, + PIT_CMD_ACCESS_LO = 1 << 4, + PIT_CMD_ACCESS_LO_HI = 3 << 4, + PIT_CMD_MODE_IRQ = 0 << 1, + PIT_CMD_MODE_RATE = 2 << 1, + + PIT_CMD_READ_BACK = 3 << 6, + PIT_CMD_RB_COUNT = 0 << 5, + PIT_CMD_RB_STATUS = 0 << 4, + PIT_CMD_RB_CHANNEL_0 = 1 << 1, + + /* + * Bit definitions of the PIT status byte + */ + PIT_STAT_INT_LINE = 1 << 7, + }; + + /* PIT counter */ + struct Counter { uint16_t value; }; + + public: + + struct Wakeup_dispatcher : Interface + { + virtual void dispatch_device_wakeup() = 0; + }; + + struct Deadline : Clock { }; + + static constexpr Deadline infinite_deadline { uint64_t(-1) }; + + private: + + Env &_env; + + Io_port_connection _io_port { _env, PIT_DATA_PORT_0, + PIT_CMD_PORT - PIT_DATA_PORT_0 + 1 }; + + Irq_connection _timer_irq { _env, unsigned(IRQ_PIT) }; + + uint64_t _max_timeout_us { PIT_MAX_USEC }; + + Wakeup_dispatcher &_dispatcher; + + Signal_handler _handler { _env.ep(), *this, &Device::_handle_timeout }; + + uint64_t _curr_time_us { }; + Counter _last_read { }; + bool _wrap_handled { }; + + uint64_t _convert_counter_to_us(uint64_t counter) + { + /* round up to 1us in case of rest */ + auto const mod = (counter * 1000 * 1000) % PIT_TICKS_PER_SECOND; + return (counter * 1000 * 1000 / PIT_TICKS_PER_SECOND) + + (mod ? 1 : 0); + } + + Counter _convert_relative_us_to_counter(uint64_t rel_us) + { + return { .value = uint16_t(min(rel_us * PIT_TICKS_PER_SECOND / 1000 / 1000, + uint64_t(PIT_MAX_COUNT))) }; + } + + void _handle_timeout() + { + _dispatcher.dispatch_device_wakeup(); + _timer_irq.ack_irq(); + } + + void _set_counter(Counter const &cnt) + { + /* wrap status gets reset by re-programming counter */ + _wrap_handled = false; + + _io_port.outb(PIT_DATA_PORT_0, uint8_t( cnt.value & 0xff)); + _io_port.outb(PIT_DATA_PORT_0, uint8_t((cnt.value >> 8) & 0xff)); + } + + void _with_counter(auto const &fn) + { + /* read-back count of counter 0 */ + _io_port.outb(PIT_CMD_PORT, PIT_CMD_READ_BACK | + PIT_CMD_RB_COUNT | + PIT_CMD_RB_STATUS | + PIT_CMD_RB_CHANNEL_0); + + /* read status byte from latch register */ + uint8_t status = _io_port.inb(PIT_DATA_PORT_0); + + /* read low and high bytes from latch register */ + uint16_t lo = _io_port.inb(PIT_DATA_PORT_0); + uint16_t hi = _io_port.inb(PIT_DATA_PORT_0); + + bool const wrapped = !!(status & PIT_STAT_INT_LINE); + + fn(Counter(uint16_t((hi << 8) | lo)), wrapped && !_wrap_handled); + + /* only handle wrap one time until next _set_counter */ + if (wrapped) + _wrap_handled = true; + } + + void _advance_current_time() + { + _with_counter([&](Counter const &pit, bool wrapped) { + + auto diff = (!wrapped && (_last_read.value >= pit.value)) + ? _last_read.value - pit.value + : PIT_MAX_COUNT - pit.value + _last_read.value; + + _curr_time_us += _convert_counter_to_us(diff); + + _last_read = pit; + }); + } + + public: + + Device(Env &env, Wakeup_dispatcher &dispatcher) + : _env(env), _dispatcher(dispatcher) + { + /* operate PIT in one-shot mode */ + _io_port.outb(PIT_CMD_PORT, PIT_CMD_SELECT_CHANNEL_0 | + PIT_CMD_ACCESS_LO_HI | PIT_CMD_MODE_IRQ); + + _timer_irq.sigh(_handler); + + _handle_timeout(); + } + + Clock now() + { + _advance_current_time(); + + return Clock { .us = _curr_time_us }; + } + + void update_deadline(Deadline const deadline) + { + uint64_t const now_us = now().us; + uint64_t const rel_us = (deadline.us > now_us) + ? min(_max_timeout_us, deadline.us - now_us) + : 1; + + auto const pit_cnt = _convert_relative_us_to_counter(rel_us); + + _last_read = pit_cnt; + + _set_counter(pit_cnt); + } +}; + + +struct Timer::Alarm : Alarms::Element +{ + Session_component &session; + + Alarm(Alarms &alarms, Session_component &session, Clock time) + : + Alarms::Element(alarms, *this, time), session(session) + { } + + void print(Output &out) const; +}; + + +static Timer::Device::Deadline next_deadline(Timer::Alarms &alarms) +{ + using namespace Timer; + + return alarms.soonest(Clock { 0 }).convert( + [&] (Clock soonest) -> Device::Deadline { + + /* scan alarms for a cluster nearby the soonest */ + uint64_t const MAX_DELAY_US = 250; + Device::Deadline result { soonest.us }; + alarms.for_each_in_range(soonest, Clock { soonest.us + MAX_DELAY_US }, + [&] (Alarm const &alarm) { + result.us = max(result.us, alarm.time.us); }); + + return result; + }, + [&] (Alarms::None) { return Device::infinite_deadline; }); +} + + +struct Timer::Session_component : Session_object +{ + Alarms &_alarms; + Device &_device; + + Signal_context_capability _sigh { }; + + Clock const _creation_time = _device.now(); + + uint64_t _local_now_us() const { return _device.now().us - _creation_time.us; } + + struct Period { uint64_t us; }; + + Constructible _period { }; + Constructible _alarm { }; + + Session_component(Env &env, + Resources const &resources, + Label const &label, + Diag const &diag, + Alarms &alarms, + Device &device) + : + Session_object(env.ep(), resources, label, diag), + _alarms(alarms), _device(device) + { } + + /** + * Called by Device::Wakeup_dispatcher + */ + void handle_wakeup() + { + if (_sigh.valid()) + Signal_transmitter(_sigh).submit(); + + if (_period.constructed()) { + Clock const next = _alarm.constructed() + ? Clock { _alarm->time.us + _period->us } + : Clock { _device.now().us + _period->us }; + + _alarm.construct(_alarms, *this, next); + + } else /* response of 'trigger_once' */ { + _alarm.destruct(); + } + } + + /****************************** + ** Timer::Session interface ** + ******************************/ + + void trigger_once(uint64_t rel_us) override + { + _period.destruct(); + _alarm.destruct(); + + Clock const now = _device.now(); + + rel_us = max(rel_us, 250u); + _alarm.construct(_alarms, *this, Clock { now.us + rel_us }); + + _device.update_deadline(next_deadline(_alarms)); + } + + void trigger_periodic(uint64_t period_us) override + { + _period.destruct(); + _alarm.destruct(); + + if (period_us) { + period_us = max(period_us, 1000u); + _period.construct(period_us); + handle_wakeup(); + } + + _device.update_deadline(next_deadline(_alarms)); + } + + void sigh(Signal_context_capability sigh) override { _sigh = sigh; } + + uint64_t elapsed_ms() const override { return _local_now_us()/1000; } + uint64_t elapsed_us() const override { return _local_now_us(); } + + void msleep(uint64_t) override { } + void usleep(uint64_t) override { } +}; + + +struct Timer::Root : public Root_component +{ + private: + + Env &_env; + Alarms &_alarms; + Device &_device; + + protected: + + Session_component *_create_session(const char *args) override + { + return new (md_alloc()) + Session_component(_env, + session_resources_from_args(args), + session_label_from_args(args), + session_diag_from_args(args), + _alarms, _device); + } + + void _upgrade_session(Session_component *s, const char *args) override + { + s->upgrade(ram_quota_from_args(args)); + s->upgrade(cap_quota_from_args(args)); + } + + void _destroy_session(Session_component *session) override + { + Genode::destroy(md_alloc(), session); + } + + public: + + Root(Env &env, Allocator &md_alloc, Alarms &alarms, Device &device) + : + Root_component(&env.ep().rpc_ep(), &md_alloc), + _env(env), _alarms(alarms), _device(device) + { } +}; + + +void Timer::Alarm::print(Output &out) const { Genode::print(out, session.label()); } + + +struct Timer::Main : Device::Wakeup_dispatcher +{ + Env &_env; + + Device _device { _env, *this }; + + Alarms _alarms { }; + + Sliced_heap _sliced_heap { _env.ram(), _env.rm() }; + + Root _root { _env, _sliced_heap, _alarms, _device }; + + /** + * Device::Wakeup_dispatcher + */ + void dispatch_device_wakeup() override + { + Clock const now = _device.now(); + + /* handle and remove pending alarms */ + while (_alarms.with_any_in_range({ 0 }, now, [&] (Alarm &alarm) { + alarm.session.handle_wakeup(); })); + + /* schedule next wakeup */ + _device.update_deadline(next_deadline(_alarms)); + } + + Main(Genode::Env &env) : _env(env) + { + _env.parent().announce(_env.ep().manage(_root)); + } +}; + + +void Component::construct(Genode::Env &env) { static Timer::Main inst(env); } diff --git a/repos/base/src/timer/pit/target.inc b/repos/base/src/timer/pit/target.inc index ae785572df..e8994291d9 100644 --- a/repos/base/src/timer/pit/target.inc +++ b/repos/base/src/timer/pit/target.inc @@ -1,9 +1,8 @@ -TARGET = pit_timer_drv +TARGET = pit_timer REQUIRES = x86 -GEN_DIR := $(dir $(call select_from_repositories,src/timer/main.cc)) -INC_DIR += $(GEN_DIR)/pit -SRC_CC += time_source.cc +SRC_CC += main.cc +LIBS += base -include $(GEN_DIR)/target.inc +REP_INC_DIR += src/include -vpath time_source.cc $(GEN_DIR)/pit +vpath main.cc $(dir $(call select_from_repositories,src/timer/pit/main.cc)) diff --git a/repos/base/src/timer/pit/time_source.cc b/repos/base/src/timer/pit/time_source.cc deleted file mode 100644 index 83b47bc72d..0000000000 --- a/repos/base/src/timer/pit/time_source.cc +++ /dev/null @@ -1,210 +0,0 @@ -/* - * \brief Time source that uses the Programmable Interval Timer (PIT) - * \author Norman Feske - * \author Martin Stein - * \date 2009-06-16 - */ - -/* - * Copyright (C) 2009-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -/* Genode includes */ -#include - -/* local includes */ -#include - -using namespace Genode; - - -void Timer::Time_source::_set_counter(uint16_t value) -{ - _handled_wrap = false; - _io_port.outb(PIT_DATA_PORT_0, (uint8_t)(value & 0xff)); - _io_port.outb(PIT_DATA_PORT_0, (uint8_t)((value >> 8) & 0xff)); -} - - -uint16_t Timer::Time_source::_read_counter(bool *wrapped) -{ - /* read-back count and status of counter 0 */ - _io_port.outb(PIT_CMD_PORT, PIT_CMD_READ_BACK | - PIT_CMD_RB_COUNT | - PIT_CMD_RB_STATUS | - PIT_CMD_RB_CHANNEL_0); - - /* read status byte from latch register */ - uint8_t status = _io_port.inb(PIT_DATA_PORT_0); - - /* read low and high bytes from latch register */ - uint16_t lo = _io_port.inb(PIT_DATA_PORT_0); - uint16_t hi = _io_port.inb(PIT_DATA_PORT_0); - - *wrapped = status & PIT_STAT_INT_LINE ? true : false; - return (uint16_t)((hi << 8) | lo); -} - - -void Timer::Time_source::set_timeout(Microseconds duration, - Timeout_handler &handler) -{ - _handler = &handler; - uint64_t duration_us = duration.value; - - /* timeout '0' is trigger to cancel the current pending, if required */ - if (!duration.value) { - duration_us = max_timeout().value; - Signal_transmitter(_signal_handler).submit(); - } else { - /* limit timer-interrupt rate */ - enum { MAX_TIMER_IRQS_PER_SECOND = 4*1000 }; - if (duration_us < (uint64_t)1000 * 1000 / MAX_TIMER_IRQS_PER_SECOND) - duration_us = (uint64_t)1000 * 1000 / MAX_TIMER_IRQS_PER_SECOND; - - if (duration_us > max_timeout().value) - duration_us = max_timeout().value; - } - - _counter_init_value = (uint16_t)((PIT_TICKS_PER_MSEC * duration_us) / 1000); - _set_counter(_counter_init_value); - - if (duration.value) - _timer_irq.ack_irq(); -} - - -uint32_t Timer::Time_source::_ticks_since_update_no_wrap(uint16_t curr_counter) -{ - /* - * The counter did not wrap since the last update of _counter_init_value. - * This means that _counter_init_value is equal to or greater than - * curr_counter and that the time that passed is simply the difference - * between the two. - */ - return _counter_init_value - curr_counter; -} - - -uint32_t Timer::Time_source::_ticks_since_update_one_wrap(uint16_t curr_counter) -{ - /* - * The counter wrapped since the last update of _counter_init_value. - * This means that the time that passed is the whole _counter_init_value - * plus the time that passed since the counter wrapped. - */ - return _counter_init_value + PIT_MAX_COUNT - curr_counter; -} - - -Duration Timer::Time_source::curr_time() -{ - /* read out and update curr time solely if running in context of irq */ - if (_irq) - _curr_time(); - - return Duration(Microseconds(_curr_time_us)); -} - - -Duration Timer::Time_source::_curr_time() -{ - /* read PIT counter and wrapped status */ - uint32_t ticks; - bool wrapped; - uint16_t const curr_counter = _read_counter(&wrapped); - - if (!wrapped) { - - /* - * The counter did not wrap since the last call to scheduled_timeout - * which means that it did not wrap since the last update of - * _counter_init_time. - */ - ticks = _ticks_since_update_no_wrap(curr_counter); - } - else if (wrapped && !_handled_wrap) { - - /* - * The counter wrapped at least once since the last call to - * schedule_timeout (wrapped) and curr_time (!_handled_wrap) which - * means that it definitely did wrap since the last update of - * _counter_init_time. We cannot determine whether it wrapped only - * once but we have to assume it. Even if it wrapped multiple times, - * the error that results from the assumption that it did not is pretty - * innocuous ((nr_of_wraps - 1) * 53 ms at a max). - */ - ticks = _ticks_since_update_one_wrap(curr_counter); - _handled_wrap = true; - } - else { /* wrapped && _handled_wrap */ - - /* - * The counter wrapped at least once since the last call to - * schedule_timeout (wrapped) but may not have wrapped since the last - * call to curr_time (_handled_wrap). - */ - - if (_counter_init_value >= curr_counter) { - - /* - * We cannot determine whether the counter wrapped since the last - * call to curr_time but we have to assume that it did not. Even if - * it wrapped, the error that results from the assumption that it - * did not is pretty innocuous as long as _counter_init_value is - * not greater than curr_counter (nr_of_wraps * 53 ms at a max). - */ - ticks = _ticks_since_update_no_wrap(curr_counter); - - } else { - - /* - * The counter definitely wrapped multiple times since the last - * call to schedule_timeout and at least once since the last call - * to curr_time. It is the only explanation for the fact that - * curr_counter became greater than _counter_init_value again - * after _counter_init_value was updated with a wrapped counter - * by curr_time (_handled_wrap). This means two things: - * - * First, the counter wrapped at least once since the last update - * of _counter_init_value. We cannot determine whether it wrapped - * only once but we have to assume it. Even if it wrapped multiple - * times, the error that results from the assumption that it - * did not is pretty innocuous ((nr_of_wraps - 1) * 53 ms at a max). - * - * Second, we have to warn the user as it is a sure indication of - * insufficient activation latency if the counter wraps multiple - * times between two schedule_timeout calls. - */ - warning("PIT wrapped multiple times, timer-driver latency too big"); - ticks = _ticks_since_update_one_wrap(curr_counter); - } - } - - /* use current counter as the reference for the next update */ - _counter_init_value = curr_counter; - - /* translate counter to microseconds and update time value */ - static_assert(PIT_TICKS_PER_MSEC >= (unsigned)TIMER_MIN_TICKS_PER_MS, - "Bad TICS_PER_MS value"); - _curr_time_us += timer_ticks_to_us(ticks, PIT_TICKS_PER_MSEC); - - return Duration(Microseconds(_curr_time_us)); -} - - -Timer::Time_source::Time_source(Env &env) -: - Signalled_time_source(env), - _io_port(env, PIT_DATA_PORT_0, PIT_CMD_PORT - PIT_DATA_PORT_0 + 1), - _timer_irq(env, IRQ_PIT) -{ - /* operate PIT in one-shot mode */ - _io_port.outb(PIT_CMD_PORT, PIT_CMD_SELECT_CHANNEL_0 | - PIT_CMD_ACCESS_LO_HI | PIT_CMD_MODE_IRQ); - - _timer_irq.sigh(_signal_handler); -} diff --git a/repos/base/src/timer/pit/time_source.h b/repos/base/src/timer/pit/time_source.h deleted file mode 100644 index 2e0646168a..0000000000 --- a/repos/base/src/timer/pit/time_source.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * \brief Time source that uses the Programmable Interval Timer (PIT) - * \author Norman Feske - * \author Martin Stein - * \date 2009-06-16 - */ - -/* - * Copyright (C) 2009-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _TIME_SOURCE_H_ -#define _TIME_SOURCE_H_ - -/* Genode includes */ -#include -#include -#include - -/* local includes */ -#include - -namespace Timer { - - using Genode::uint64_t; - using Microseconds = Genode::Microseconds; - using Duration = Genode::Duration; - class Time_source; -} - - -class Timer::Time_source : public Genode::Signalled_time_source -{ - private: - - - enum { - PIT_TICKS_PER_SECOND = 1193182, - PIT_TICKS_PER_MSEC = PIT_TICKS_PER_SECOND/1000, - PIT_MAX_COUNT = 65535, - PIT_DATA_PORT_0 = 0x40, /* data port for PIT channel 0, - connected to the PIC */ - PIT_CMD_PORT = 0x43, /* PIT command port */ - - PIT_MAX_USEC = (PIT_MAX_COUNT*1000)/(PIT_TICKS_PER_MSEC), - - IRQ_PIT = 0, /* timer interrupt at the PIC */ - - /* - * Bit definitions for accessing the PIT command port - */ - PIT_CMD_SELECT_CHANNEL_0 = 0 << 6, - PIT_CMD_ACCESS_LO = 1 << 4, - PIT_CMD_ACCESS_LO_HI = 3 << 4, - PIT_CMD_MODE_IRQ = 0 << 1, - PIT_CMD_MODE_RATE = 2 << 1, - - PIT_CMD_READ_BACK = 3 << 6, - PIT_CMD_RB_COUNT = 0 << 5, - PIT_CMD_RB_STATUS = 0 << 4, - PIT_CMD_RB_CHANNEL_0 = 1 << 1, - - /* - * Bit definitions of the PIT status byte - */ - PIT_STAT_INT_LINE = 1 << 7, - }; - - Genode::Io_port_connection _io_port; - Genode::Irq_connection _timer_irq; - uint64_t mutable _curr_time_us = 0; - Genode::uint16_t mutable _counter_init_value = 0; - bool mutable _handled_wrap = false; - - void _set_counter(Genode::uint16_t value); - - Genode::uint16_t _read_counter(bool *wrapped); - - Genode::uint32_t _ticks_since_update_one_wrap(Genode::uint16_t curr_counter); - - Genode::uint32_t _ticks_since_update_no_wrap(Genode::uint16_t curr_counter); - - Duration _curr_time(); - - public: - - Time_source(Genode::Env &env); - - - /************************* - ** Genode::Time_source ** - *************************/ - - Duration curr_time() override; - void set_timeout(Microseconds duration, Genode::Timeout_handler &handler) override; - Microseconds max_timeout() const override { - return Microseconds(PIT_MAX_USEC); } -}; - -#endif /* _TIME_SOURCE_H_ */ diff --git a/repos/base/src/timer/target.inc b/repos/base/src/timer/target.inc deleted file mode 100644 index 03559f797d..0000000000 --- a/repos/base/src/timer/target.inc +++ /dev/null @@ -1,5 +0,0 @@ -SRC_CC += main.cc -LIBS += base -INC_DIR += $(call select_from_repositories,src/timer/include) - -vpath main.cc $(dir $(call select_from_repositories,src/timer/main.cc)) diff --git a/repos/dde_bsd/README b/repos/dde_bsd/README index 9f30b6d92c..80a1932b08 100644 --- a/repos/dde_bsd/README +++ b/repos/dde_bsd/README @@ -3,7 +3,7 @@ This repository contains device drivers ported from OpenBSD. Audio ##### -The audio driver is ported from OpenBSD 6.6 and includes support for +The audio driver is ported from OpenBSD 7.3 and includes support for Intel HD Audio devices. The HDA driver works on real hardware and supposedly in VirtualBox. @@ -47,7 +47,7 @@ or recording because it may provoke the generation of artefacts. The following configures the driver of playback and recording: -! +! ! ! ! diff --git a/repos/dde_bsd/patches/audio_bufsz.patch b/repos/dde_bsd/patches/audio_bufsz.patch new file mode 100644 index 0000000000..7d491ec2e9 --- /dev/null +++ b/repos/dde_bsd/patches/audio_bufsz.patch @@ -0,0 +1,13 @@ +Decrease the initial audio buffer size that implicitly limits the number +of records blocks. +--- a/dev/audio.c ++++ b/dev/audio.c +@@ -55,7 +55,7 @@ + #define AUDIO_DEV(n) (minor(n) & 0xf0) + #define AUDIO_DEV_AUDIO 0 /* minor of /dev/audio0 */ + #define AUDIO_DEV_AUDIOCTL 0xc0 /* minor of /dev/audioctl */ +-#define AUDIO_BUFSZ 65536 /* buffer size in bytes */ ++#define AUDIO_BUFSZ 4096 /* buffer size in bytes */ + + /* + * mixer entries added by the audio(4) layer diff --git a/repos/dde_bsd/ports/dde_bsd.hash b/repos/dde_bsd/ports/dde_bsd.hash index 025ba4ecf6..460d603aaa 100644 --- a/repos/dde_bsd/ports/dde_bsd.hash +++ b/repos/dde_bsd/ports/dde_bsd.hash @@ -1 +1 @@ -771f320f0d4e11510d8f565fda456400b4793230 +b6086e021be26a2f2a07463c0318b79fd8d0513e diff --git a/repos/dde_bsd/ports/dde_bsd.port b/repos/dde_bsd/ports/dde_bsd.port index b4dfb5b6d9..4e45a44e98 100644 --- a/repos/dde_bsd/ports/dde_bsd.port +++ b/repos/dde_bsd/ports/dde_bsd.port @@ -1,15 +1,15 @@ LICENSE := BSD -VERSION := 1 +VERSION := individual (see sources) DOWNLOADS := audio.archive # -# Audio drivers from OpenBSD 7.1 +# Audio drivers from OpenBSD 7.3 # SRC_DIR_AUDIO := src/lib/audio -VERSION_AUDIO := 7.1 +VERSION(audio) := 7.3 BASE_URL := https://cdn.openbsd.org/pub/OpenBSD -URL(audio) := $(BASE_URL)/$(VERSION_AUDIO)/sys.tar.gz -SHA(audio) := 890cb97c01052f26cefe5430d635e0fdf6047ca701a99992968e16801e2a6565 +URL(audio) := $(BASE_URL)/${VERSION(audio)}/sys.tar.gz +SHA(audio) := bb0dfa11584d68464b3f788e43655f6454bb3ecba8ad5500377630bcf23570ec DIR(audio) := $(SRC_DIR_AUDIO) TAR_OPT(audio) := --strip-components=1 --files-from $(REP_DIR)/audio.list HASH_INPUT += $(REP_DIR)/audio.list diff --git a/repos/dde_bsd/recipes/pkg/bsd_audio_drv/README b/repos/dde_bsd/recipes/pkg/bsd_audio/README similarity index 100% rename from repos/dde_bsd/recipes/pkg/bsd_audio_drv/README rename to repos/dde_bsd/recipes/pkg/bsd_audio/README diff --git a/repos/dde_bsd/recipes/pkg/bsd_audio/archives b/repos/dde_bsd/recipes/pkg/bsd_audio/archives new file mode 100644 index 0000000000..e552b3f4ab --- /dev/null +++ b/repos/dde_bsd/recipes/pkg/bsd_audio/archives @@ -0,0 +1 @@ +_/src/bsd_audio diff --git a/repos/dde_bsd/recipes/pkg/bsd_audio/hash b/repos/dde_bsd/recipes/pkg/bsd_audio/hash new file mode 100644 index 0000000000..b8ccf5f15a --- /dev/null +++ b/repos/dde_bsd/recipes/pkg/bsd_audio/hash @@ -0,0 +1 @@ +2024-08-28 d9b3b6700616965b61c9cf673d1d2924d795437b diff --git a/repos/dde_bsd/recipes/pkg/bsd_audio/runtime b/repos/dde_bsd/recipes/pkg/bsd_audio/runtime new file mode 100644 index 0000000000..99cfae20b7 --- /dev/null +++ b/repos/dde_bsd/recipes/pkg/bsd_audio/runtime @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/repos/dde_bsd/recipes/pkg/bsd_audio_drv/archives b/repos/dde_bsd/recipes/pkg/bsd_audio_drv/archives deleted file mode 100644 index ef624c667a..0000000000 --- a/repos/dde_bsd/recipes/pkg/bsd_audio_drv/archives +++ /dev/null @@ -1 +0,0 @@ -_/src/bsd_audio_drv diff --git a/repos/dde_bsd/recipes/pkg/bsd_audio_drv/hash b/repos/dde_bsd/recipes/pkg/bsd_audio_drv/hash deleted file mode 100644 index d0a0da2612..0000000000 --- a/repos/dde_bsd/recipes/pkg/bsd_audio_drv/hash +++ /dev/null @@ -1 +0,0 @@ -2022-10-11 c9953284ebe0570c926982c35f37647a3132549d diff --git a/repos/dde_bsd/recipes/pkg/bsd_audio_drv/runtime b/repos/dde_bsd/recipes/pkg/bsd_audio_drv/runtime deleted file mode 100644 index fbdd563946..0000000000 --- a/repos/dde_bsd/recipes/pkg/bsd_audio_drv/runtime +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/repos/dde_bsd/recipes/src/bsd_audio/content.mk b/repos/dde_bsd/recipes/src/bsd_audio/content.mk new file mode 100644 index 0000000000..ae9f6cf89c --- /dev/null +++ b/repos/dde_bsd/recipes/src/bsd_audio/content.mk @@ -0,0 +1,39 @@ +PORT_DIR := $(call port_dir,$(REP_DIR)/ports/dde_bsd) + +MK_FILES := dde_bsd_audio.inc dde_bsd_audio_include.mk dde_bsd_audio_pci.inc + +LIB_MK := $(addprefix lib/mk/, $(MK_FILES)) \ + $(foreach SPEC,x86_32 x86_64,lib/mk/spec/$(SPEC)/dde_bsd_audio.mk) \ + lib/import/import-dde_bsd_audio_include.mk + +MIRROR_FROM_REP_DIR := $(LIB_MK) src/lib src/driver patches include + +MIRROR_FROM_PORT_DIR := $(addprefix src/lib/audio/, \ + dev/pci/azalia_codec.c \ + dev/pci/pcidevs.h \ + dev/pci/pcidevs_data.h \ + dev/pci/azalia.h \ + dev/pci/azalia.c \ + dev/mulaw.h \ + dev/audio_if.h \ + dev/mulaw.c \ + dev/audio.c \ + lib/libkern \ + sys/device.h \ + sys/audioio.h \ + sys/queue.h) + +content: $(MIRROR_FROM_REP_DIR) $(MIRROR_FROM_PORT_DIR) LICENSE + +$(MIRROR_FROM_REP_DIR): + $(mirror_from_rep_dir) + +$(MIRROR_FROM_PORT_DIR): + mkdir -p $(dir $@) + cp -r $(PORT_DIR)/$@ $@ + +LICENSE: + ( echo 'OpenBSD code is most likely licensed under a ISC like license but for'; \ + echo 'historical reasons different variations of the Berkeley Copyright are'; \ + echo 'also in use. Please check the copyright header in the contrib source'; \ + echo 'files in src/lib/audio/dev and src/lib/audio/sys.') > $@ diff --git a/repos/dde_bsd/recipes/src/bsd_audio/hash b/repos/dde_bsd/recipes/src/bsd_audio/hash new file mode 100644 index 0000000000..c6969cf50a --- /dev/null +++ b/repos/dde_bsd/recipes/src/bsd_audio/hash @@ -0,0 +1 @@ +2024-08-28 efd2b77afecdc8673da69eaa69f4e8baf3d03950 diff --git a/repos/dde_bsd/recipes/src/bsd_audio/used_apis b/repos/dde_bsd/recipes/src/bsd_audio/used_apis new file mode 100644 index 0000000000..8d1a0fe5d2 --- /dev/null +++ b/repos/dde_bsd/recipes/src/bsd_audio/used_apis @@ -0,0 +1,10 @@ +base +os +format +audio_in_session +audio_out_session +platform_session +play_session +record_session +report_session +timer_session diff --git a/repos/dde_bsd/recipes/src/bsd_audio_drv/content.mk b/repos/dde_bsd/recipes/src/bsd_audio_drv/content.mk deleted file mode 100644 index 01764c9ed0..0000000000 --- a/repos/dde_bsd/recipes/src/bsd_audio_drv/content.mk +++ /dev/null @@ -1,39 +0,0 @@ -PORT_DIR := $(call port_dir,$(REP_DIR)/ports/dde_bsd) - -MK_FILES := dde_bsd_audio.inc dde_bsd_audio_include.mk dde_bsd_audio_pci.inc - -LIB_MK := $(addprefix lib/mk/, $(MK_FILES)) \ - $(foreach SPEC,x86_32 x86_64,lib/mk/spec/$(SPEC)/dde_bsd_audio.mk) \ - lib/import/import-dde_bsd_audio_include.mk - -MIRROR_FROM_REP_DIR := $(LIB_MK) src/lib src/drivers patches include - -MIRROR_FROM_PORT_DIR := $(addprefix src/lib/audio/, \ - dev/pci/azalia_codec.c \ - dev/pci/pcidevs.h \ - dev/pci/pcidevs_data.h \ - dev/pci/azalia.h \ - dev/pci/azalia.c \ - dev/mulaw.h \ - dev/audio_if.h \ - dev/mulaw.c \ - dev/audio.c \ - lib/libkern \ - sys/device.h \ - sys/audioio.h \ - sys/queue.h) - -content: $(MIRROR_FROM_REP_DIR) $(MIRROR_FROM_PORT_DIR) LICENSE - -$(MIRROR_FROM_REP_DIR): - $(mirror_from_rep_dir) - -$(MIRROR_FROM_PORT_DIR): - mkdir -p $(dir $@) - cp -r $(PORT_DIR)/$@ $@ - -LICENSE: - ( echo 'OpenBSD code is most likely licensed under a ISC like license but for'; \ - echo 'historical reasons different variations of the Berkeley Copyright are'; \ - echo 'also in use. Please check the copyright header in the contrib source'; \ - echo 'files in src/lib/audio/dev and src/lib/audio/sys.') > $@ diff --git a/repos/dde_bsd/recipes/src/bsd_audio_drv/hash b/repos/dde_bsd/recipes/src/bsd_audio_drv/hash deleted file mode 100644 index 7893b4e706..0000000000 --- a/repos/dde_bsd/recipes/src/bsd_audio_drv/hash +++ /dev/null @@ -1 +0,0 @@ -2022-10-11 eeb4565fb902ca980c98c6225c5c8141c8744011 diff --git a/repos/dde_bsd/recipes/src/bsd_audio_drv/used_apis b/repos/dde_bsd/recipes/src/bsd_audio_drv/used_apis deleted file mode 100644 index c6939f5a67..0000000000 --- a/repos/dde_bsd/recipes/src/bsd_audio_drv/used_apis +++ /dev/null @@ -1,7 +0,0 @@ -base -os -audio_in_session -audio_out_session -platform_session -report_session -timer_session diff --git a/repos/dde_bsd/run/audio_in.run b/repos/dde_bsd/run/audio_in.run index 681ee398a2..a7c34f392f 100644 --- a/repos/dde_bsd/run/audio_in.run +++ b/repos/dde_bsd/run/audio_in.run @@ -10,30 +10,71 @@ if {[have_spec linux]} { exit 0 } +# select use of 'Audio_in/Audio_out' or 'Record/Play' sessions +proc use_record_play_sessions { } { return 1 } -# -# Build -# +proc build_targets { } { -set build_components { - core init timer - drivers/acpi - drivers/platform - app/pci_decode - server/report_rom - drivers/audio - test/audio_in + set targets { + core init timer + driver/acpi driver/platform app/pci_decode server/report_rom + driver/audio + } + + if {[use_record_play_sessions]} { + lappend targets server/record_play_mixer + } else { + lappend targets test/audio_in + } } -build $build_components +build [build_targets] create_boot_directory -# -# Config -# +proc audio_driver_config_attr { } { -append config { + if {[use_record_play_sessions]} { + return {report_mixer="yes" record_play="yes"} + } else { + return {report_mixer="yes"} + } +} + +proc record_play_start_nodes { } { + + if {![use_record_play_sessions]} { return "" } + + return { + + + + + + + + + + + + + + + } +} + +proc audio_in_out_start_nodes { } { + + if {[use_record_play_sessions]} { return "" } + + return { + + + + } +} + +install_config { @@ -58,39 +99,29 @@ append config { - - + + - + - - - - - - + - + - - - - - - + - + @@ -98,51 +129,33 @@ append config { - - - - - - - + - + - - - + + + - + - - - + + } [record_play_start_nodes] { + } [audio_in_out_start_nodes] { + } -install_config $config - - -# -# Boot modules -# - -set boot_modules { - core ld.lib.so init timer - platform_drv acpi_drv pci_decode report_rom - pci_audio_drv test-audio_in -} - -build_boot_image $boot_modules +build_boot_image [build_artifacts] run_genode_until forever diff --git a/repos/dde_bsd/run/audio_out.run b/repos/dde_bsd/run/audio_out.run index 86bd1dc7ce..50bbb6539d 100644 --- a/repos/dde_bsd/run/audio_out.run +++ b/repos/dde_bsd/run/audio_out.run @@ -10,16 +10,87 @@ if {[have_spec linux]} { exit 0 } +# select use of 'Audio_in/Audio_out' or 'Record/Play' sessions +proc use_record_play_sessions { } { return 1 } create_boot_directory -build { - core init timer - drivers/acpi - drivers/platform - app/pci_decode - server/report_rom - drivers/audio - test/audio_out + +proc build_targets { } { + + set targets { + core init timer + driver/acpi driver/platform app/pci_decode server/report_rom + driver/audio + } + + if {[use_record_play_sessions]} { + lappend targets server/record_play_mixer app/waveform_player \ + test/audio_play lib/vfs + } else { + lappend targets test/audio_out + } +} + +build [build_targets] + +proc audio_driver_config_attr { } { + + if {[use_record_play_sessions]} { + return {report_mixer="yes" record_play="yes"} + } else { + return {report_mixer="yes"} + } +} + +proc record_play_start_nodes { } { + + if {![use_record_play_sessions]} { + return "" } + + return { + + + + + + + + + + + + + + + + + + + + + + + + + } +} + +proc audio_in_out_start_nodes { } { + + if {[use_record_play_sessions]} { + return "" } + + return { + + + + sample.f32 + + + + + + } } install_config { @@ -45,40 +116,30 @@ install_config { - - - + + + - + - - - - - - + - + - - - - - - + - + @@ -86,59 +147,38 @@ install_config { - - - - - - - + - + - - - - - + + + + + - - - - sample.raw - - - - - + } [record_play_start_nodes] { + } [audio_in_out_start_nodes] { + } # # Get sample file # -if {![file exists bin/sample.raw]} { +if {![file exists bin/sample.f32]} { puts "" puts "The sample file is missing. Please take a look at" - puts "repos/dde_bsd/README, create 'sample.raw' and put" + puts "repos/dde_bsd/README, create 'sample.f32' and put" puts "the file into './bin'. afterwards" puts "" exit 1 } -build_boot_image { - core ld.lib.so init timer - platform_drv acpi_drv pci_decode report_rom - pci_audio_drv test-audio_out sample.raw -} +build_boot_image [list {*}[build_artifacts] sample.f32] - -# -# For obvious reasons the timeout depends on the total -# length of the used sample file. -# -run_genode_until {.*played.*1 time\(s\)} 60 +run_genode_until forever diff --git a/repos/dde_bsd/src/driver/audio/main.cc b/repos/dde_bsd/src/driver/audio/main.cc new file mode 100644 index 0000000000..d7aab2cb2c --- /dev/null +++ b/repos/dde_bsd/src/driver/audio/main.cc @@ -0,0 +1,677 @@ +/* + * \brief Startup audio driver library + * \author Josef Soentgen + * \date 2014-11-09 + */ + +/* + * Copyright (C) 2014-2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + + +/* Genode includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* local includes */ +#include