mirror of
https://github.com/mmueller41/genode.git
synced 2026-01-22 04:52:56 +01:00
Compare commits
81 Commits
sculpt-21.
...
21.11
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4188427596 | ||
|
|
ea6f90ec17 | ||
|
|
c528cd7819 | ||
|
|
92b7be4d11 | ||
|
|
13dab699b1 | ||
|
|
7eb3da71b5 | ||
|
|
14de84fae6 | ||
|
|
916683b6d6 | ||
|
|
e256969489 | ||
|
|
7a2826a2fe | ||
|
|
45cebd774d | ||
|
|
1f58b05255 | ||
|
|
30b3ad218f | ||
|
|
7c1888644a | ||
|
|
2ec9e69fd4 | ||
|
|
0bb0ac079a | ||
|
|
fcc236d906 | ||
|
|
17da7c88d0 | ||
|
|
4d93187d31 | ||
|
|
645e51dc1d | ||
|
|
8155505b41 | ||
|
|
d39af2206c | ||
|
|
133d21ad38 | ||
|
|
09d020508c | ||
|
|
dc39a8db62 | ||
|
|
9591e6caee | ||
|
|
a65807ff08 | ||
|
|
059c7ed74a | ||
|
|
98385a7658 | ||
|
|
49bf58a2ae | ||
|
|
327ec61ee3 | ||
|
|
cd7a65a313 | ||
|
|
23514bf5c2 | ||
|
|
974627f700 | ||
|
|
3b456e0037 | ||
|
|
231ac187fe | ||
|
|
959bcae557 | ||
|
|
694dff8a5c | ||
|
|
68caa26407 | ||
|
|
4cfd954e1e | ||
|
|
293d545b97 | ||
|
|
4df7e6adde | ||
|
|
449f647e58 | ||
|
|
f2a627c107 | ||
|
|
2ecb09ba7e | ||
|
|
522a1cdc5b | ||
|
|
c0c2ed2bf5 | ||
|
|
c774272366 | ||
|
|
533015b93e | ||
|
|
f4e52863c0 | ||
|
|
7a06633173 | ||
|
|
1a79bf2be2 | ||
|
|
3701733c8f | ||
|
|
5a21431c31 | ||
|
|
00eadf9791 | ||
|
|
33bf926b50 | ||
|
|
4798ffd055 | ||
|
|
228d1c27b7 | ||
|
|
68878ca98a | ||
|
|
28db5cadee | ||
|
|
8d5903cba9 | ||
|
|
74a8a801e4 | ||
|
|
b12b0ed93d | ||
|
|
7917c5d9ec | ||
|
|
6ecae6adb3 | ||
|
|
6d991313b1 | ||
|
|
43ef9b5a3a | ||
|
|
87bb81cd66 | ||
|
|
332cfb38c1 | ||
|
|
275479867d | ||
|
|
4f1e9fd256 | ||
|
|
80d11ca751 | ||
|
|
60f1a1a554 | ||
|
|
851d96de8a | ||
|
|
ecb1a6187c | ||
|
|
d4a6342295 | ||
|
|
a10903a197 | ||
|
|
c38c2a6455 | ||
|
|
e748efacd8 | ||
|
|
42ff902576 | ||
|
|
7e2716800b |
89
doc/news.txt
89
doc/news.txt
@@ -4,6 +4,95 @@
|
||||
===========
|
||||
|
||||
|
||||
Genode OS Framework release 21.11 | 2021-11-30
|
||||
##############################################
|
||||
|
||||
| Genode 21.11 puts the spotlight on device drivers. Interactive Genode
|
||||
| scenarios come to the Pinephone, hardware-accelerated graphics becomes
|
||||
| available on Intel Gen9+ and Vivante GPUs, and Xilnx Zynq receives
|
||||
| new love.
|
||||
|
||||
The previous release presented our new take on porting drivers from Linux, and
|
||||
the architectural integration of hardware-accelerated graphics in Genode-based
|
||||
systems. The just released version 21.11 is the continuation of both topics.
|
||||
Thanks to our streamlined approach for transplanting Linux drivers to Genode, we
|
||||
were able to reuse the Pinephone's Linux drivers for the display and
|
||||
touchscreen without modification. But, in contrast to running those drivers in
|
||||
the Linux kernel, we are walking on new ground by confining each driver in a
|
||||
separate sandbox.
|
||||
|
||||
With our GPU line of work, we followed two major directions during the release
|
||||
cycle. For one, we applied our architectural approach to a second GPU vendor
|
||||
besides Intel, namely the Vivante GPU as used by the i.MX SoC family.
|
||||
Combined with the etnaviv Gallium driver of the Mesa library, Genode thereby
|
||||
becomes able to render graphics with hardware acceleration on the MNT Reform
|
||||
open-hardware laptop. The second branch is the promised extension of our
|
||||
custom Intel GPU multiplexer to GPUs of generation 9 or newer. Thereby, GPU
|
||||
support has now become a regular feature of the Genode-based Sculpt OS that
|
||||
can be taken for a spin on commodity PC hardware.
|
||||
|
||||
Regarding 32-bit ARM platforms, the current release revives our engagement
|
||||
with Xilinx Zynq devices, which combine FPGA fabric with a 32-bit ARM CPU.
|
||||
In particular, the release brings the framework to the USRP E310 board,
|
||||
opening new hardware-software co-design opportunities.
|
||||
|
||||
Besides the many hardware-related topics outlined above, two functional
|
||||
improvements stand out. First, the Genode version of VirtualBox 6 has reached
|
||||
feature parity with version 5. Both versions can now be used interchangeably
|
||||
on Sculpt OS. Finally, libSDL2 got upgraded with support for audio and OpenGL,
|
||||
which is a nice pathway for hosting games on Genode.
|
||||
|
||||
The new version is described in full detail by the
|
||||
[https:/documentation/release-notes/21.11 - release documentation of version 21.11...]
|
||||
|
||||
|
||||
Sculpt OS release 21.10 | 2021-10-14
|
||||
####################################
|
||||
|
||||
| Sculpt OS version 21.10 introduces GPU-accelerated graphics on Intel,
|
||||
| media playback in the web browser, VirtualBox 6, and USB webcam support.
|
||||
|
||||
At the first glance, the just released Sculpt 21.10 looks and feels nearly
|
||||
identical to the time-tested previous version 21.03. However, a look at the
|
||||
installable packages reveals a firework of exciting new features.
|
||||
|
||||
First and technically most exciting, the new version enables the use of
|
||||
hardware-accelerated graphics on Intel GPUs, paving the ground for
|
||||
graphics-intensive applications and games. The GPU support is based on the
|
||||
combination of the Mesa library stack with our custom GPU multiplexer
|
||||
as featured in
|
||||
[https://genode.org/documentation/release-notes/21.08#Advancing_GPU_driver_stack - Genode 21.08].
|
||||
_Note that this fresh new feature should best be regarded as experimental_
|
||||
_and be used with caution._
|
||||
|
||||
Second, our port of the Chromium-based Falkon web browser has become able to
|
||||
present media content like videos and sound. Look out for the browser in the
|
||||
tools menu of cproc's depot. It is accompanied with a ready-to-use audio
|
||||
driver and a mixer component. In cases where audio output is not desired, the
|
||||
browser - or any other component that requests audio output - can be connected
|
||||
to a new component called black hole, which merely mimics an audio driver
|
||||
without any audible effect.
|
||||
|
||||
Third, with the addition of the new file-vault component, Sculpt now provides
|
||||
an easy way to setup and use an encrypted file store using our custom CBE
|
||||
block encrypter as underlying crypto container. The file vault is especially
|
||||
useful in combination with the recall-fs component that provides each client
|
||||
with a distinct storage compartment.
|
||||
|
||||
Finally, the support for USB webcams as introduced with
|
||||
[https://genode.org/documentation/release-notes/21.05#Webcam_support - Genode 21.05]
|
||||
has entered Sculpt OS in the form of a new webcam package. The webcam support
|
||||
can best be combined with our new port of VirtualBox 6 that is available in
|
||||
addition to VirtualBox version 5. With Sculpt 21.10, both VirtualBox versions
|
||||
can be used in parallel.
|
||||
|
||||
Sculpt OS 21.10 is available as ready-to-use system image at the
|
||||
[https://genode.org/download/sculpt - Sculpt download page] and is accompanied
|
||||
with updated [https://genode.org/documentation/articles/sculpt-21-10 - documentation].
|
||||
More details about individual new features of Sculpt 21.10 will be covered
|
||||
soon by dedicated articles at [https://genodians.org].
|
||||
|
||||
|
||||
Genode OS Framework release 21.08 | 2021-08-31
|
||||
##############################################
|
||||
|
||||
|
||||
@@ -289,9 +289,9 @@ Examining the log file leaves us with the following list of source files:
|
||||
! FILTER_OUT_dos = cdrom_aspi_win32.cpp cdrom_ioctl_linux.cpp cdrom_ioctl_os2.cpp \
|
||||
! cdrom_ioctl_win32.cpp
|
||||
! SRC_CC_dos = $(filter-out $(FILTER_OUT_dos), \
|
||||
! $(notdir $(wildcard $(DOSBOX_DIR)/src/*.cpp)))
|
||||
! $(notdir $(wildcard $(DOSBOX_DIR)/src/dos/*.cpp)))
|
||||
! […]
|
||||
! SRC_CC = $(DOSBOX_DIR)/src/dosbox.cpp
|
||||
! SRC_CC = $(notdir $(DOSBOX_DIR)/src/dosbox.cpp)
|
||||
! SRC_CC += $(SRC_CC_cpu) $(SRC_CC_debug) $(SRC_CC_dos) $(SRC_CC_fpu) \
|
||||
! $(SRC_CC_gui) $(SRC_CC_hw) $(SRC_CC_hw_ser) $(SRC_CC_ints) \
|
||||
! $(SRC_CC_ints) $(SRC_CC_misc) $(SRC_CC_shell)
|
||||
|
||||
835
doc/release_notes/21-11.txt
Normal file
835
doc/release_notes/21-11.txt
Normal file
@@ -0,0 +1,835 @@
|
||||
|
||||
|
||||
===============================================
|
||||
Release notes for the Genode OS Framework 21.11
|
||||
===============================================
|
||||
|
||||
Genode Labs
|
||||
|
||||
|
||||
|
||||
Version 21.11 of the Genode OS Framework puts device drivers into the
|
||||
spotlight. Where to begin? Back in
|
||||
[https://genode.org/news/road-map-for-2021 - January], we envisioned Genode
|
||||
running on the Pinephone. With the current release, the first interactive
|
||||
Genode scenarios become alive on this platform. Unlike the regular Linux-based
|
||||
systems used on the Pinephone, we are walking on new ground by running each
|
||||
individual driver in a dedicated sandbox.
|
||||
|
||||
Speaking of 64-bit ARM platforms, Genode's support for the i.MX8 SoC family
|
||||
received a new USB host driver as well as the first version of the Vivante GPU
|
||||
driver. The latter is a continuation of our GPU-related work presented in the
|
||||
[https://genode.org/documentation/release-notes/21.08#Advancing_GPU_driver_stack - previous release],
|
||||
which proves that our approach of integrating hardware-accelerated graphics
|
||||
into the framework's architecture is applicable across different GPU vendors.
|
||||
As promised three months ago, we have also taken our custom Intel GPU
|
||||
multiplexer to Gen9 or newer devices. In fact, GPU support has now become a
|
||||
regular feature of the Genode-based Sculpt OS that can be taken for a spin on
|
||||
commodity PC hardware.
|
||||
|
||||
Even though most efforts are nowadays spent on 64-bit platforms, we have
|
||||
revived Genode's support for Xilinx Zynq devices in aspiration of future
|
||||
hardware-software co-design work. Those chips combine FPGA fabric with 32-bit
|
||||
ARM cores and thereby allow us to explore the combination of reconfigurable
|
||||
hardware with Genode's component architecture.
|
||||
|
||||
For users who prefer the comforts of virtual hardware over the tinkering with
|
||||
physical devices, new drivers for VirtIO input and graphics open up the use of
|
||||
interactive Genode systems on Qemu's "virt" platform.
|
||||
|
||||
Besides the predominant device-driver topics of the release, one other
|
||||
highlight is the feature completion of Genode's version of VirtualBox 6 on PC
|
||||
platforms, which has now reached parity with the time-tested version 5. Now,
|
||||
features like shared folders, shared clipboard, sound, or USB pass-through
|
||||
have become readily available.
|
||||
|
||||
|
||||
A little kingdom for each SoC family
|
||||
####################################
|
||||
|
||||
With the number of supported boards and CPU architectures growing, our
|
||||
existing maintenance structure of the central Genode code repository becomes
|
||||
increasingly nonviable. We made the following observations.
|
||||
|
||||
First, with respect to drivers ported from Linux, each SoC tends to refer
|
||||
to a different _flavour_ of the Linux kernel. This so-called vendor kernel
|
||||
may be a specific version with a blessed kernel configuration, or even a
|
||||
hard fork. In the past, we tried harmonizing drivers across SoCs by using
|
||||
the vanilla Linux kernel as common ground. But in practice, this common
|
||||
ground seems to be walked-on by only a few. Devices are shipped with vendor
|
||||
kernels after all. To get the best supported drivers for a given hardware,
|
||||
we have to port the drivers from the respective vendor kernel.
|
||||
This realization, in turn, faces us with the problem of a growing number
|
||||
of vendor kernels we have to work with whenever extending Genode's hardware
|
||||
support to a new SoC. But there are only so many Linux kernels one can juggle
|
||||
with.
|
||||
|
||||
Second, when using one monolithic code base for all SoCs, the coordination of
|
||||
the code repository becomes a bottleneck when it comes to reviewing and
|
||||
merging contributions, and the nurturing of a consistent level of quality
|
||||
assurance. In the case of Genode, this responsibility is shared by two head
|
||||
maintainers. However, their expertise lies in the Genode framework, not in the
|
||||
peculiarities of specific SoC hardware. Hence, the review of such SoC-related
|
||||
contributions must remain at surface level. But the burden of responsibility
|
||||
still rests on the two.
|
||||
|
||||
Third, we ultimately want to encourage 3rd parties - like hardware vendors -
|
||||
to supplement SoC support for Genode independently from us. Forcing such
|
||||
independent developers to funnel their results into our code base is not
|
||||
always natural and may even be legally impeded by Genode's need for a
|
||||
[https://genode.org/community/contributions#Genode_Contributors_Agreement - contributor's agreement].
|
||||
We want to avoid such artificial friction.
|
||||
|
||||
The consequence of these observations is the need to modularize our code base
|
||||
around the idea of giving each SoC family a little kingdom of their own. We
|
||||
envision a code repository with a different maintainer for each SoC family. As
|
||||
a prerequisite, we had to cleanly separate SoC-specific code from the generic
|
||||
code that will remain in the main Genode repository. To stress this approach,
|
||||
each of four developers picked a dedicated SoC family and went with it. Stefan
|
||||
Kalkowski took the i.MX-related code to his
|
||||
[https://github.com/skalk/genode-imx - genode-imx] repository,
|
||||
Johannes Schlatow took the Xilinx Zynq code to his
|
||||
[https://github.com/jschlatow/genode-zynq - genode-zynq] repository,
|
||||
Norman Feske
|
||||
maintains the Allwinner code for the Pinephone in
|
||||
his [https://github.com/nfeske/genode-allwinner - genode-allwinner]
|
||||
repository, and Sebastian Sumpf gave the RISC-V support a new home
|
||||
at his [https://github.com/ssumpf/genode-riscv - genode-riscv] repository.
|
||||
|
||||
By looking at this modularization from four different perspectives at the same
|
||||
time, we reached satisfying interfaces between the generic and SoC-specific
|
||||
code. We found that this maintenance model works as anticipated. In
|
||||
particular, we hoped that each SoC can be shepherded by a single person
|
||||
without stress. This turned out to be true.
|
||||
|
||||
We also found that the taken approach gives each maintainer a sense of
|
||||
autonomy that was not possible with one monolithic code base. This is
|
||||
particularly fruitful when drafting generic utilities for the eventual
|
||||
inclusion into Genode's main repository. The drafts can first receive a test
|
||||
of time at individual SoC repositories before integrating them into the common
|
||||
code base, the pin I/O interfaces described in
|
||||
Section [Pin I/O session interfaces] being a good example.
|
||||
|
||||
The supportive tooling for each SoC tends to differ between vendors, speaking
|
||||
of custom system-image formats, boot loaders, or firmware. The SoC-specific
|
||||
repositories provide a natural home for hosting such tools, custom work-flow
|
||||
scripts, and configurations.
|
||||
|
||||
With this exploratory phase completed, we plan to move the SoC-specific
|
||||
repositories - that currently reside at each maintainer's GitHub account -
|
||||
under the banner of [https://github.com/genodelabs - genodelabs] during the
|
||||
next release cycle.
|
||||
|
||||
|
||||
NXP i.MX family
|
||||
===============
|
||||
|
||||
Support for the family of i.MX SoC related boards is located in the
|
||||
[https://github.com/skalk/genode-imx - genode-imx] repository.
|
||||
By now, it contains far-reaching support for the i.MX 8M Quad evaluation kit,
|
||||
and the MNT Reform2.
|
||||
|
||||
Besides the basic kernel support for Genode's custom base-hw microkernel,
|
||||
it contains drivers for using SD and eMMC cards, HDMI, and MIPI-DSI connected
|
||||
displays, Ethernet, and USB connected devices. Moreover, we are proud to
|
||||
introduce support for the Vivante GPU used by the i.MX 8M SoC. All mentioned
|
||||
device drivers were ported using the
|
||||
[https://genode.org/documentation/release-notes/21.08#Linux-device-driver_environment_re-imagined - re-imagined approach to port Linux drivers]
|
||||
that was introduced in the previous release.
|
||||
|
||||
To obtain a ready-to-use SD-card when testing an arbitrary run-script
|
||||
scenario, it is sufficient to add the following value to the 'RUN_OPT'
|
||||
variable:
|
||||
|
||||
! RUN_OPT += --include image/imx8mq_mmc
|
||||
|
||||
Depending on which board you've chosen, it will build the corresponding u-boot
|
||||
bootloader, file system, Genode system image, and integrate those parts into
|
||||
one SD-card image.
|
||||
|
||||
|
||||
Xilinx Zynq
|
||||
===========
|
||||
|
||||
Basic platform support for the Zynq-7000 SoC has already been added to Genode
|
||||
with
|
||||
[https://genode.org/documentation/release-notes/15.11#Xilinx_Zynq-7000 - release 15.11].
|
||||
While the virtualized zynq_qemu board support resided in the main Genode
|
||||
repository and was regularly tested, support files for real Zynq-hardware were
|
||||
living in segregation within the Genode-world repository.
|
||||
|
||||
By creating a new realm in form of a
|
||||
[https://github.com/jschlatow/genode-zynq - genode-zynq repository], we were
|
||||
able to consolidate the Zynq-specific board support and drivers in one place.
|
||||
Furthermore, we are currently intensifying our work on this platform and
|
||||
documenting the journey on
|
||||
[https://genodians.org/jschlatow/2021-11-29-zynq-guide-1 - genodians.org].
|
||||
This particularly includes building ready-to-use SD card images with u-boot
|
||||
and supporting run-time re-configuration of the FPGA.
|
||||
|
||||
In order to use the zynq repository, you only need to create a clone at
|
||||
_repos/zynq_, create a new build directory for arm_v7a and uncomment the
|
||||
corresponding line in your etc/build.conf. Step-by-step instructions for
|
||||
individual boards can be found at _repos/zynq/doc/_.
|
||||
|
||||
|
||||
Allwinner A64 (Pinephone)
|
||||
=========================
|
||||
|
||||
During the release cycle, Genode's support for the Allwinner A64 SoC, and
|
||||
the Pinephone in particular, made big leaps forward. The corresponding code
|
||||
is hosted in the dedicated
|
||||
[https://github.com/nfeske/genode-allwinner - genode-allwinner] repository.
|
||||
|
||||
First, the Linux version taken as the basis for ported device drivers has been
|
||||
updated to 5.14.1 in order to support the revision v2 of the Pine-A64-LTS
|
||||
board, which features a different Ethernet PHY, namely the Motorcomm YT8511
|
||||
PHY. Genode's 'pine_a64lts' board supports both board revisions now.
|
||||
|
||||
To enable touchscreen input on the Pinephone, the corresponding driver for the
|
||||
Goodix touchscreen controller has been ported from the Linux kernel. It
|
||||
complements the framebuffer driver that we introduced with the previous
|
||||
release. Combined, both drivers enable the use of Genode's regular interactive
|
||||
scenarios based on the 'drivers_interactive' package. The biggest technical
|
||||
challenge was the untangling of both drivers from the clock, reset, and power
|
||||
control units (CCU, RSB, PMIC). Those low-level platform configurations are
|
||||
now handled by a new A64-specific version of the platform driver.
|
||||
|
||||
[image pinephone_touch]
|
||||
Genode's nano-3D example responding to touch input
|
||||
|
||||
The improved driver support is accompanied with new tooling for booting Genode
|
||||
on the Pinephone, either via USB fastboot, or via SD-card. Both options are
|
||||
described in the following Genodians article.
|
||||
|
||||
:Booting Genode on the Pinephone:
|
||||
|
||||
[https://genodians.org/nfeske/2021-09-20-pine-fun-pinephone-boot]
|
||||
|
||||
|
||||
RISC-V
|
||||
======
|
||||
|
||||
RISC-V board support for the base-hw kernel is now located at the
|
||||
[https://github.com/ssumpf/genode-riscv - genode-riscv] repository. Currently,
|
||||
the repository contains support for the
|
||||
[https://hensoldt-cyber.com/mig-v - MiG-V] SoC including kernel specific parts
|
||||
as well as a driver for MiG-V's network-interface controller.
|
||||
|
||||
|
||||
Base framework and OS-level infrastructure
|
||||
##########################################
|
||||
|
||||
New pattern for C++ error handling
|
||||
==================================
|
||||
|
||||
Genode employs C++ exceptions for propagating errors, which is true to the
|
||||
language. However, the use and the mechanics of C++ exceptions comes with its
|
||||
own bag of problems. The current release introduces a new error-handling
|
||||
pattern in the form of the so-called 'Attempt' utility. Its name reflects its
|
||||
designated use as a carrier for return values. This new utility is described
|
||||
by a dedicated article at Genodians.org:
|
||||
|
||||
:An 'Attempt' to avoid C++ exceptions:
|
||||
|
||||
[https://genodians.org/nfeske/2021-11-26-attempt-no-exceptions]
|
||||
|
||||
During the release cycle, we applied the 'Attempt' pattern to Genode's
|
||||
low-level memory-allocation code, namely core's PD session interface (for the
|
||||
allocation of RAM dataspaces), and the code related to the generic 'Allocator'
|
||||
interface (for the allocation of bytes). The latter is an extensive change,
|
||||
touching all implementations of this interface.
|
||||
|
||||
To largely uphold compatibility with components using the original
|
||||
exception-based interface as a mere client - in particular use cases where an
|
||||
'Allocator' is passed to the 'new' operator - the traditional 'alloc' is still
|
||||
supported. But it exists merely as a wrapper around the new 'try_alloc'.
|
||||
However, the change does not preserve compatibility with the original
|
||||
'Range_allocator' interface. So uses of this interface must be adapted.
|
||||
|
||||
|
||||
Pin I/O session interfaces
|
||||
==========================
|
||||
|
||||
On ARM-based SoCs, the use of general-purpose I/O (GPIO) pins is omnipresent.
|
||||
Traditionally, Genode features the "Gpio" session interface for this purpose.
|
||||
This interface allows a client to access an individual pin. Once assigned to a
|
||||
pin, the session grants the client the full responsibility for the pin. In
|
||||
particular the direction of the I/O pin is laid into the hands of the client.
|
||||
We later realized that the wiring and thereby the direction of a pin is
|
||||
ultimately a board-level decision. Wrongly operating an input pin in output
|
||||
mode can easily result in a short-circuit. Therefore, the client of an
|
||||
individual pin should better not be burdened with the responsibility to
|
||||
control the pin direction or pull resistors. To address this concern, it is
|
||||
best to split the roles of GPIO pins into clear-cut session interfaces.
|
||||
Those roles are:
|
||||
|
||||
* The sensing of the state of a GPIO pin, e.g., detecting whether a button is
|
||||
pressed or not: operating a pin as an input signal. This role is now covered
|
||||
by the "Pin_state" session interface with the single RPC function
|
||||
|
||||
! bool state() const;
|
||||
|
||||
By calling this function, the client can request the state of the pin.
|
||||
That's it.
|
||||
|
||||
* Controlling the signal level of a pin: operating a pin as an output signal.
|
||||
This role is now addressed by the "Pin_control" session interface that
|
||||
provides an interface of only one rather unsurprising RPC function
|
||||
|
||||
! void state(bool);
|
||||
|
||||
* Receiving a notification of a change of the signal level of a GPIO pin:
|
||||
operating a pin as an interrupt source. This role can be represented by
|
||||
Genode's existing IRQ session interface - the same interface as provided by
|
||||
Genode's core for GIC interrupts.
|
||||
|
||||
Since each pin corresponds to a separate session, per-pin access control
|
||||
becomes possible by Genode's regular session-routing mechanisms.
|
||||
In contrast to the original GPIO session, the role of each pin as output and
|
||||
input becomes explicit. A client can no longer drive a pin that is an input
|
||||
signal unless explicitly permitted.
|
||||
|
||||
The interfaces were created and time-tested in the context of our
|
||||
Pinephone-related development, in particular during the work described in the
|
||||
following two articles.
|
||||
|
||||
:Device access from the user level:
|
||||
|
||||
[https://genodians.org/nfeske/2021-03-17-pine-fun-device-access]
|
||||
|
||||
:One Platform driver to rule them all:
|
||||
|
||||
[https://genodians.org/nfeske/2021-04-29-platform-driver]
|
||||
|
||||
|
||||
Pin-driver framework
|
||||
--------------------
|
||||
|
||||
In real-world system scenarios, a variety of different components must
|
||||
decidedly interact with individual GPIO pins. This is where a so-called pin
|
||||
driver enters the picture. This component provides the pin-state, pin-control,
|
||||
and IRQ services. Analogously to how the platform driver safeguards the access
|
||||
to device resources by different - mutually distrusting - device drivers, the
|
||||
pin driver's job is the safeguarding of GPIO pins.
|
||||
|
||||
To ease the implementation of such pin drivers, the new session interfaces are
|
||||
accompanied by a set of new utilities in
|
||||
[https://github.com/genodelabs/genode/blob/staging/repos/os/include/os/pin_driver.h - os/pin_driver.h].
|
||||
The use of these utilities is best illustrated by the
|
||||
[https://github.com/nfeske/genode-allwinner/tree/master/src/drivers/pin/a64 - pin driver for the A64 SoC].
|
||||
|
||||
|
||||
Time-multiplexed pin direction
|
||||
------------------------------
|
||||
|
||||
There exist rare use cases for changing the direction of an I/O pin during
|
||||
runtime. For example, the Goodix touchscreen controller as found in the
|
||||
Pinephone monitors the state of its interrupt signal during reset. During its
|
||||
normal operation, this signal is driven by the touchscreen controller but
|
||||
during reset, it is driven by the host to send one bit of information (I2C
|
||||
address selection). We support this time-multiplexed use of one pin as both
|
||||
input and output by the means of session lifetimes. The pin driver switches
|
||||
the pin into output mode not before a client establishes a pin-control session
|
||||
referring to this pin. The client can thereby control the direction by
|
||||
creating or closing its pin-control session.
|
||||
|
||||
|
||||
Genode C APIs
|
||||
=============
|
||||
|
||||
USB host-controller service API
|
||||
-------------------------------
|
||||
|
||||
While porting the Linux driver for the Designware USB host-controller used
|
||||
within the i.MX 8M SoC, we introduced a new C API to serve Genode USB clients
|
||||
from C driver ports. It enables drivers to:
|
||||
|
||||
* Announce and release USB devices,
|
||||
* Ask for a session handle of an open session via the bus/device ID pair,
|
||||
* Ask for a single USB request via a session handle,
|
||||
* Acknowledge a USB request via a session and request handle, and
|
||||
* Notify potential USB clients that I/O progress has been made.
|
||||
|
||||
You can find the new C API under _repos/os/include/genode_c_api/usb.h_. A
|
||||
working example driver can be found within the 'genode-imx' repository under
|
||||
_src/drivers/usb_host/imx8mq_.
|
||||
|
||||
|
||||
Touchscreen driver API
|
||||
----------------------
|
||||
|
||||
To accommodate input drivers written in C, like the ones ported from the Linux
|
||||
kernel, we need a clean way to connect C code with Genode's event session
|
||||
interface.
|
||||
The current release introduces a C API to be used by input drivers to generate
|
||||
Genode events. The interface is located at
|
||||
_repos/os/include/genode_c_api/event.h_ whereas the implementation resides at
|
||||
_repos/os/src/lib/genode_c_api/event.cc_.
|
||||
The initial version is limited to multitouch events only.
|
||||
As of now, it is used by the Goodix touchscreen driver for the Pinephone.
|
||||
|
||||
|
||||
Event filter for converting touch to pointer input
|
||||
==================================================
|
||||
|
||||
Unlike traditional pointer devices, touchscreens have no notion of a pointer
|
||||
position, hovering, or mouse buttons. E.g., without touching, there is no
|
||||
position. There exists a gap between those devices and regular GUI
|
||||
applications, which respond to pointer events in terms of hovering motion (in
|
||||
screen coordinates) and mouse clicks. Genode's existing touchscreen drivers
|
||||
try to bridge this gap by translating touch input to pointer events in rather
|
||||
pragmatic ways. This is not optimal for two reasons.
|
||||
|
||||
First, putting the burden of emulating traditional pointer devices on the
|
||||
touchscreen drivers not only inflates their complexity but is also unnatural
|
||||
when the calibration of touch coordinates to screen coordinates comes into
|
||||
play. In this case, the touchscreen driver must be made aware of the display
|
||||
resolution. Second, the heuristics of how touch events are best translated
|
||||
into pointer events tend to differ from driver to driver, or between Genode
|
||||
use cases. Any intelligence that is builtin in the drivers stands in the way
|
||||
of interchanging the drivers or enhancing the translation across all drivers
|
||||
(e.g., adding two-finger-scroll).
|
||||
|
||||
To solve this problem in a clean way, we added a new optional filter for
|
||||
translating touch events to pointer events to Genode's event-filter component
|
||||
(first introduced in
|
||||
[https://genode.org/documentation/release-notes/17.02#Input-event_filter - 17.02]
|
||||
as input filter, reworked in
|
||||
[https://genode.org/documentation/release-notes/20.08#Replacing_the_input_filter_with_an_event_filter - 20.08]).
|
||||
The new filter comes in the form of a new '<touch-click>' node in the filter's
|
||||
'<output>' definition. For example, the configuration of the event filter that
|
||||
sits in-between the Goodix touchscreen driver for the Pinephone and the
|
||||
nitpicker GUI server looks as follows.
|
||||
|
||||
! <config>
|
||||
! <output>
|
||||
! <touch-click>
|
||||
! <input name="touch"/>
|
||||
! </touch-click>
|
||||
! </output>
|
||||
! <policy label="touch" input="touch"/>
|
||||
! </config>
|
||||
|
||||
The filter augments touch events with artificial absolute motion and mouse
|
||||
click/clack events as understood by regular GUI applications. The original
|
||||
touch events are preserved, enabling touch-aware applications to interpret
|
||||
touch gestures.
|
||||
|
||||
|
||||
Device drivers
|
||||
##############
|
||||
|
||||
Hardware-accelerated graphics
|
||||
=============================
|
||||
|
||||
Generic GPU-session interface
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
When we introduced the GPU session initially, it was modeled after the
|
||||
perceived requirements of the Linux i915 DRM back end. In the meantime, with
|
||||
the enablement of a more recent Mesa version and the addition of Vivante as
|
||||
another GPU family, we learned that some of those requirements are obsolete.
|
||||
|
||||
First, we replaced the 'info' RPC by an information ROM dataspace to overcome
|
||||
the following limitations.
|
||||
|
||||
* The amount of data that can be transferred in an RPC is constrained by the
|
||||
underlying base platform,
|
||||
* Most information never changes during run time but must be copied
|
||||
nonetheless when using an RPC interface,
|
||||
* The information presented differs depending on the used GPU device.
|
||||
With the introduction of Vivante, the original Intel-centric implementation no
|
||||
longer suffices.
|
||||
* Sequence numbers of GPU execution buffers are not GPU-specific and, thus,
|
||||
should be part of the generic GPU session interface.
|
||||
|
||||
Currently, the GPU-specific information is presented in binary format, which
|
||||
is specified in _gpu/info_intel.h_ resp. _gpu/info_etnaviv.h_ for the Vivante
|
||||
GPU. We entertain the idea to replace the current representation by an
|
||||
XML-based ROM in the future to render the interface binary agnostic and also
|
||||
backwards-compatible. The information ROM can be accessed via the
|
||||
'attached_info' client API function.
|
||||
|
||||
Furthermore, we replaced the usage of heavy-weight dataspace capabilities with
|
||||
light-weight client-local identifiers called 'Buffer_id' within the API. In
|
||||
case the client requires a capability (e.g., for mapping the buffer in its
|
||||
address space) it uses the corresponding ID to request it from the server.
|
||||
|
||||
With upcoming support for other driver back ends, we need to take their
|
||||
requirements into account as well. We introduced abstractions that further
|
||||
encapsulate the device-specific state and operations. The changes in this
|
||||
release represent only the first consolidation steps of Genode's GPU support
|
||||
and we will continue this work during the next months.
|
||||
|
||||
|
||||
Intel GPU support for Gen9 and newer
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
As mentioned in the
|
||||
[https://genode.org/documentation/release-notes/21.08#Advancing_GPU_driver_stack - 21.08]
|
||||
release notes, we were fiercely working on Intel GPU Gen9+ support because
|
||||
Gen8 (Broadwell) was the only stable running GPU on Genode at the time. For
|
||||
Gen9+, we experienced severe GPU hangs after an undefined amount of rendering
|
||||
passes. As promised in the previous release, we dove right in and were able to
|
||||
identify the main causes of this behavior. This led to working Gen9+ support in
|
||||
[https://genode.org/documentation/articles/sculpt-21-10#GPU - Sculpt OS release 21.10].
|
||||
To go into a little more detail, we had to look into workarounds as described by the
|
||||
[https://01.org/sites/default/files/documentation/intel-gfx-prm-osrc-skl-vol16-workarounds_0.pdf - Intel documentation]
|
||||
and the Linux kernel driver, and determine known workarounds that only apply
|
||||
to Gen9 and above. After many iterations, we found one workaround that fixed
|
||||
our GPU hang issue and now apply it during GPU initialization. Additionally,
|
||||
we found the hardware context sizes (a memory region where the GPU stores its
|
||||
state) vary between GPU generations, where Gen9 requires more space than Gen8.
|
||||
|
||||
Additionally, we found that some features like tiling or client mappings
|
||||
through the global-graphics translation table are not required by our updated
|
||||
Mesa 21.0.0 Iris Gallium driver. Since these resources are global and were
|
||||
split between multiple GPU client applications, not using them lifts the
|
||||
limits formerly imposed by the partitioning.
|
||||
|
||||
For the Sculpt integration, we added GPU-service support and are providing
|
||||
various packages. A summary on how to test GPU acceleration on Sculpt can be
|
||||
found at the following Genodians article.
|
||||
|
||||
:Test driving Sculpt's 3D support:
|
||||
|
||||
[https://genodians.org/ssumpf/2021-10-25-glmark2]
|
||||
|
||||
|
||||
|
||||
Vivante GPUs (i.MX8)
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
With the previous release, we already foresaw adding support for Vivante
|
||||
GPUs as found in i.MX8 SoCs by show-casing a work-in-progress driver
|
||||
component based on the Linux 'etnaviv' DRM driver and using the also ported
|
||||
'etnaviv' Gallium driver.
|
||||
|
||||
This driver component is now available in an updated fashion in the
|
||||
[https://github.com/skalk/genode-imx - genode-imx] repository that
|
||||
encapsulates support for the family of i.MX8 SoCs for Genode. In contrast to
|
||||
our first prototype, the driver now relies completely on the new DDE Linux
|
||||
approach and re-uses the existing 'lx_emul' and 'lx_kit' libraries. At the
|
||||
moment, the driver does not make use of a C-API to Genode services for
|
||||
accessing the GPU service like the other new DDE Linux drivers do but
|
||||
implements the session directly. We decided against prematurely introducing
|
||||
such an C-API while the GPU session itself is still in flux.
|
||||
|
||||
[image glmark_mnt_reform]
|
||||
Glmark running via the ported Vivante GPU driver on the MNT Reform laptop
|
||||
|
||||
Briefly touching on the current implementation of the driver, we had to extend
|
||||
the 'lx_kit' API slightly to implement the buffer-object allocation. Also, we
|
||||
added a special-purpose interface called 'lx_drm' that comprises all Linux DRM
|
||||
I/O controls that need to be performed for implementing the GPU session and
|
||||
itself is a simple layer on top of 'drm_ioctl'.
|
||||
|
||||
The 'lx_drm' functions are executed within the context of an emulated Linux
|
||||
kernel thread executed under a cooperative user-level scheduling scheme.
|
||||
However, since the GPU session is based on synchronous RPCs and we do not know
|
||||
in advance if a call into the ported driver code blocks at some point, we had
|
||||
to ensure the RPC returns not before the operation completed. The completion
|
||||
of operations may include several blocking states and concurrent event
|
||||
handling (e.g., hardware interrupts).
|
||||
|
||||
For the time being, the driver component is still being worked on. We are, for
|
||||
example, investigating overall performance regressions. Nevertheless, the
|
||||
driver is functionally complete and currently supports one client at a time.
|
||||
|
||||
In addition to the driver component, we cleaned up the existing 'etnaviv'
|
||||
libdrm back end and created a Sculpt pkg called *mesa_gpu-etnaviv* analogous
|
||||
to the pkgs for 'iris' and 'softpipe' back ends. The most visible change is
|
||||
the switch from the ad-hoc DRM session to the GPU session.
|
||||
|
||||
All in all, we are now at a stage were we can work on optimizing the graphics
|
||||
stack on the Vivante GPU and are in particular looking forward to porting the
|
||||
next Linux driver. After all, by doing so, we can flesh out and maybe
|
||||
generalize the 'lx_drm' API so that for other drivers the porting effort gets
|
||||
reduced even further.
|
||||
|
||||
|
||||
VirtIO input and framebuffer drivers
|
||||
====================================
|
||||
|
||||
_This section was co-authored by Piotr Tworek who created the_
|
||||
_VirtIO driver support. Thanks Piotr for the welcome contribution!_
|
||||
|
||||
Over the
|
||||
[https://genode.org/documentation/release-notes/21.02#VirtIO_block_devices_for_virtual_machines_on_ARM - previous]
|
||||
[https://genode.org/documentation/release-notes/21.08#RAM_framebuffer_driver_for_Qemu - releases]
|
||||
of Genode this year, the framework received steadily improved driver support
|
||||
for virtual devices as supported by Qemu. The primary motivation behind this
|
||||
line of work is the use of virtual hardware as an experimentation ground for
|
||||
Genode on the AARCH64 and RISC-V architectures. The use of virtual hardware
|
||||
nicely side-steps the costs and (un-)availability of suitable devices, and
|
||||
avoids the extra effort that is usually involved when working with real
|
||||
hardware. The current release further advances the virtual-device support by
|
||||
the introduction of VirtIO input and graphics drivers.
|
||||
|
||||
|
||||
VirtIO input
|
||||
------------
|
||||
|
||||
The new input driver can service Qemu VirtIO mouse, keyboard, and tablet
|
||||
devices. The implementation is based on the VirtIO 1.1 device specification,
|
||||
Section 5.8 "Input Device". The driver can service three separate device
|
||||
types, namely mouse, keyboard, and tablet. The main difference between mouse
|
||||
and tablet devices is that the former produces relative events whereas the
|
||||
latter produces absolute motion events.
|
||||
|
||||
By default, the driver tries to attach to the first VirtIO input device of any
|
||||
of the listed types. Such behavior would pose a bit of a problem since in
|
||||
Genode, we'd like to know that a specific instance of the driver will attach
|
||||
only to a mouse for example. This way, we can define proper policies for it.
|
||||
To allow such behavior, the VirtIO input driver has one configuration key
|
||||
called 'match_product', which accepts the values of "mouse", "keyboard",
|
||||
"tablet", and "any" (default). Using this config key, one can accomplish
|
||||
exactly what is needed to tell the driver to only attach to a VirtIO input
|
||||
device if it's of "match_product" type.
|
||||
|
||||
|
||||
VirtIO framebuffer
|
||||
------------------
|
||||
|
||||
The new VirtIO framebuffer driver implements the necessary bits to provide 2D
|
||||
framebuffer support on top of a VirtIO GPU device as provided by Qemu. Compared
|
||||
to the ramfb driver, which was introduced in Genode
|
||||
[https://genode.org/documentation/release-notes/21.08#RAM_framebuffer_driver_for_Qemu - 21.08],
|
||||
the VirtIO framebuffer driver has one major benefit: It allows the Qemu window
|
||||
to be dynamically resized at runtime. The driver will treat this as resolution
|
||||
change and act accordingly. In contrast to the VirtIO input driver, the
|
||||
framebuffer driver does not support any extra config options.
|
||||
|
||||
|
||||
Practical use
|
||||
-------------
|
||||
|
||||
Thanks to the new drivers, the drivers_interactive package for the 'virt_qemu'
|
||||
board has become fully interactively usable. The drivers subsystem spawns two
|
||||
instances of virtio_input. One attaches to a keyboard device and the second to
|
||||
a mouse. This is what the default virt_qemu board exposes. At this time, the
|
||||
tablet device is not instantiated by default but it might become useful in the
|
||||
future for testing Genode's touch support.
|
||||
|
||||
Make sure that Qemu exposes those new devices in the modern VirtIO 1.0 mode.
|
||||
Versions up to Qemu 5.1.0 still use pre-1.0 mode in the default setup.
|
||||
|
||||
One thing to keep in mind is that the VirtIO framebuffer driver will change
|
||||
the resolution of the virtual display whenever the Qemu window is resized.
|
||||
This means that for high resolution screens, one might have to tweak the
|
||||
default RAM quota for the driver. The default should be enough for 1080p
|
||||
screens, but not much more than that.
|
||||
|
||||
|
||||
Linux device-driver environment
|
||||
===============================
|
||||
|
||||
While working on Linux device-driver ports that use the new DDE Linux
|
||||
environment introduced in
|
||||
[https://genode.org/documentation/release-notes/21.08#Linux-device-driver_environment_re-imagined - release 21.08],
|
||||
we stumbled across some inaccuracies and missing pieces of the former
|
||||
implementation.
|
||||
For instance, kworker threads were blocked unconditionally before. But the
|
||||
original Linux kernel semantics includes corner-cases that delay kworker
|
||||
suspension. By adding them, we circumvent potential deadlocks. The cache
|
||||
maintenance operations got optimized by checking the read/write direction of
|
||||
the device with regard to DMA memory more accurately. Moreover, we had to
|
||||
learn that on ARM the minimal alignment for all allocations within Linux have
|
||||
to be of cache-line granularity.
|
||||
|
||||
Feature-wise, a new API got introduced to access the pin-control service and
|
||||
IRQ sessions offered by it. This is useful when a Linux driver directly
|
||||
depends on GPIO settings respectively uses GPIO pins as interrupt source.
|
||||
|
||||
|
||||
Libraries and Applications
|
||||
##########################
|
||||
|
||||
Feature completion of VirtualBox 6
|
||||
==================================
|
||||
|
||||
With [https://genode.org/documentation/articles/sculpt-21-10 - Sculpt OS 21.10],
|
||||
we released VirtualBox version 6 as experimental alternative to the existing
|
||||
port of version 5. We also switched to version 6 as daily driver on our
|
||||
development machines at Genode Labs. These steps yielded the following
|
||||
improvements during the past Genode release cycle.
|
||||
|
||||
The integration features shared folders, shared clipboard, and guest
|
||||
mouse-pointer shape were fully enabled. Most guest-integration modules in
|
||||
VirtualBox are implemented as shared libraries/objects, which are loaded at
|
||||
runtime on demand. Following our goal to keep changes to the upstream code
|
||||
minimal, our version of VirtualBox 6 now provides VBoxSharedClipboard and
|
||||
VBoxSharedFolders as dedicated libraries that must be integrated into the
|
||||
system as follows. Note, the libraries are accessed by the VirtualBox code as
|
||||
files before loading but must also be available as ROMs to our runtime dynamic
|
||||
linker.
|
||||
|
||||
! <start name="virtualbox6">
|
||||
! <config vbox_file="machine.vbox6">
|
||||
! <vfs>
|
||||
! <!-- original file names of shared objects -->
|
||||
! <rom name="VBoxSharedClipboard.so"/>
|
||||
! <rom name="VBoxSharedFolders.so"/>
|
||||
! </vfs>
|
||||
! </config>
|
||||
! <route>
|
||||
! <!-- map file names to Genode shared-object naming scheme -->
|
||||
! <service name="ROM" label="VBoxSharedClipboard.so">
|
||||
! <parent label="virtualbox6-sharedclipboard.lib.so"/> </service>
|
||||
! <service name="ROM" label="VBoxSharedFolders.so">
|
||||
! <parent label="virtualbox6-sharedfolders.lib.so"/> </service>
|
||||
! </route>
|
||||
! </start>
|
||||
|
||||
As depicted in the configuration snippet above, we use the file extension
|
||||
_.vbox6_ for VirtualBox 6 configuration files. The background is that there
|
||||
are some subtle incompatibilities in VirtualBox 6 with settings we used in
|
||||
version 5. For example, the version of the configuration file must be set to
|
||||
1.18+ for maximum compatibility of virtual-device configuration and guest
|
||||
operating systems. An example configuration is provided by the pkg/vbox6 depot
|
||||
archive and specifies the version like follows.
|
||||
|
||||
! <VirtualBox xmlns="http://www.virtualbox.org/" version="1.18-genode">
|
||||
|
||||
Unlike VirtualBox 5, the current version does not implement a custom Audio
|
||||
back end for Genode but uses the existing OSS back end of the original
|
||||
implementation. The feature can be enabled in .vbox and runtime configuration.
|
||||
We recommend using the HDA controller.
|
||||
|
||||
! <AudioAdapter controller="HDA" driver="OSS" enabled="true" enabledOut="true" enabledIn="false"/>
|
||||
|
||||
! <start name="virtualbox6">
|
||||
! <config>
|
||||
! <vfs>
|
||||
! <dir name="dev"> <oss name="dsp"/> </dir>
|
||||
! <vfs>
|
||||
! </config>
|
||||
! </start>
|
||||
|
||||
More device-related improvements are the reporting of mouse-wheel events, the
|
||||
support of up to 8 pass-through USB devices via the virtual XHCI USB3
|
||||
controller, and a ready-to-use Sculpt package to capture webcam streams in the
|
||||
VM (genodelabs/pkg/vbox6-capture).
|
||||
|
||||
Finally, this release includes a whole lot of stability improvements to bring
|
||||
VirtualBox 6 on par with version 5 in daily use like robust machine state
|
||||
handling including the FPU, fixed corner cases in the AHCI model and
|
||||
Startup-IPI implementation as well as enhanced timeout and CPU wakeup
|
||||
handling.
|
||||
|
||||
|
||||
Sculpt OS for 64-bit ARM in addition to x86
|
||||
===========================================
|
||||
|
||||
Up until now, the Genode-based [https://genode.org/download/sculpt - Sculpt OS]
|
||||
was primarily targeted at the 64-bit x86 architecture. However, since the
|
||||
hardware support of 64-bit ARM platforms like i.MX8 has reached almost feature
|
||||
parity with the PC platform, it was time to introduce the notion of CPU
|
||||
architectures to package index files.
|
||||
|
||||
In Sculpt OS, software packages are provided in a federated way from any
|
||||
number of package providers. Each provider offers a so-called _index_ that
|
||||
enlists the available package versions blessed for a specific Sculpt OS
|
||||
release. See the release notes for Genode
|
||||
[https://genode.org/documentation/release-notes/19.02#Announcing_software_packages - 19.02]
|
||||
for more details.
|
||||
Starting with [https://genode.org/news/sculpt-os-release-21.10 - Sculpt OS 21.10]
|
||||
released in October, each index file features a declaration of the CPU
|
||||
architectures supported by the package provider.
|
||||
|
||||
! <index>
|
||||
! <supports arch="x86_64"/>
|
||||
! <supports arch="arm_v8a"/>
|
||||
! ...
|
||||
|
||||
Sculpt uses this information to decide whether to display the index or not by
|
||||
comparing the architecture of the running machine with these declarations.
|
||||
Individual entries of an index file can be tagged as being specific for one
|
||||
architecture.
|
||||
|
||||
! <pkg path="mesa_gpu-intel" info="Intel GPU driver (IRIS)" arch="x86_64"/>
|
||||
|
||||
This annotation can also be specified for a sub index.
|
||||
|
||||
! <index name="Virtual machines" arch="x86_64">
|
||||
! ...
|
||||
! </index>
|
||||
|
||||
Thanks to this approach, most packages - which are architecture-agnostic - can
|
||||
be offered for both x64_64 and arm_v8a with almost no manual work. In fact,
|
||||
starting with Sculpt 21.10, all default packages offered by Genode Labs are
|
||||
available for both architectures.
|
||||
|
||||
|
||||
Audio and OpenGL support for libSDL2
|
||||
====================================
|
||||
|
||||
With this release, we extend the features of our SDL2 port by enabling audio
|
||||
support via the OSS back end and added basic support for using OpenGL.
|
||||
|
||||
Re-using the existing OSS back end via our VFS OSS plugin is in contrast to
|
||||
how we enabled audio in our SDL1 port where we use Genode's audio-out
|
||||
session directly. Instead of having to add a Genode specific back end to each
|
||||
ported software, it is more reasonable to have just one implementation of a
|
||||
somewhat common interface for which the back end already exists.
|
||||
|
||||
The OpenGL support, on the other hand, has not been thoroughly tested yet
|
||||
but works well enough for one or the other game. It still suffers from the
|
||||
same limitation as the normal video back end where resizing the window during
|
||||
runtime is not supported. This feature is yet to be implemented.
|
||||
|
||||
Additionally, we made SDL2 now to use its existing pthread back ends,
|
||||
rather than using the generic fallback ones, as we deem the current pthread
|
||||
support in Genode sufficient.
|
||||
|
||||
|
||||
SSH terminal moved to Genode world repository
|
||||
=============================================
|
||||
|
||||
The SSH terminal component now resides in the world repository. When we
|
||||
initially introduced this component, it complemented the existing TCP
|
||||
terminal. Rather than using plain TCP to access a terminal server the
|
||||
connection is secured by the SSH protocol.
|
||||
|
||||
In the meantime the component itself incorporated more and more features
|
||||
that were not anticipated in the initial design. Since we have not used
|
||||
the component much ourselves lately, albeit some features are tested in our
|
||||
nightly CI, we decided to move it to the world repository.
|
||||
|
||||
On a different note, the component now features new support for SFTP that
|
||||
enables one to access a Genode file system via SSH. Thanks to Tomasz Gajewski
|
||||
for this welcome contribution.
|
||||
|
||||
|
||||
Build system and tools
|
||||
######################
|
||||
|
||||
Moving the platform-specific board support into extra repositories made it
|
||||
necessary to review the run tool with respect to virtualized platforms. For
|
||||
running Genode within Qemu, the run tool used to assemble the Qemu command
|
||||
line depending on the target board. In order to achieve a clean cut between
|
||||
the main repository hosting this part of the run tool and the
|
||||
platform-specific repositories, we came up with a way to specify the Qemu
|
||||
arguments outside the main repository.
|
||||
|
||||
The solution follows along our approach of how we already specify the
|
||||
architecture and link address of a target board in distinct files within a
|
||||
board-property directory _board/<board_name>/_. Similarly, the board-specific
|
||||
Qemu arguments are now provided in a _board/<board_name>/qemu_args_ file. This
|
||||
file may contain one or multiple lines that will be appended to the command
|
||||
line generated by the run tool. Because it is required by virt_qemu, it is
|
||||
possible to restrict particular arguments to a certain spec, e.g. arm_v8a, by
|
||||
prefixing the line with 'arm_v8a:'. Note, that any '-m *' argument, which
|
||||
specifies the amount of RAM, provided within a _qemu_args_ file will override
|
||||
any memory setting provided in the run scripts.
|
||||
|
||||
Moreover, the _qemu_args_ file is obliged with instantiating a network
|
||||
controller since this is also specific to the platform. For the zynq_qemu
|
||||
board, e.g., this is achieved by the following arguments:
|
||||
|
||||
! -net nic,model=cadence_gem,netdev=net0 -netdev user,id=net0
|
||||
|
||||
Always instantiating a network device removes the need to call
|
||||
'append_qemu_nic_args' in the run scripts. However, you can still use this
|
||||
function to add forwarding rules to the netdev with id _net0_.
|
||||
@@ -1 +1 @@
|
||||
2021-10-13 05c76f8a5e76e0cc76fd7336c7cf63836ecec35d
|
||||
2021-11-29 dc3dc62ee3267db5cab87426b73323828cbc8d15
|
||||
|
||||
@@ -38,61 +38,67 @@ static inline bool can_use_super_page(addr_t, size_t)
|
||||
}
|
||||
|
||||
|
||||
addr_t Io_mem_session_component::_map_local(addr_t base, size_t size)
|
||||
addr_t Io_mem_session_component::_map_local(addr_t phys_base, size_t size)
|
||||
{
|
||||
using namespace Fiasco;
|
||||
auto map_io_region = [] (addr_t phys_base, addr_t local_base, size_t size)
|
||||
{
|
||||
using namespace Fiasco;
|
||||
|
||||
l4_threadid_t const sigma0 = sigma0_threadid;
|
||||
|
||||
unsigned offset = 0;
|
||||
while (size) {
|
||||
|
||||
/*
|
||||
* Call sigma0 for I/O region
|
||||
*/
|
||||
|
||||
/* special case for page0, which is RAM in sigma0/x86 */
|
||||
l4_umword_t const request = (phys_base + offset == 0)
|
||||
? SIGMA0_REQ_FPAGE_RAM
|
||||
: SIGMA0_REQ_FPAGE_IOMEM;
|
||||
|
||||
size_t const size_log2 = can_use_super_page(phys_base + offset, size)
|
||||
? get_super_page_size_log2()
|
||||
: get_page_size_log2();
|
||||
|
||||
l4_umword_t dw0 = 0, dw1 = 0;
|
||||
l4_msgdope_t result { };
|
||||
l4_msgtag_t tag { };
|
||||
|
||||
int const err =
|
||||
l4_ipc_call_tag(sigma0,
|
||||
L4_IPC_SHORT_MSG,
|
||||
request,
|
||||
l4_fpage(phys_base + offset, size_log2, 0, 0).fpage,
|
||||
l4_msgtag(L4_MSGTAG_SIGMA0, 0, 0, 0),
|
||||
L4_IPC_MAPMSG(local_base + offset, size_log2),
|
||||
&dw0, &dw1,
|
||||
L4_IPC_NEVER, &result, &tag);
|
||||
|
||||
if (err || !l4_ipc_fpage_received(result)) {
|
||||
error("map_local failed err=", err, " "
|
||||
"(", l4_ipc_fpage_received(result), ")");
|
||||
return;
|
||||
}
|
||||
|
||||
offset += 1 << size_log2;
|
||||
size -= 1 << size_log2;
|
||||
}
|
||||
};
|
||||
|
||||
/* align large I/O dataspaces on a super-page boundary within core */
|
||||
size_t alignment = (size >= get_super_page_size()) ? get_super_page_size_log2()
|
||||
: get_page_size_log2();
|
||||
size_t align = (size >= get_super_page_size()) ? get_super_page_size_log2()
|
||||
: get_page_size_log2();
|
||||
|
||||
/* find appropriate region for mapping */
|
||||
void *local_base = 0;
|
||||
if (platform().region_alloc().alloc_aligned(size, &local_base, alignment).error())
|
||||
return 0;
|
||||
return platform().region_alloc().alloc_aligned(size, align).convert<addr_t>(
|
||||
|
||||
/* call sigma0 for I/O region */
|
||||
int err;
|
||||
l4_umword_t request;
|
||||
l4_umword_t dw0, dw1;
|
||||
l4_msgdope_t result;
|
||||
l4_msgtag_t tag;
|
||||
[&] (void *ptr) {
|
||||
addr_t const core_local_base = (addr_t)ptr;
|
||||
map_io_region(phys_base, core_local_base, size);
|
||||
return core_local_base; },
|
||||
|
||||
l4_threadid_t sigma0 = sigma0_threadid;
|
||||
|
||||
unsigned offset = 0;
|
||||
while (size) {
|
||||
/* FIXME what about caching demands? */
|
||||
/* FIXME what about read / write? */
|
||||
|
||||
/* special case for page0, which is RAM in sigma0/x86 */
|
||||
if (base + offset == 0)
|
||||
request = SIGMA0_REQ_FPAGE_RAM;
|
||||
else
|
||||
request = SIGMA0_REQ_FPAGE_IOMEM;
|
||||
|
||||
size_t page_size_log2 = get_page_size_log2();
|
||||
if (can_use_super_page(base + offset, size))
|
||||
page_size_log2 = get_super_page_size_log2();
|
||||
|
||||
err = l4_ipc_call_tag(sigma0,
|
||||
L4_IPC_SHORT_MSG,
|
||||
request,
|
||||
l4_fpage(base + offset, page_size_log2, 0, 0).fpage,
|
||||
l4_msgtag(L4_MSGTAG_SIGMA0, 0, 0, 0),
|
||||
L4_IPC_MAPMSG((addr_t)local_base + offset, page_size_log2),
|
||||
&dw0, &dw1,
|
||||
L4_IPC_NEVER, &result, &tag);
|
||||
|
||||
if (err || !l4_ipc_fpage_received(result)) {
|
||||
error("map_local failed err=", err, " "
|
||||
"(", l4_ipc_fpage_received(result), ")");
|
||||
return 0;
|
||||
}
|
||||
|
||||
offset += 1 << page_size_log2;
|
||||
size -= 1 << page_size_log2;
|
||||
}
|
||||
|
||||
return (addr_t)local_base;
|
||||
[&] (Range_allocator::Alloc_error) -> addr_t {
|
||||
error("core-local mapping of memory-mapped I/O range failed");
|
||||
return 0; });
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ Irq_session_component::Irq_session_component(Range_allocator &irq_alloc,
|
||||
if (msi)
|
||||
throw Service_denied();
|
||||
|
||||
if (irq_alloc.alloc_addr(1, _irq_number).error()) {
|
||||
if (irq_alloc.alloc_addr(1, _irq_number).failed()) {
|
||||
error("unavailable IRQ ", _irq_number, " requested");
|
||||
throw Service_denied();
|
||||
}
|
||||
|
||||
@@ -445,51 +445,42 @@ Platform::Platform()
|
||||
fiasco_register_thread_name(core_thread.native_thread_id(),
|
||||
core_thread.name().string());
|
||||
|
||||
/* core log as ROM module */
|
||||
auto export_page_as_rom_module = [&] (auto rom_name, auto content_fn)
|
||||
{
|
||||
void * phys_ptr = nullptr;
|
||||
unsigned const pages = 1;
|
||||
size_t const log_size = pages << get_page_size_log2();
|
||||
size_t const size = 1 << get_page_size_log2();
|
||||
ram_alloc().alloc_aligned(size, get_page_size_log2()).with_result(
|
||||
|
||||
ram_alloc().alloc_aligned(log_size, &phys_ptr, get_page_size_log2());
|
||||
addr_t const phys_addr = reinterpret_cast<addr_t>(phys_ptr);
|
||||
[&] (void *phys_ptr) {
|
||||
|
||||
void * const core_local_ptr = phys_ptr;
|
||||
addr_t const core_local_addr = phys_addr;
|
||||
/* core-local memory is one-to-one mapped physical RAM */
|
||||
addr_t const phys_addr = reinterpret_cast<addr_t>(phys_ptr);
|
||||
void * const core_local_ptr = phys_ptr;
|
||||
|
||||
/* let one page free after the log buffer */
|
||||
region_alloc().remove_range(core_local_addr, log_size + get_page_size());
|
||||
region_alloc().remove_range((addr_t)core_local_ptr, size);
|
||||
memset(core_local_ptr, 0, size);
|
||||
content_fn(core_local_ptr, size);
|
||||
|
||||
memset(core_local_ptr, 0, log_size);
|
||||
_rom_fs.insert(new (core_mem_alloc())
|
||||
Rom_module(phys_addr, size, rom_name));
|
||||
},
|
||||
[&] (Range_allocator::Alloc_error) {
|
||||
warning("failed to export ", rom_name, " as ROM module"); }
|
||||
);
|
||||
};
|
||||
|
||||
_rom_fs.insert(new (core_mem_alloc()) Rom_module(phys_addr, log_size,
|
||||
"core_log"));
|
||||
|
||||
init_core_log(Core_log_range { core_local_addr, log_size } );
|
||||
}
|
||||
/* core log as ROM module */
|
||||
export_page_as_rom_module("core_log",
|
||||
[&] (void *core_local_ptr, size_t size) {
|
||||
init_core_log(Core_log_range { (addr_t)core_local_ptr, size } ); });
|
||||
|
||||
/* export platform specific infos */
|
||||
{
|
||||
void * phys_ptr = nullptr;
|
||||
size_t const size = 1 << get_page_size_log2();
|
||||
|
||||
if (ram_alloc().alloc_aligned(size, &phys_ptr,
|
||||
get_page_size_log2()).ok()) {
|
||||
addr_t const phys_addr = reinterpret_cast<addr_t>(phys_ptr);
|
||||
addr_t const core_local_addr = phys_addr;
|
||||
|
||||
region_alloc().remove_range(core_local_addr, size);
|
||||
|
||||
Genode::Xml_generator xml(reinterpret_cast<char *>(core_local_addr),
|
||||
size, "platform_info", [&] ()
|
||||
{
|
||||
xml.node("kernel", [&] () { xml.attribute("name", "fiasco"); });
|
||||
});
|
||||
|
||||
_rom_fs.insert(new (core_mem_alloc()) Rom_module(phys_addr, size,
|
||||
"platform_info"));
|
||||
}
|
||||
}
|
||||
export_page_as_rom_module("platform_info",
|
||||
[&] (void *core_local_ptr, size_t size) {
|
||||
Xml_generator xml(reinterpret_cast<char *>(core_local_ptr),
|
||||
size, "platform_info",
|
||||
[&] () {
|
||||
xml.node("kernel", [&] () {
|
||||
xml.attribute("name", "fiasco"); }); }); });
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
2021-10-13 0e3f2b9302333cb9bcabfb933a0ab142f41d070c
|
||||
2021-11-29 86ebd8f9b9c153fc0eb7ef7ef7604116f8438e04
|
||||
|
||||
@@ -1 +1 @@
|
||||
2021-10-13 af7ceb5c77e20a66ed9f394526766b31a205d89d
|
||||
2021-11-29 731498ebe667555a14fdcbf3c1cab33e227fb036
|
||||
|
||||
@@ -1 +1 @@
|
||||
2021-10-13 62af5bc4ad5747f1552f1c03882f756ec7f1d63c
|
||||
2021-11-29 ae5de8b6bf4f21e2cdc74151aff195c56f74032e
|
||||
|
||||
@@ -1 +1 @@
|
||||
2021-10-13 6bd8c055af6f1031539124d93164d0ae24f956c8
|
||||
2021-11-29 6f4c635c08bbdd5610c157fd001955de4a2fb81e
|
||||
|
||||
@@ -1 +1 @@
|
||||
2021-10-13 dabb150f6be49ee72d2d5db160e8885ac7faddd0
|
||||
2021-11-29 af285a52c89b07a1cfd2c03dac4905d8d7a498e3
|
||||
|
||||
@@ -34,14 +34,18 @@ addr_t Io_mem_session_component::_map_local(addr_t base, size_t size)
|
||||
: get_page_size_log2();
|
||||
|
||||
/* find appropriate region for mapping */
|
||||
void *local_base = 0;
|
||||
if (platform().region_alloc().alloc_aligned(size, &local_base, alignment).error())
|
||||
return 0;
|
||||
return platform().region_alloc().alloc_aligned(size, alignment).convert<addr_t>(
|
||||
|
||||
if (!map_local_io(base, (addr_t)local_base, size >> get_page_size_log2())) {
|
||||
error("map_local_io failed");
|
||||
return 0;
|
||||
}
|
||||
[&] (void *local_base) {
|
||||
if (!map_local_io(base, (addr_t)local_base, size >> get_page_size_log2())) {
|
||||
error("map_local_io failed");
|
||||
platform().region_alloc().free(local_base, base);
|
||||
return 0UL;
|
||||
}
|
||||
return (addr_t)local_base;
|
||||
},
|
||||
|
||||
return (addr_t)local_base;
|
||||
[&] (Range_allocator::Alloc_error) {
|
||||
error("allocation of virtual memory for local I/O mapping failed");
|
||||
return 0UL; });
|
||||
}
|
||||
|
||||
@@ -196,7 +196,7 @@ Irq_session_component::Irq_session_component(Range_allocator &irq_alloc,
|
||||
}
|
||||
msi_alloc.set(_irq_number, 1);
|
||||
} else {
|
||||
if (irq_alloc.alloc_addr(1, _irq_number).error()) {
|
||||
if (irq_alloc.alloc_addr(1, _irq_number).failed()) {
|
||||
error("unavailable IRQ ", _irq_number, " requested");
|
||||
throw Service_denied();
|
||||
}
|
||||
|
||||
@@ -467,75 +467,68 @@ Platform::Platform()
|
||||
core_thread.pager(_sigma0);
|
||||
_core_pd->bind_thread(core_thread);
|
||||
|
||||
/* export x86 platform specific infos */
|
||||
auto export_page_as_rom_module = [&] (auto rom_name, auto content_fn)
|
||||
{
|
||||
void * core_local_ptr = nullptr;
|
||||
void * phys_ptr = nullptr;
|
||||
unsigned const pages = 1;
|
||||
size_t const align = get_page_size_log2();
|
||||
size_t const size = pages << get_page_size_log2();
|
||||
size_t const pages = 1;
|
||||
size_t const align = get_page_size_log2();
|
||||
size_t const bytes = pages << get_page_size_log2();
|
||||
ram_alloc().alloc_aligned(bytes, align).with_result(
|
||||
|
||||
if (ram_alloc().alloc_aligned(size, &phys_ptr, align).error())
|
||||
return;
|
||||
[&] (void *phys_ptr) {
|
||||
|
||||
if (region_alloc().alloc_aligned(size, &core_local_ptr, align).error())
|
||||
return;
|
||||
addr_t const phys_addr = reinterpret_cast<addr_t>(phys_ptr);
|
||||
|
||||
addr_t const phys_addr = reinterpret_cast<addr_t>(phys_ptr);
|
||||
addr_t const core_local_addr = reinterpret_cast<addr_t>(core_local_ptr);
|
||||
region_alloc().alloc_aligned(bytes, align).with_result(
|
||||
[&] (void *core_local_ptr) {
|
||||
|
||||
if (!map_local(phys_addr, core_local_addr, pages))
|
||||
return;
|
||||
if (!map_local(phys_addr, (addr_t)core_local_ptr, pages)) {
|
||||
warning("map_local failed while exporting ",
|
||||
rom_name, " as ROM module");
|
||||
ram_alloc().free(phys_ptr, bytes);
|
||||
region_alloc().free(core_local_ptr, bytes);
|
||||
return;
|
||||
}
|
||||
|
||||
memset(core_local_ptr, 0, size);
|
||||
memset(core_local_ptr, 0, bytes);
|
||||
content_fn((char *)core_local_ptr, bytes);
|
||||
|
||||
Xml_generator xml(reinterpret_cast<char *>(core_local_addr),
|
||||
pages << get_page_size_log2(),
|
||||
"platform_info", [&] ()
|
||||
{
|
||||
xml.node("kernel", [&] () {
|
||||
xml.attribute("name", "foc");
|
||||
xml.attribute("acpi", true);
|
||||
xml.attribute("msi" , true);
|
||||
_rom_fs.insert(new (core_mem_alloc())
|
||||
Rom_module(phys_addr, bytes, rom_name));
|
||||
},
|
||||
[&] (Range_allocator::Alloc_error) {
|
||||
warning("failed allocate virtual memory to export ",
|
||||
rom_name, " as ROM module");
|
||||
ram_alloc().free(phys_ptr, bytes);
|
||||
}
|
||||
);
|
||||
},
|
||||
[&] (Range_allocator::Alloc_error) {
|
||||
warning("failed to export ", rom_name, " as ROM module"); }
|
||||
);
|
||||
};
|
||||
|
||||
export_page_as_rom_module("platform_info",
|
||||
[&] (char *core_local_ptr, size_t size) {
|
||||
Xml_generator xml(core_local_ptr, size, "platform_info", [&] ()
|
||||
{
|
||||
xml.node("kernel", [&] () {
|
||||
xml.attribute("name", "foc");
|
||||
xml.attribute("acpi", true);
|
||||
xml.attribute("msi" , true);
|
||||
});
|
||||
xml.node("hardware", [&] () {
|
||||
_setup_platform_info(xml, sigma0_map_kip()); });
|
||||
|
||||
xml.node("affinity-space", [&] () {
|
||||
xml.attribute("width", affinity_space().width());
|
||||
xml.attribute("height", affinity_space().height()); });
|
||||
});
|
||||
xml.node("hardware", [&] () {
|
||||
_setup_platform_info(xml, sigma0_map_kip()); });
|
||||
}
|
||||
);
|
||||
|
||||
xml.node("affinity-space", [&] () {
|
||||
xml.attribute("width", affinity_space().width());
|
||||
xml.attribute("height", affinity_space().height()); });
|
||||
});
|
||||
|
||||
_rom_fs.insert(new (core_mem_alloc()) Rom_module(phys_addr, size,
|
||||
"platform_info"));
|
||||
}
|
||||
|
||||
/* core log as ROM module */
|
||||
{
|
||||
void * core_local_ptr = nullptr;
|
||||
void * phys_ptr = nullptr;
|
||||
unsigned const pages = 1;
|
||||
size_t const align = get_page_size_log2();
|
||||
size_t const size = pages << get_page_size_log2();
|
||||
|
||||
if (ram_alloc().alloc_aligned(size, &phys_ptr, align).error())
|
||||
return;
|
||||
if (region_alloc().alloc_aligned(size, &core_local_ptr, align).error())
|
||||
return;
|
||||
|
||||
addr_t const phys_addr = reinterpret_cast<addr_t>(phys_ptr);
|
||||
addr_t const core_local_addr = reinterpret_cast<addr_t>(core_local_ptr);
|
||||
|
||||
if (!map_local(phys_addr, core_local_addr, pages))
|
||||
return;
|
||||
|
||||
memset(core_local_ptr, 0, size);
|
||||
|
||||
_rom_fs.insert(new (core_mem_alloc()) Rom_module(phys_addr, size,
|
||||
"core_log"));
|
||||
|
||||
init_core_log(Core_log_range { core_local_addr, size } );
|
||||
}
|
||||
export_page_as_rom_module("core_log",
|
||||
[&] (char *core_local_ptr, size_t size) {
|
||||
init_core_log(Core_log_range { (addr_t)core_local_ptr, size } ); });
|
||||
|
||||
Affinity::Space const cpus = affinity_space();
|
||||
|
||||
|
||||
@@ -198,11 +198,9 @@ unsigned long Cap_id_allocator::alloc()
|
||||
{
|
||||
Mutex::Guard lock_guard(_mutex);
|
||||
|
||||
void *id = nullptr;
|
||||
if (_id_alloc.alloc(CAP_ID_OFFSET, &id))
|
||||
return (unsigned long) id;
|
||||
|
||||
throw Out_of_ids();
|
||||
return _id_alloc.try_alloc(CAP_ID_OFFSET).convert<unsigned long>(
|
||||
[&] (void *id) { return (unsigned long)id; },
|
||||
[&] (Range_allocator::Alloc_error) -> unsigned long { throw Out_of_ids(); });
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
arm_v8a
|
||||
@@ -1 +0,0 @@
|
||||
0x40010000
|
||||
@@ -1 +0,0 @@
|
||||
arm_v7a
|
||||
@@ -1 +0,0 @@
|
||||
0x00100000
|
||||
@@ -1,14 +0,0 @@
|
||||
REP_INC_DIR += src/bootstrap/board/zynq_qemu
|
||||
|
||||
SRC_S += bootstrap/spec/arm/crt0.s
|
||||
|
||||
SRC_CC += bootstrap/board/zynq_qemu/platform.cc
|
||||
SRC_CC += bootstrap/spec/arm/cpu.cc
|
||||
SRC_CC += bootstrap/spec/arm/cortex_a9_mmu.cc
|
||||
SRC_CC += bootstrap/spec/arm/gicv2.cc
|
||||
SRC_CC += bootstrap/spec/arm/arm_v7_cpu.cc
|
||||
SRC_CC += hw/spec/32bit/memory_map.cc
|
||||
|
||||
NR_OF_CPUS = 1
|
||||
|
||||
include $(call select_from_repositories,lib/mk/bootstrap-hw.inc)
|
||||
@@ -1,11 +0,0 @@
|
||||
#
|
||||
# \brief Build config for Genodes core process
|
||||
# \author Johannes Schlatow
|
||||
# \date 2014-12-15
|
||||
#
|
||||
|
||||
# add C++ sources
|
||||
SRC_CC += platform_services.cc
|
||||
|
||||
# include less specific configuration
|
||||
include $(call select_from_repositories,lib/mk/spec/cortex_a9/core-hw.inc)
|
||||
@@ -1,13 +0,0 @@
|
||||
#
|
||||
# \brief Build config for Genodes core process
|
||||
# \author Johannes Schlatow
|
||||
# \date 2014-12-15
|
||||
#
|
||||
|
||||
# add include paths
|
||||
REP_INC_DIR += src/core/board/zynq_qemu
|
||||
|
||||
NR_OF_CPUS = 1
|
||||
|
||||
# include less specific configuration
|
||||
include $(call select_from_repositories,lib/mk/spec/arm_v7/core-hw-zynq.inc)
|
||||
@@ -1,14 +0,0 @@
|
||||
REP_INC_DIR += src/bootstrap/board/imx8q_evk
|
||||
|
||||
SRC_CC += bootstrap/board/imx8q_evk/platform.cc
|
||||
SRC_CC += bootstrap/spec/arm/gicv3.cc
|
||||
SRC_CC += bootstrap/spec/arm_64/cortex_a53_mmu.cc
|
||||
SRC_CC += lib/base/arm_64/kernel/interface.cc
|
||||
SRC_CC += spec/64bit/memory_map.cc
|
||||
SRC_S += bootstrap/spec/arm_64/crt0.s
|
||||
|
||||
NR_OF_CPUS = 4
|
||||
|
||||
vpath spec/64bit/memory_map.cc $(call select_from_repositories,src/lib/hw)
|
||||
|
||||
include $(call select_from_repositories,lib/mk/bootstrap-hw.inc)
|
||||
@@ -1,19 +0,0 @@
|
||||
REP_INC_DIR += src/core/board/imx8q_evk
|
||||
REP_INC_DIR += src/core/spec/arm/virtualization
|
||||
|
||||
# add C++ sources
|
||||
SRC_CC += kernel/vm_thread_on.cc
|
||||
SRC_CC += spec/arm/gicv3.cc
|
||||
SRC_CC += spec/arm_v8/virtualization/kernel/vm.cc
|
||||
SRC_CC += spec/arm/virtualization/platform_services.cc
|
||||
SRC_CC += spec/arm/virtualization/vm_session_component.cc
|
||||
SRC_CC += vm_session_common.cc
|
||||
SRC_CC += vm_session_component.cc
|
||||
|
||||
#add assembly sources
|
||||
SRC_S += spec/arm_v8/virtualization/exception_vector.s
|
||||
|
||||
NR_OF_CPUS = 4
|
||||
|
||||
# include less specific configuration
|
||||
include $(call select_from_repositories,lib/mk/spec/arm_v8/core-hw.inc)
|
||||
@@ -1 +1 @@
|
||||
2021-10-13 11943f5bc31d6ebd43c67e008cf12cc7e2ca2934
|
||||
2021-11-29 b165dd50f62e2d73910c5ecf28315c6589368409
|
||||
|
||||
@@ -1 +1 @@
|
||||
2021-10-13 69215f704c6797b15bcacfc11a2709d5b65019e9
|
||||
2021-11-29 8640feb279f3a881867f809ae912975347c0b1b8
|
||||
|
||||
@@ -1 +1 @@
|
||||
2021-10-13 78f942508805ec6afc8d75550d5b67f38664b5f6
|
||||
2021-11-29 a01852908262310fc409888a30b4765af289aa31
|
||||
|
||||
@@ -1 +1 @@
|
||||
2021-10-13 85df38295bad953fc194078cc22d31f1acfa4c08
|
||||
2021-11-29 17cbcd9ba4667f79e4aba4798b413f081c22de40
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
include $(GENODE_DIR)/repos/base-hw/recipes/src/base-hw_content.inc
|
||||
@@ -1 +0,0 @@
|
||||
2021-10-13 e23737af156d1967b1d59c690b62f5538856a85c
|
||||
@@ -1,2 +0,0 @@
|
||||
base-hw
|
||||
base
|
||||
@@ -1 +1 @@
|
||||
2021-10-13 cf4e82d22cc8f343aa16f5b996e4cf3cc9608d69
|
||||
2021-11-29 dfa1d469c3fc106655d9a50920daffd1dd89677a
|
||||
|
||||
@@ -1 +1 @@
|
||||
2021-10-13 ec5754c900404b3d4e1594fa5e36630afb58df0e
|
||||
2021-11-29 fbf5af570d706af8f13ea996fd720c529d594497
|
||||
|
||||
@@ -1 +1 @@
|
||||
2021-10-13 910b8cd795a9326fc0b3fcd9afef8d35abd60c8b
|
||||
2021-11-29 52defb3af4f16f183ef35f5956079711053ff753
|
||||
|
||||
@@ -1 +1 @@
|
||||
2021-10-13 67dab318aac08eb348e660cfe11c711a9aea1198
|
||||
2021-11-29 065c3a960169cb275938c657083d377e8a86ad35
|
||||
|
||||
@@ -1 +1 @@
|
||||
2021-10-13 e43c142340fd7f0fcae846c5203c308fe50a979e
|
||||
2021-11-29 5e42f43a7df531cdf5c8cec4b8b292c930456955
|
||||
|
||||
@@ -1 +1 @@
|
||||
2021-10-13 ae6959ca0ea79c0b8611c7e4a56e5cdb634cfaf1
|
||||
2021-11-29 d458f8d92ed61428b73297d8b0e45de09e2e3456
|
||||
|
||||
@@ -1 +1 @@
|
||||
2021-10-13 0aed7db811134981a69cf1f4bb5cef3ba7e9a7c2
|
||||
2021-11-29 860f33fd363c0518df12ea1260b5140da88dbddf
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
include $(GENODE_DIR)/repos/base-hw/recipes/src/base-hw_content.inc
|
||||
@@ -1 +0,0 @@
|
||||
2021-10-13 3233ce8f7b5f3246ace4fbdf810b1632cb147a1a
|
||||
@@ -1,2 +0,0 @@
|
||||
base-hw
|
||||
base
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* \brief Board driver for bootstrap
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2019-06-12
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 _BOOTSTRAP__SPEC__IMX8Q_EVK__BOARD_H_
|
||||
#define _BOOTSTRAP__SPEC__IMX8Q_EVK__BOARD_H_
|
||||
|
||||
#include <hw/spec/arm_64/imx8q_evk_board.h>
|
||||
#include <hw/spec/arm_64/cpu.h>
|
||||
#include <hw/spec/arm/gicv3.h>
|
||||
#include <hw/spec/arm/lpae.h>
|
||||
|
||||
namespace Board {
|
||||
|
||||
using namespace Hw::Imx8q_evk_board;
|
||||
|
||||
struct Cpu : Hw::Arm_64_cpu
|
||||
{
|
||||
static void wake_up_all_cpus(void*);
|
||||
};
|
||||
|
||||
using Hw::Pic;
|
||||
};
|
||||
|
||||
#endif /* _BOOTSTRAP__SPEC__IMX8Q_EVK__BOARD_H_ */
|
||||
@@ -1,231 +0,0 @@
|
||||
/*
|
||||
* \brief Platform implementations specific for base-hw and i.MX8Q EVK
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2019-06-12
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <platform.h>
|
||||
|
||||
|
||||
/**
|
||||
* Leave out the first page (being 0x0) from bootstraps RAM allocator,
|
||||
* some code does not feel happy with addresses being zero
|
||||
*/
|
||||
Bootstrap::Platform::Board::Board()
|
||||
:
|
||||
early_ram_regions(Memory_region { ::Board::RAM_BASE, ::Board::RAM_SIZE }),
|
||||
late_ram_regions(Memory_region { }),
|
||||
core_mmio(Memory_region { ::Board::UART_BASE, ::Board::UART_SIZE },
|
||||
Memory_region { ::Board::Cpu_mmio::IRQ_CONTROLLER_DISTR_BASE,
|
||||
::Board::Cpu_mmio::IRQ_CONTROLLER_DISTR_SIZE },
|
||||
Memory_region { ::Board::Cpu_mmio::IRQ_CONTROLLER_REDIST_BASE,
|
||||
::Board::Cpu_mmio::IRQ_CONTROLLER_REDIST_SIZE })
|
||||
{
|
||||
::Board::Pic pic {};
|
||||
|
||||
static volatile unsigned long iomux_values[][2] {
|
||||
// IOMUXC
|
||||
{ 0x30330064, 0x6 },
|
||||
{ 0x30330140, 0x0 },
|
||||
{ 0x30330144, 0x0 },
|
||||
{ 0x30330148, 0x0 },
|
||||
{ 0x3033014C, 0x0 },
|
||||
{ 0x30330150, 0x0 },
|
||||
{ 0x30330154, 0x0 },
|
||||
{ 0x30330158, 0x0 },
|
||||
{ 0x30330180, 0x2 },
|
||||
{ 0x30330184, 0x0 },
|
||||
{ 0x30330188, 0x0 },
|
||||
{ 0x3033018C, 0x0 },
|
||||
{ 0x30330190, 0x0 },
|
||||
{ 0x30330194, 0x0 },
|
||||
{ 0x30330198, 0x0 },
|
||||
{ 0x3033019C, 0x0 },
|
||||
{ 0x303301A0, 0x0 },
|
||||
{ 0x303301A4, 0x0 },
|
||||
{ 0x303301A8, 0x0 },
|
||||
{ 0x303301AC, 0x0 },
|
||||
{ 0x303301BC, 0x0 },
|
||||
{ 0x303301C0, 0x0 },
|
||||
{ 0x303301C4, 0x0 },
|
||||
{ 0x303301C8, 0x0 },
|
||||
{ 0x303301E8, 0x0 },
|
||||
{ 0x303301EC, 0x0 },
|
||||
{ 0x303301FC, 0x1 },
|
||||
{ 0x30330200, 0x1 },
|
||||
{ 0x3033021C, 0x10 }, /* Enable SION I2c2_scl */
|
||||
{ 0x30330220, 0x10 }, /* Enable SION I2c2_sda */
|
||||
{ 0x30330224, 0x10 },
|
||||
{ 0x30330228, 0x10 },
|
||||
{ 0x3033022C, 0x12 },
|
||||
{ 0x30330230, 0x12 },
|
||||
{ 0x30330244, 0x0 },
|
||||
{ 0x30330248, 0x0 },
|
||||
{ 0x3033029C, 0x19 },
|
||||
{ 0x303302A4, 0x19 },
|
||||
{ 0x303302A8, 0x19 },
|
||||
{ 0x303302B0, 0xD6 },
|
||||
{ 0x303302C0, 0x4F },
|
||||
{ 0x303302C4, 0x16 },
|
||||
{ 0x303302CC, 0x59 },
|
||||
{ 0x30330308, 0x9F },
|
||||
{ 0x3033030C, 0xDF },
|
||||
{ 0x30330310, 0xDF },
|
||||
{ 0x30330314, 0xDF },
|
||||
{ 0x30330318, 0xDF },
|
||||
{ 0x3033031C, 0xDF },
|
||||
{ 0x30330320, 0xDF },
|
||||
{ 0x30330324, 0xDF },
|
||||
{ 0x30330328, 0xDF },
|
||||
{ 0x3033032C, 0xDF },
|
||||
{ 0x30330334, 0x9f },
|
||||
{ 0x3033033C, 0x83 },
|
||||
{ 0x30330340, 0xC3 },
|
||||
{ 0x30330344, 0xC3 },
|
||||
{ 0x30330348, 0xC3 },
|
||||
{ 0x3033034C, 0xC3 },
|
||||
{ 0x30330350, 0xC3 },
|
||||
{ 0x30330368, 0x59 },
|
||||
{ 0x30330370, 0x19 },
|
||||
{ 0x3033039C, 0x19 },
|
||||
{ 0x303303A0, 0x19 },
|
||||
{ 0x303303A4, 0x19 },
|
||||
{ 0x303303A8, 0xD6 },
|
||||
{ 0x303303AC, 0xD6 },
|
||||
{ 0x303303B0, 0xD6 },
|
||||
{ 0x303303B4, 0xD6 },
|
||||
{ 0x303303B8, 0xD6 },
|
||||
{ 0x303303BC, 0xD6 },
|
||||
{ 0x303303C0, 0xD6 },
|
||||
{ 0x303303E8, 0xD6 },
|
||||
{ 0x303303EC, 0xD6 },
|
||||
{ 0x303303F0, 0xD6 },
|
||||
{ 0x303303F4, 0xD6 },
|
||||
{ 0x303303F8, 0xD6 },
|
||||
{ 0x303303FC, 0xD6 },
|
||||
{ 0x30330400, 0xD6 },
|
||||
{ 0x30330404, 0xD6 },
|
||||
{ 0x30330408, 0xD6 },
|
||||
{ 0x3033040C, 0xD6 },
|
||||
{ 0x30330410, 0xD6 },
|
||||
{ 0x30330414, 0xD6 },
|
||||
{ 0x30330424, 0xD6 },
|
||||
{ 0x30330428, 0xD6 },
|
||||
{ 0x3033042C, 0xD6 },
|
||||
{ 0x30330430, 0xD6 },
|
||||
{ 0x30330450, 0xD6 },
|
||||
{ 0x30330454, 0xD6 },
|
||||
{ 0x30330460, 0x19 },
|
||||
{ 0x30330464, 0x49 },
|
||||
{ 0x30330468, 0x49 },
|
||||
{ 0x3033046C, 0x16 },
|
||||
{ 0x30330484, 0x67 }, /* I2c2_scl pullup resistor 40 ohm */
|
||||
{ 0x30330488, 0x67 }, /* I2c2_sda pullup resistor 40 ohm */
|
||||
{ 0x3033048C, 0x67 },
|
||||
{ 0x30330490, 0x67 },
|
||||
{ 0x30330494, 0x76 },
|
||||
{ 0x30330498, 0x76 },
|
||||
{ 0x3033049C, 0x49 },
|
||||
{ 0x303304A0, 0x49 },
|
||||
{ 0x303304AC, 0x49 },
|
||||
{ 0x303304B0, 0x49 },
|
||||
{ 0x303304C8, 0x1 },
|
||||
{ 0x303304CC, 0x4 },
|
||||
{ 0x30330500, 0x1 },
|
||||
{ 0x30330504, 0x2 },
|
||||
{ 0x30340038, 0x49409600 },
|
||||
{ 0x30340040, 0x49409200 },
|
||||
{ 0x30340034, 0x4 }, /* MIPI mux selector */
|
||||
/*
|
||||
{ 0x30340060, 0x180800 },
|
||||
{ 0x30340064, 0x6400520 },
|
||||
{ 0x30340068, 0x0A }, */
|
||||
};
|
||||
|
||||
struct Gpio_reg : Genode::Mmio
|
||||
{
|
||||
Gpio_reg(Genode::addr_t const mmio_base)
|
||||
: Genode::Mmio(mmio_base) { }
|
||||
|
||||
struct Data : Register<0x0, 32> {};
|
||||
struct Dir : Register<0x4, 32> {};
|
||||
struct Int_conf_0 : Register<0xc, 32> {};
|
||||
struct Int_conf_1 : Register<0x10, 32> {};
|
||||
struct Int_mask : Register<0x14, 32> {};
|
||||
struct Int_stat : Register<0x18, 32> {};
|
||||
};
|
||||
|
||||
struct Ccm_reg : Genode::Mmio
|
||||
{
|
||||
Ccm_reg(Genode::addr_t const mmio_base)
|
||||
: Genode::Mmio(mmio_base) { }
|
||||
|
||||
struct Target_root_0 : Register<0x8000, 32> {};
|
||||
};
|
||||
|
||||
struct Pll_reg : Genode::Mmio
|
||||
{
|
||||
Pll_reg(Genode::addr_t const mmio_base)
|
||||
: Genode::Mmio(mmio_base) { }
|
||||
|
||||
struct Pll_arm_0 : Register<0x28, 32> {};
|
||||
struct Pll_arm_1 : Register<0x2c, 32> {};
|
||||
};
|
||||
|
||||
unsigned num_values = sizeof(iomux_values) / (2*sizeof(unsigned long));
|
||||
for (unsigned i = 0; i < num_values; i++)
|
||||
*((volatile Genode::uint32_t*)iomux_values[i][0]) = (Genode::uint32_t)iomux_values[i][1];
|
||||
|
||||
|
||||
Ccm_reg ccm(0x30380000);
|
||||
Ccm_reg pll(0x30360000);
|
||||
|
||||
/* configure GPIO PIN 13 of GPIO 1 for high voltage */
|
||||
Gpio_reg regulator(0x30200000);
|
||||
regulator.write<Gpio_reg::Int_conf_0>(0);
|
||||
regulator.write<Gpio_reg::Int_conf_1>(0);
|
||||
regulator.write<Gpio_reg::Int_mask>(0x1000);
|
||||
regulator.write<Gpio_reg::Int_stat>(0xffffffff);
|
||||
regulator.write<Gpio_reg::Dir>(0x2328);
|
||||
regulator.write<Gpio_reg::Data>(0x9f40);
|
||||
|
||||
ccm.write<Ccm_reg::Target_root_0>(0x14000000);
|
||||
pll.write<Pll_reg::Pll_arm_1>(0x4a);
|
||||
|
||||
unsigned long v = pll.read<Pll_reg::Pll_arm_0>();
|
||||
pll.write<Pll_reg::Pll_arm_0>(v & 0xffffffe0);
|
||||
v = pll.read<Pll_reg::Pll_arm_0>();
|
||||
pll.write<Pll_reg::Pll_arm_0>(v | (1<<12));
|
||||
|
||||
while (!(pll.read<Pll_reg::Pll_arm_0>() & (1<<11))) { ; }
|
||||
|
||||
v = pll.read<Pll_reg::Pll_arm_0>();
|
||||
pll.write<Pll_reg::Pll_arm_0>(v ^ (1<<12));
|
||||
ccm.write<Ccm_reg::Target_root_0>(0x11000000);
|
||||
}
|
||||
|
||||
|
||||
void Board::Cpu::wake_up_all_cpus(void * ip)
|
||||
{
|
||||
enum Function_id { CPU_ON = 0xC4000003 };
|
||||
|
||||
unsigned long result = 0;
|
||||
for (unsigned i = 1; i < NR_OF_CPUS; i++) {
|
||||
asm volatile("mov x0, %1 \n"
|
||||
"mov x1, %2 \n"
|
||||
"mov x2, %3 \n"
|
||||
"mov x3, %2 \n"
|
||||
"smc #0 \n"
|
||||
"mov %0, x0 \n"
|
||||
: "=r" (result) : "r" (CPU_ON), "r" (i), "r" (ip)
|
||||
: "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
|
||||
"x8", "x9", "x10", "x11", "x12", "x13", "x14");
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* \brief Zynq 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__ZYNQ__BOARD_H_
|
||||
#define _SRC__BOOTSTRAP__SPEC__ZYNQ__BOARD_H_
|
||||
|
||||
#include <hw/spec/arm/zynq_qemu_board.h>
|
||||
#include <spec/arm/cortex_a9_actlr.h>
|
||||
#include <spec/arm/cortex_a9_page_table.h>
|
||||
#include <spec/arm/cpu.h>
|
||||
#include <hw/spec/arm/gicv2.h>
|
||||
|
||||
namespace Board {
|
||||
|
||||
using namespace Hw::Zynq_qemu_board;
|
||||
using Pic = Hw::Gicv2;
|
||||
static constexpr bool NON_SECURE = false;
|
||||
}
|
||||
|
||||
#endif /* _SRC__BOOTSTRAP__SPEC__ZYNQ__BOARD_H_ */
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* \brief Platform implementations specific for base-hw and Zynq
|
||||
* \author Johannes Schlatow
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2014-12-15
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* core includes */
|
||||
#include <platform.h>
|
||||
|
||||
using namespace Board;
|
||||
|
||||
|
||||
Bootstrap::Platform::Board::Board()
|
||||
:
|
||||
early_ram_regions(Memory_region { RAM_0_BASE + 0x1000,
|
||||
RAM_0_SIZE - 0x1000 }),
|
||||
late_ram_regions(Memory_region { RAM_0_BASE, 0x1000 }),
|
||||
core_mmio(Memory_region { CORTEX_A9_PRIVATE_MEM_BASE,
|
||||
CORTEX_A9_PRIVATE_MEM_SIZE },
|
||||
Memory_region { UART_BASE,
|
||||
UART_SIZE },
|
||||
Memory_region { PL310_MMIO_BASE,
|
||||
PL310_MMIO_SIZE })
|
||||
{ }
|
||||
|
||||
|
||||
bool Cpu::errata(Board::Cpu::Errata) { return false; }
|
||||
|
||||
|
||||
void Cpu::wake_up_all_cpus(void* ip)
|
||||
{
|
||||
struct Wakeup_generator : Genode::Mmio
|
||||
{
|
||||
struct Core1_boot_addr : Register<0x0, 32> { };
|
||||
|
||||
Wakeup_generator(void * const ip) : Mmio(CORE1_ENTRY)
|
||||
{
|
||||
write<Core1_boot_addr>((Genode::addr_t)ip);
|
||||
}
|
||||
};
|
||||
|
||||
Wakeup_generator wgen(ip);
|
||||
asm volatile("dsb\n"
|
||||
"sev\n");
|
||||
}
|
||||
@@ -30,19 +30,16 @@ extern unsigned _bss_end;
|
||||
void * Platform::Ram_allocator::alloc_aligned(size_t size, unsigned align)
|
||||
{
|
||||
using namespace Genode;
|
||||
using namespace Hw;
|
||||
|
||||
void * ret;
|
||||
assert(Base::alloc_aligned(round_page(size), &ret,
|
||||
max(align, get_page_size_log2())).ok());
|
||||
return ret;
|
||||
}
|
||||
return Base::alloc_aligned(Hw::round_page(size),
|
||||
max(align, get_page_size_log2())).convert<void *>(
|
||||
|
||||
|
||||
bool Platform::Ram_allocator::alloc(size_t size, void **out_addr)
|
||||
{
|
||||
*out_addr = alloc_aligned(size, 0);
|
||||
return true;
|
||||
[&] (void *ptr) { return ptr; },
|
||||
[&] (Ram_allocator::Alloc_error e) -> void *
|
||||
{
|
||||
error("bootstrap RAM allocation failed, error=", e);
|
||||
assert(false);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -53,8 +53,13 @@ class Bootstrap::Platform
|
||||
};
|
||||
|
||||
|
||||
class Ram_allocator : public Genode::Allocator_avl_base
|
||||
class Ram_allocator : private Genode::Allocator_avl_base
|
||||
{
|
||||
/*
|
||||
* 'Ram_allocator' is derived from 'Allocator_avl_base' to access
|
||||
* the protected 'slab_block_size'.
|
||||
*/
|
||||
|
||||
private:
|
||||
|
||||
using Base = Genode::Allocator_avl_base;
|
||||
@@ -73,8 +78,7 @@ class Bootstrap::Platform
|
||||
{ }
|
||||
|
||||
void * alloc_aligned(size_t size, unsigned align);
|
||||
bool alloc(size_t size, void **out_addr) override;
|
||||
void * alloc(size_t size) { return Allocator::alloc(size); }
|
||||
void * alloc(size_t size) { return alloc_aligned(size, 0); }
|
||||
|
||||
void add(Memory_region const &);
|
||||
void remove(Memory_region const &);
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* \brief Board driver for core
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2019-06-12
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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__IMX8Q_EVK__BOARD_H_
|
||||
#define _CORE__SPEC__IMX8Q_EVK__BOARD_H_
|
||||
|
||||
/* base-hw internal includes */
|
||||
#include <hw/spec/arm_64/imx8q_evk_board.h>
|
||||
|
||||
/* base-hw Core includes */
|
||||
#include <spec/arm/generic_timer.h>
|
||||
#include <spec/arm/virtualization/gicv3.h>
|
||||
#include <spec/arm_v8/cpu.h>
|
||||
|
||||
/* base-hw includes */
|
||||
#include <spec/arm_64/cpu/vm_state_virtualization.h>
|
||||
|
||||
/* base-hw Core includes */
|
||||
#include <spec/arm/virtualization/board.h>
|
||||
|
||||
namespace Board {
|
||||
|
||||
using namespace Hw::Imx8q_evk_board;
|
||||
|
||||
enum {
|
||||
TIMER_IRQ = 14 + 16,
|
||||
VT_TIMER_IRQ = 11 + 16,
|
||||
VT_MAINTAINANCE_IRQ = 9 + 16,
|
||||
VCPU_MAX = 16
|
||||
};
|
||||
};
|
||||
|
||||
#endif /* _CORE__SPEC__IMX8Q_EVK__BOARD_H_ */
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* \brief Board driver for core on Zynq
|
||||
* \author Johannes Schlatow
|
||||
* \author Stefan Kalkowski
|
||||
* \author Martin Stein
|
||||
* \date 2014-06-02
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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__ZYNQ_QEMU__BOARD_H_
|
||||
#define _CORE__SPEC__ZYNQ_QEMU__BOARD_H_
|
||||
|
||||
/* base-hw internal includes */
|
||||
#include <hw/spec/arm/gicv2.h>
|
||||
#include <hw/spec/arm/zynq_qemu_board.h>
|
||||
|
||||
/* base-hw Core includes */
|
||||
#include <spec/arm/cortex_a9_private_timer.h>
|
||||
#include <spec/cortex_a9/cpu.h>
|
||||
|
||||
namespace Board {
|
||||
|
||||
using namespace Hw::Zynq_qemu_board;
|
||||
|
||||
class Global_interrupt_controller { };
|
||||
class Pic : public Hw::Gicv2 { public: Pic(Global_interrupt_controller &) { } };
|
||||
|
||||
L2_cache & l2_cache();
|
||||
}
|
||||
|
||||
#endif /* _CORE__SPEC__ZYNQ_QEMU__BOARD_H_ */
|
||||
@@ -29,12 +29,15 @@ 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)
|
||||
{
|
||||
auto lambda = [&] (Dataspace_component *ds) -> Local_addr {
|
||||
if (!ds)
|
||||
return _ep.apply(ds_cap, [&] (Dataspace_component *ds_ptr) -> Local_addr {
|
||||
|
||||
if (!ds_ptr)
|
||||
throw Invalid_dataspace();
|
||||
|
||||
Dataspace_component &ds = *ds_ptr;
|
||||
|
||||
if (size == 0)
|
||||
size = ds->size();
|
||||
size = ds.size();
|
||||
|
||||
size_t page_rounded_size = (size + get_page_size() - 1) & get_page_mask();
|
||||
|
||||
@@ -48,10 +51,13 @@ Core_region_map::attach(Dataspace_capability ds_cap, size_t size,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
unsigned const align = get_page_size_log2();
|
||||
|
||||
/* allocate range in core's virtual address space */
|
||||
void *virt_addr;
|
||||
if (!platform().region_alloc().alloc_aligned(page_rounded_size, &virt_addr,
|
||||
get_page_size_log2()).ok()) {
|
||||
Allocator::Alloc_result 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;
|
||||
@@ -61,16 +67,23 @@ Core_region_map::attach(Dataspace_capability ds_cap, size_t size,
|
||||
|
||||
/* map the dataspace's physical pages to corresponding virtual addresses */
|
||||
unsigned num_pages = page_rounded_size >> get_page_size_log2();
|
||||
Page_flags const flags { (writeable && ds->writable()) ? RW : RO,
|
||||
Page_flags const flags { (writeable && ds.writable()) ? RW : RO,
|
||||
NO_EXEC, KERN, GLOBAL,
|
||||
ds->io_mem() ? DEVICE : RAM,
|
||||
ds->cacheability() };
|
||||
if (!map_local(ds->phys_addr(), (addr_t)virt_addr, num_pages, flags))
|
||||
return nullptr;
|
||||
ds.io_mem() ? DEVICE : RAM,
|
||||
ds.cacheability() };
|
||||
|
||||
return virt_addr;
|
||||
};
|
||||
return _ep.apply(ds_cap, lambda);
|
||||
return virt.convert<Local_addr>(
|
||||
|
||||
[&] (void *virt_addr) -> void * {
|
||||
if (map_local(ds.phys_addr(), (addr_t)virt_addr, num_pages, flags))
|
||||
return virt_addr;
|
||||
|
||||
platform().region_alloc().free(virt_addr, page_rounded_size);
|
||||
return nullptr; },
|
||||
|
||||
[&] (Allocator::Alloc_error) {
|
||||
return nullptr; });
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -57,8 +57,8 @@ class Genode::Cpu_thread_allocator : public Allocator
|
||||
** Allocator interface **
|
||||
*************************/
|
||||
|
||||
bool alloc(size_t size, void **out_addr) override {
|
||||
return _alloc.alloc(size, out_addr); }
|
||||
Alloc_result try_alloc(size_t size) override {
|
||||
return _alloc.alloc(size); }
|
||||
|
||||
void free(void *addr, size_t size) override {
|
||||
_alloc.free(addr, size); }
|
||||
|
||||
@@ -78,7 +78,7 @@ Irq_session_component::Irq_session_component(Range_allocator &irq_alloc,
|
||||
}
|
||||
|
||||
/* allocate interrupt */
|
||||
if (_irq_alloc.alloc_addr(1, _irq_number).error()) {
|
||||
if (_irq_alloc.alloc_addr(1, _irq_number).failed()) {
|
||||
error("unavailable interrupt ", _irq_number, " requested");
|
||||
throw Service_denied();
|
||||
}
|
||||
|
||||
@@ -35,10 +35,41 @@ using namespace Kernel;
|
||||
|
||||
void Thread::_ipc_alloc_recv_caps(unsigned cap_count)
|
||||
{
|
||||
Genode::Allocator &slab = pd().platform_pd().capability_slab();
|
||||
using Allocator = Genode::Allocator;
|
||||
|
||||
Allocator &slab = pd().platform_pd().capability_slab();
|
||||
for (unsigned i = 0; i < cap_count; i++) {
|
||||
if (_obj_id_ref_ptr[i] == nullptr)
|
||||
_obj_id_ref_ptr[i] = slab.alloc(sizeof(Object_identity_reference));
|
||||
if (_obj_id_ref_ptr[i] != nullptr)
|
||||
continue;
|
||||
|
||||
slab.try_alloc(sizeof(Object_identity_reference)).with_result(
|
||||
|
||||
[&] (void *ptr) {
|
||||
_obj_id_ref_ptr[i] = ptr; },
|
||||
|
||||
[&] (Allocator::Alloc_error e) {
|
||||
|
||||
switch (e) {
|
||||
case Allocator::Alloc_error::DENIED:
|
||||
|
||||
/*
|
||||
* Slab is exhausted, reflect condition to the client.
|
||||
*/
|
||||
throw Genode::Out_of_ram();
|
||||
|
||||
case Allocator::Alloc_error::OUT_OF_CAPS:
|
||||
case Allocator::Alloc_error::OUT_OF_RAM:
|
||||
|
||||
/*
|
||||
* These conditions cannot happen because the slab
|
||||
* does not try to grow automatically. It is
|
||||
* explicitely expanded by the client as response to
|
||||
* the 'Out_of_ram' condition above.
|
||||
*/
|
||||
Genode::raw("unexpected recv_caps allocation failure");
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
_ipc_rcv_caps = cap_count;
|
||||
}
|
||||
|
||||
@@ -112,28 +112,46 @@ void Platform::_init_platform_info()
|
||||
{
|
||||
unsigned const pages = 1;
|
||||
size_t const rom_size = pages << get_page_size_log2();
|
||||
void *phys_ptr = nullptr;
|
||||
void *virt_ptr = nullptr;
|
||||
const char *rom_name = "platform_info";
|
||||
|
||||
if (!ram_alloc().alloc(get_page_size(), &phys_ptr)) {
|
||||
error("could not setup platform_info ROM - ram allocation error");
|
||||
return;
|
||||
}
|
||||
struct Guard
|
||||
{
|
||||
Range_allocator &phys_alloc;
|
||||
Range_allocator &virt_alloc;
|
||||
|
||||
if (!region_alloc().alloc(rom_size, &virt_ptr)) {
|
||||
error("could not setup platform_info ROM - region allocation error");
|
||||
ram_alloc().free(phys_ptr);
|
||||
return;
|
||||
}
|
||||
struct {
|
||||
void *phys_ptr = nullptr;
|
||||
void *virt_ptr = nullptr;
|
||||
};
|
||||
|
||||
addr_t const phys_addr = reinterpret_cast<addr_t>(phys_ptr);
|
||||
addr_t const virt_addr = reinterpret_cast<addr_t>(virt_ptr);
|
||||
Guard(Range_allocator &phys_alloc, Range_allocator &virt_alloc)
|
||||
: phys_alloc(phys_alloc), virt_alloc(virt_alloc) { }
|
||||
|
||||
~Guard()
|
||||
{
|
||||
if (phys_ptr) phys_alloc.free(phys_ptr);
|
||||
if (virt_ptr) virt_alloc.free(phys_ptr);
|
||||
}
|
||||
} guard { ram_alloc(), region_alloc() };
|
||||
|
||||
ram_alloc().try_alloc(get_page_size()).with_result(
|
||||
[&] (void *ptr) { guard.phys_ptr = ptr; },
|
||||
[&] (Allocator::Alloc_error) {
|
||||
error("could not setup platform_info ROM - RAM allocation error"); });
|
||||
|
||||
region_alloc().try_alloc(rom_size).with_result(
|
||||
[&] (void *ptr) { guard.virt_ptr = ptr; },
|
||||
[&] (Allocator::Alloc_error) {
|
||||
error("could not setup platform_info ROM - region allocation error"); });
|
||||
|
||||
if (!guard.phys_ptr || !guard.virt_ptr)
|
||||
return;
|
||||
|
||||
addr_t const phys_addr = reinterpret_cast<addr_t>(guard.phys_ptr);
|
||||
addr_t const virt_addr = reinterpret_cast<addr_t>(guard.virt_ptr);
|
||||
|
||||
if (!map_local(phys_addr, virt_addr, pages, Hw::PAGE_FLAGS_KERN_DATA)) {
|
||||
error("could not setup platform_info ROM - map error");
|
||||
region_alloc().free(virt_ptr);
|
||||
ram_alloc().free(phys_ptr);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -156,10 +174,11 @@ void Platform::_init_platform_info()
|
||||
return;
|
||||
}
|
||||
|
||||
region_alloc().free(virt_ptr);
|
||||
|
||||
_rom_fs.insert(
|
||||
new (core_mem_alloc()) Rom_module(phys_addr, rom_size, rom_name));
|
||||
|
||||
/* keep phys allocation but let guard revert virt allocation */
|
||||
guard.phys_ptr = nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -203,25 +222,32 @@ Platform::Platform()
|
||||
|
||||
/* core log as ROM module */
|
||||
{
|
||||
void * core_local_ptr = nullptr;
|
||||
void * phys_ptr = nullptr;
|
||||
unsigned const pages = 1;
|
||||
size_t const log_size = pages << get_page_size_log2();
|
||||
unsigned const align = get_page_size_log2();
|
||||
|
||||
ram_alloc().alloc_aligned(log_size, &phys_ptr, get_page_size_log2());
|
||||
addr_t const phys_addr = reinterpret_cast<addr_t>(phys_ptr);
|
||||
ram_alloc().alloc_aligned(log_size, align).with_result(
|
||||
|
||||
/* let one page free after the log buffer */
|
||||
region_alloc().alloc_aligned(log_size, &core_local_ptr, get_page_size_log2());
|
||||
addr_t const core_local_addr = reinterpret_cast<addr_t>(core_local_ptr);
|
||||
[&] (void *phys) {
|
||||
addr_t const phys_addr = reinterpret_cast<addr_t>(phys);
|
||||
|
||||
map_local(phys_addr, core_local_addr, pages);
|
||||
memset(core_local_ptr, 0, log_size);
|
||||
region_alloc().alloc_aligned(log_size, align). with_result(
|
||||
|
||||
_rom_fs.insert(new (core_mem_alloc()) Rom_module(phys_addr, log_size,
|
||||
"core_log"));
|
||||
[&] (void *ptr) {
|
||||
|
||||
init_core_log(Core_log_range { core_local_addr, log_size } );
|
||||
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"));
|
||||
|
||||
init_core_log(Core_log_range { (addr_t)ptr, log_size } );
|
||||
},
|
||||
[&] (Range_allocator::Alloc_error) { /* ignored */ }
|
||||
);
|
||||
},
|
||||
[&] (Range_allocator::Alloc_error) { }
|
||||
);
|
||||
}
|
||||
|
||||
class Idle_thread_trace_source : public Trace::Source::Info_accessor,
|
||||
|
||||
@@ -37,11 +37,16 @@ Core_mem_allocator &Hw::Address_space::_cma()
|
||||
|
||||
void *Hw::Address_space::_table_alloc()
|
||||
{
|
||||
void * ret = nullptr;
|
||||
if (!_cma().alloc_aligned(sizeof(Page_table), (void**)&ret,
|
||||
Page_table::ALIGNM_LOG2).ok())
|
||||
throw Insufficient_ram_quota();
|
||||
return ret;
|
||||
unsigned const align = Page_table::ALIGNM_LOG2;
|
||||
|
||||
return _cma().alloc_aligned(sizeof(Page_table), align).convert<void *>(
|
||||
|
||||
[&] (void *ptr) {
|
||||
return ptr; },
|
||||
|
||||
[&] (Range_allocator::Alloc_result) -> void * {
|
||||
/* XXX distinguish error conditions */
|
||||
throw Insufficient_ram_quota(); });
|
||||
}
|
||||
|
||||
|
||||
@@ -134,10 +139,15 @@ Cap_space::Cap_space() : _slab(nullptr, &_initial_sb) { }
|
||||
|
||||
void Cap_space::upgrade_slab(Allocator &alloc)
|
||||
{
|
||||
void * block = nullptr;
|
||||
if (!alloc.alloc(SLAB_SIZE, &block))
|
||||
throw Out_of_ram();
|
||||
_slab.insert_sb(block);
|
||||
alloc.try_alloc(SLAB_SIZE).with_result(
|
||||
|
||||
[&] (void *ptr) {
|
||||
_slab.insert_sb(ptr); },
|
||||
|
||||
[&] (Allocator::Alloc_error) {
|
||||
/* XXX distinguish error conditions */
|
||||
throw Out_of_ram();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -71,13 +71,18 @@ Platform_thread::Platform_thread(Label const &label, Native_utcb &utcb)
|
||||
_kobj(_kobj.CALLED_FROM_CORE, _label.string())
|
||||
{
|
||||
/* create UTCB for a core thread */
|
||||
void *utcb_phys;
|
||||
if (!platform().ram_alloc().alloc(sizeof(Native_utcb), &utcb_phys)) {
|
||||
error("failed to allocate UTCB");
|
||||
throw Out_of_ram();
|
||||
}
|
||||
map_local((addr_t)utcb_phys, (addr_t)_utcb_core_addr,
|
||||
sizeof(Native_utcb) / get_page_size());
|
||||
platform().ram_alloc().try_alloc(sizeof(Native_utcb)).with_result(
|
||||
|
||||
[&] (void *utcb_phys) {
|
||||
map_local((addr_t)utcb_phys, (addr_t)_utcb_core_addr,
|
||||
sizeof(Native_utcb) / get_page_size());
|
||||
},
|
||||
[&] (Range_allocator::Alloc_error) {
|
||||
error("failed to allocate UTCB");
|
||||
/* XXX distinguish error conditions */
|
||||
throw Out_of_ram();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -33,30 +33,40 @@ void Ram_dataspace_factory::_clear_ds (Dataspace_component &ds)
|
||||
{
|
||||
size_t page_rounded_size = (ds.size() + get_page_size() - 1) & get_page_mask();
|
||||
|
||||
struct Guard
|
||||
{
|
||||
Range_allocator &virt_alloc;
|
||||
struct { void *virt_ptr = nullptr; };
|
||||
|
||||
Guard(Range_allocator &virt_alloc) : virt_alloc(virt_alloc) { }
|
||||
|
||||
~Guard() { if (virt_ptr) virt_alloc.free(virt_ptr); }
|
||||
|
||||
} guard(platform().region_alloc());
|
||||
|
||||
/* allocate range in core's virtual address space */
|
||||
void *virt_addr;
|
||||
if (!platform().region_alloc().alloc(page_rounded_size, &virt_addr)) {
|
||||
error("could not allocate virtual address range in core of size ",
|
||||
page_rounded_size);
|
||||
platform().region_alloc().try_alloc(page_rounded_size).with_result(
|
||||
[&] (void *ptr) { guard.virt_ptr = ptr; },
|
||||
[&] (Range_allocator::Alloc_error e) {
|
||||
error("could not allocate virtual address range in core of size ",
|
||||
page_rounded_size, ", error=", e); });
|
||||
|
||||
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)virt_addr, num_pages)) {
|
||||
if (!map_local(ds.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)virt_addr, page_rounded_size,
|
||||
Cpu::clear_memory_region((addr_t)guard.virt_ptr, page_rounded_size,
|
||||
ds.cacheability() != CACHED);
|
||||
|
||||
/* unmap dataspace from core */
|
||||
if (!unmap_local((addr_t)virt_addr, num_pages))
|
||||
error("could not unmap core-local address range at ", virt_addr);
|
||||
|
||||
/* free core's virtual address space */
|
||||
platform().region_alloc().free(virt_addr, page_rounded_size);
|
||||
if (!unmap_local((addr_t)guard.virt_ptr, num_pages))
|
||||
error("could not unmap core-local address range at ", guard.virt_ptr);
|
||||
}
|
||||
|
||||
|
||||
@@ -86,22 +86,28 @@ class Genode::Rpc_cap_factory
|
||||
{
|
||||
Mutex::Guard guard(_mutex);
|
||||
|
||||
/* allocate kernel object */
|
||||
Kobject * obj;
|
||||
if (!_slab.alloc(sizeof(Kobject), (void**)&obj))
|
||||
throw Allocator::Out_of_memory();
|
||||
construct_at<Kobject>(obj, ep);
|
||||
return _slab.try_alloc(sizeof(Kobject)).convert<Native_capability>(
|
||||
|
||||
if (!obj->cap.valid()) {
|
||||
raw("Invalid entrypoint ", (addr_t)Capability_space::capid(ep),
|
||||
" for allocating a capability!");
|
||||
destroy(&_slab, obj);
|
||||
return Native_capability();
|
||||
}
|
||||
[&] (void *ptr) {
|
||||
|
||||
/* store it in the list and return result */
|
||||
_list.insert(obj);
|
||||
return obj->cap;
|
||||
/* create kernel object */
|
||||
Kobject &obj = *construct_at<Kobject>(ptr, ep);
|
||||
|
||||
if (!obj.cap.valid()) {
|
||||
raw("Invalid entrypoint ", (addr_t)Capability_space::capid(ep),
|
||||
" for allocating a capability!");
|
||||
destroy(&_slab, &obj);
|
||||
return Native_capability();
|
||||
}
|
||||
|
||||
/* store it in the list and return result */
|
||||
_list.insert(&obj);
|
||||
return obj.cap;
|
||||
},
|
||||
[&] (Allocator::Alloc_error) -> Native_capability {
|
||||
/* XXX distinguish error conditions */
|
||||
throw Allocator::Out_of_memory();
|
||||
});
|
||||
}
|
||||
|
||||
void free(Native_capability cap)
|
||||
|
||||
@@ -43,16 +43,20 @@ void Genode::platform_add_local_services(Rpc_entrypoint &ep,
|
||||
Hw::Mm::hypervisor_exception_vector().size / get_page_size(),
|
||||
Hw::PAGE_FLAGS_KERN_TEXT);
|
||||
|
||||
void * stack = nullptr;
|
||||
assert(platform().ram_alloc().alloc_aligned(Hw::Mm::hypervisor_stack().size,
|
||||
(void**)&stack,
|
||||
get_page_size_log2()).ok());
|
||||
map_local((addr_t)stack,
|
||||
Hw::Mm::hypervisor_stack().base,
|
||||
Hw::Mm::hypervisor_stack().size / get_page_size(),
|
||||
Hw::PAGE_FLAGS_KERN_DATA);
|
||||
platform().ram_alloc().alloc_aligned(Hw::Mm::hypervisor_stack().size,
|
||||
get_page_size_log2()).with_result(
|
||||
[&] (void *stack) {
|
||||
map_local((addr_t)stack,
|
||||
Hw::Mm::hypervisor_stack().base,
|
||||
Hw::Mm::hypervisor_stack().size / get_page_size(),
|
||||
Hw::PAGE_FLAGS_KERN_DATA);
|
||||
|
||||
static Vm_root vm_root(ep, sh, core_env().ram_allocator(),
|
||||
core_env().local_rm(), trace_sources);
|
||||
static Core_service<Vm_session_component> vm_service(services, vm_root);
|
||||
static Vm_root vm_root(ep, sh, core_env().ram_allocator(),
|
||||
core_env().local_rm(), trace_sources);
|
||||
static Core_service<Vm_session_component> vm_service(services, vm_root);
|
||||
},
|
||||
[&] (Range_allocator::Alloc_error) {
|
||||
warning("failed to allocate hypervisor stack for VM service");
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -73,14 +73,17 @@ void Vm_session_component::_detach_vm_memory(addr_t vm_addr, size_t size)
|
||||
|
||||
void * Vm_session_component::_alloc_table()
|
||||
{
|
||||
void * table;
|
||||
/* get some aligned space for the translation table */
|
||||
if (!cma().alloc_aligned(sizeof(Board::Vm_page_table), (void**)&table,
|
||||
Board::Vm_page_table::ALIGNM_LOG2).ok()) {
|
||||
error("failed to allocate kernel object");
|
||||
throw Insufficient_ram_quota();
|
||||
}
|
||||
return table;
|
||||
return cma().alloc_aligned(sizeof(Board::Vm_page_table),
|
||||
Board::Vm_page_table::ALIGNM_LOG2).convert<void *>(
|
||||
[&] (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(); }
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -21,8 +21,14 @@ using State = Genode::Pd_session::Managing_system_state;
|
||||
|
||||
State Pd_session_component::managing_system(State const & s)
|
||||
{
|
||||
static constexpr addr_t SMCCC_NOT_SUPPORTED = 0xffffffffUL;
|
||||
|
||||
State ret;
|
||||
ret.r[0] = Hw::Psci_smc_functor::call(s.r[0], s.r[1], s.r[2], s.r[3]);
|
||||
|
||||
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]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* \brief Zynq 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__ZYNQ_BOARD_H_
|
||||
#define _SRC__INCLUDE__HW__SPEC__ARM__ZYNQ_BOARD_H_
|
||||
|
||||
#include <drivers/defs/zynq_qemu.h>
|
||||
#include <drivers/uart/xilinx.h>
|
||||
#include <hw/spec/arm/cortex_a9.h>
|
||||
#include <hw/spec/arm/pl310.h>
|
||||
#include <hw/spec/arm/boot_info.h>
|
||||
|
||||
namespace Hw::Zynq_qemu_board {
|
||||
|
||||
using namespace Zynq_qemu;
|
||||
using L2_cache = Hw::Pl310;
|
||||
using Cpu_mmio = Hw::Cortex_a9_mmio<CORTEX_A9_PRIVATE_MEM_BASE>;
|
||||
using Serial = Genode::Xilinx_uart;
|
||||
|
||||
enum {
|
||||
UART_BASE = UART_0_MMIO_BASE,
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* _SRC__INCLUDE__HW__SPEC__ARM__ZYNQ_BOARD_H_ */
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* \brief Board definitions for i.MX8 Quad EVK
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2019-06-12
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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_64__IMX8Q_EVK__BOARD_H_
|
||||
#define _SRC__INCLUDE__HW__SPEC__ARM_64__IMX8Q_EVK__BOARD_H_
|
||||
|
||||
#include <drivers/uart/imx.h>
|
||||
#include <hw/spec/arm/boot_info.h>
|
||||
|
||||
namespace Hw::Imx8q_evk_board {
|
||||
|
||||
using Serial = Genode::Imx_uart;
|
||||
|
||||
enum {
|
||||
RAM_BASE = 0x40000000,
|
||||
RAM_SIZE = 0xc0000000,
|
||||
|
||||
UART_BASE = 0x30860000,
|
||||
UART_SIZE = 0x1000,
|
||||
UART_CLOCK = 250000000,
|
||||
};
|
||||
|
||||
namespace Cpu_mmio {
|
||||
enum {
|
||||
IRQ_CONTROLLER_DISTR_BASE = 0x38800000,
|
||||
IRQ_CONTROLLER_DISTR_SIZE = 0x10000,
|
||||
IRQ_CONTROLLER_VT_CPU_BASE = 0x31020000,
|
||||
IRQ_CONTROLLER_VT_CPU_SIZE = 0x2000,
|
||||
IRQ_CONTROLLER_REDIST_BASE = 0x38880000,
|
||||
IRQ_CONTROLLER_REDIST_SIZE = 0xc0000,
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
#endif /* _SRC__INCLUDE__HW__SPEC__ARM_64__IMX8Q_EVK__BOARD_H_ */
|
||||
@@ -2,6 +2,10 @@ SRC_CC += lx_hybrid.cc new_delete.cc capability_space.cc
|
||||
SRC_CC += signal_transmitter.cc signal.cc
|
||||
SRC_C += libgcc.c
|
||||
|
||||
# new_delete.cc uses libsupc++ which means we need to access
|
||||
# its include directory.
|
||||
STDINC := yes
|
||||
|
||||
vpath new_delete.cc $(BASE_DIR)/src/lib/cxx
|
||||
vpath lx_hybrid.cc $(REP_DIR)/src/lib/lx_hybrid
|
||||
vpath libgcc.c $(REP_DIR)/src/lib/lx_hybrid
|
||||
|
||||
@@ -1 +1 @@
|
||||
2021-10-13 52a921d570e363144984ebf4e4f9a9386fa5864a
|
||||
2021-11-29 dcaadcb8b692ac78060694d86ea4340fd18d87b3
|
||||
|
||||
@@ -1 +1 @@
|
||||
2021-10-13 0cfcfb0e903ca534510e38c6bbbcc0815e76af59
|
||||
2021-11-29 a6c8044ea55fc0e02e5a37d968751e530a640b9a
|
||||
|
||||
@@ -64,22 +64,21 @@ class Genode::Platform : public Platform_generic
|
||||
|
||||
struct Dummy_allocator : Range_allocator
|
||||
{
|
||||
void free(void *, size_t) override { ASSERT_NEVER_CALLED; }
|
||||
bool need_size_for_free() const override { ASSERT_NEVER_CALLED; }
|
||||
size_t consumed() const override { ASSERT_NEVER_CALLED; }
|
||||
size_t overhead(size_t) const override { ASSERT_NEVER_CALLED; }
|
||||
int add_range (addr_t, size_t ) override { ASSERT_NEVER_CALLED; }
|
||||
int remove_range(addr_t, size_t ) override { ASSERT_NEVER_CALLED; }
|
||||
void free(void *) override { ASSERT_NEVER_CALLED; }
|
||||
size_t avail() const override { ASSERT_NEVER_CALLED; }
|
||||
bool valid_addr(addr_t ) const override { ASSERT_NEVER_CALLED; }
|
||||
bool alloc(size_t, void **) override { ASSERT_NEVER_CALLED; }
|
||||
void free(void *, size_t) override { ASSERT_NEVER_CALLED; }
|
||||
bool need_size_for_free() const override { ASSERT_NEVER_CALLED; }
|
||||
size_t consumed() const override { ASSERT_NEVER_CALLED; }
|
||||
size_t overhead(size_t) const override { ASSERT_NEVER_CALLED; }
|
||||
Range_result add_range (addr_t, size_t ) override { ASSERT_NEVER_CALLED; }
|
||||
Range_result remove_range(addr_t, size_t ) override { ASSERT_NEVER_CALLED; }
|
||||
void free(void *) override { ASSERT_NEVER_CALLED; }
|
||||
size_t avail() const override { ASSERT_NEVER_CALLED; }
|
||||
bool valid_addr(addr_t ) const override { ASSERT_NEVER_CALLED; }
|
||||
Alloc_result try_alloc(size_t) override { ASSERT_NEVER_CALLED; }
|
||||
Alloc_result alloc_addr(size_t, addr_t) override { ASSERT_NEVER_CALLED; }
|
||||
|
||||
Alloc_return alloc_aligned(size_t, void **, unsigned, Range) override
|
||||
Alloc_result alloc_aligned(size_t, unsigned, Range) override
|
||||
{ ASSERT_NEVER_CALLED; }
|
||||
|
||||
Alloc_return alloc_addr(size_t, addr_t) override
|
||||
{ ASSERT_NEVER_CALLED; }
|
||||
|
||||
} _dummy_alloc { };
|
||||
|
||||
@@ -88,25 +87,31 @@ class Genode::Platform : public Platform_generic
|
||||
*/
|
||||
struct Pseudo_ram_allocator : Range_allocator
|
||||
{
|
||||
bool alloc(size_t, void **out_addr) override
|
||||
Alloc_result try_alloc(size_t) override
|
||||
{
|
||||
*out_addr = 0;
|
||||
return true;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Alloc_return alloc_aligned(size_t, void **out, unsigned, Range) override
|
||||
Alloc_result alloc_aligned(size_t, unsigned, Range) override
|
||||
{
|
||||
*out = 0;
|
||||
return Alloc_return::OK;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Alloc_return alloc_addr(size_t, addr_t) override
|
||||
Alloc_result alloc_addr(size_t, addr_t) override
|
||||
{
|
||||
return Alloc_return::OK;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Range_result add_range(addr_t, size_t) override
|
||||
{
|
||||
return Range_ok();
|
||||
}
|
||||
|
||||
Range_result remove_range(addr_t, size_t) override
|
||||
{
|
||||
return Range_ok();
|
||||
}
|
||||
|
||||
int add_range(addr_t, size_t) override { return 0; }
|
||||
int remove_range(addr_t, size_t) override { return 0; }
|
||||
void free(void *) override { }
|
||||
void free(void *, size_t) override { }
|
||||
size_t avail() const override { return ram_quota_from_env(); }
|
||||
|
||||
@@ -79,7 +79,7 @@ class Stack_area_region_map : public Genode::Region_map
|
||||
|
||||
struct Stack_area_ram_allocator : Genode::Ram_allocator
|
||||
{
|
||||
Genode::Ram_dataspace_capability alloc(Genode::size_t, Genode::Cache) override {
|
||||
Alloc_result try_alloc(Genode::size_t, Genode::Cache) override {
|
||||
return Genode::Ram_dataspace_capability(); }
|
||||
|
||||
void free(Genode::Ram_dataspace_capability) override { }
|
||||
|
||||
@@ -410,11 +410,7 @@ namespace {
|
||||
{
|
||||
typedef Genode::size_t size_t;
|
||||
|
||||
bool alloc(size_t size, void **out_addr) override
|
||||
{
|
||||
*out_addr = malloc(size);
|
||||
return true;
|
||||
}
|
||||
Alloc_result try_alloc(size_t size) override { return malloc(size); }
|
||||
|
||||
void free(void *addr, size_t) override { ::free(addr); }
|
||||
|
||||
|
||||
@@ -51,9 +51,9 @@ Main::Main(Env &env) : heap(env.ram(), env.rm())
|
||||
|
||||
/* induce initial heap expansion to remove RM noise */
|
||||
if (1) {
|
||||
void *addr;
|
||||
heap.alloc(0x100000, &addr);
|
||||
heap.free(addr, 0);
|
||||
heap.try_alloc(0x100000).with_result(
|
||||
[&] (void *ptr) { heap.free(ptr, 0); },
|
||||
[&] (Allocator::Alloc_error) { });
|
||||
}
|
||||
|
||||
addr_t beg((addr_t)&blob_beg);
|
||||
|
||||
@@ -316,6 +316,7 @@ namespace Nova {
|
||||
R8_R15 = 1U << 22, /* R8 .. R15 */
|
||||
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 */
|
||||
FPU = 1U << 31, /* FPU state */
|
||||
|
||||
IRQ = EFL | STA | INJ | TSC,
|
||||
@@ -590,7 +591,7 @@ namespace Nova {
|
||||
mword_t reserved1;
|
||||
#endif
|
||||
} gdtr, idtr;
|
||||
unsigned long long tsc_val, tsc_off;
|
||||
unsigned long long tsc_val, tsc_off, tsc_aux;
|
||||
} __attribute__((packed));
|
||||
mword_t mr[(4096 - 4 * sizeof(mword_t)) / sizeof(mword_t)];
|
||||
};
|
||||
|
||||
@@ -1 +1 @@
|
||||
2ff8c9abf7389a2bdb7e0aa8aa4d2fec688c51af
|
||||
b06f9132099cd798147f6951f27a5d3a17f28fa4
|
||||
|
||||
@@ -4,7 +4,7 @@ DOWNLOADS := nova.git
|
||||
|
||||
# r10 branch
|
||||
URL(nova) := https://github.com/alex-ab/NOVA.git
|
||||
REV(nova) := 5c64bba1ee59902eb2a4ce4abe4b867eaf085dac
|
||||
REV(nova) := 825c1f94c82ae03f554c02b91430eca6983329da
|
||||
DIR(nova) := src/kernel/nova
|
||||
|
||||
PATCHES := $(sort $(wildcard $(REP_DIR)/patches/*.patch))
|
||||
|
||||
@@ -1 +1 @@
|
||||
2021-05-09 7e538243f9886048199e49cec7643674585b164c
|
||||
2021-11-29 768f505c4774de780119b4f18b648ff08ae1a596
|
||||
|
||||
@@ -1 +1 @@
|
||||
2021-10-14 a5d63836f2a18ac99fc43addb018f014a03b0ebc
|
||||
2021-11-29 80e3a0a005973ab010f5c63e0373073f7e2f4fba
|
||||
|
||||
@@ -39,8 +39,12 @@ static inline void * alloc_region(Dataspace_component &ds, const size_t size)
|
||||
void *virt_addr = 0;
|
||||
size_t align_log2 = log2(ds.size());
|
||||
for (; align_log2 >= get_page_size_log2(); align_log2--) {
|
||||
if (platform().region_alloc().alloc_aligned(size,
|
||||
&virt_addr, align_log2).ok())
|
||||
|
||||
platform().region_alloc().alloc_aligned(size, align_log2).with_result(
|
||||
[&] (void *ptr) { virt_addr = ptr; },
|
||||
[&] (Allocator::Alloc_error) { });
|
||||
|
||||
if (virt_addr)
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -69,33 +69,36 @@ static bool msi(Genode::addr_t irq_sel, Genode::addr_t phys_mem,
|
||||
Genode::addr_t &msi_addr, Genode::addr_t &msi_data,
|
||||
Genode::Signal_context_capability sig_cap)
|
||||
{
|
||||
void * virt = 0;
|
||||
if (platform().region_alloc().alloc_aligned(4096, &virt, 12).error())
|
||||
return false;
|
||||
return platform().region_alloc().alloc_aligned(4096, 12).convert<bool>(
|
||||
|
||||
Genode::addr_t virt_addr = reinterpret_cast<Genode::addr_t>(virt);
|
||||
if (!virt_addr)
|
||||
return false;
|
||||
[&] (void *virt_ptr) {
|
||||
|
||||
using Nova::Rights;
|
||||
using Nova::Utcb;
|
||||
addr_t const virt_addr = reinterpret_cast<addr_t>(virt_ptr);
|
||||
|
||||
Nova::Mem_crd phys_crd(phys_mem >> 12, 0, Rights(true, false, false));
|
||||
Nova::Mem_crd virt_crd(virt_addr >> 12, 0, Rights(true, false, false));
|
||||
Utcb &utcb = *reinterpret_cast<Utcb *>(Thread::myself()->utcb());
|
||||
using Nova::Rights;
|
||||
using Nova::Utcb;
|
||||
|
||||
if (map_local_phys_to_virt(utcb, phys_crd, virt_crd, platform_specific().core_pd_sel())) {
|
||||
platform().region_alloc().free(virt, 4096);
|
||||
return false;
|
||||
}
|
||||
Nova::Mem_crd phys_crd(phys_mem >> 12, 0, Rights(true, false, false));
|
||||
Nova::Mem_crd virt_crd(virt_addr >> 12, 0, Rights(true, false, false));
|
||||
|
||||
/* try to assign MSI to device */
|
||||
bool res = associate(irq_sel, msi_addr, msi_data, sig_cap, virt_addr);
|
||||
Utcb &utcb = *reinterpret_cast<Utcb *>(Thread::myself()->utcb());
|
||||
|
||||
unmap_local(Nova::Mem_crd(virt_addr >> 12, 0, Rights(true, true, true)));
|
||||
platform().region_alloc().free(virt, 4096);
|
||||
if (map_local_phys_to_virt(utcb, phys_crd, virt_crd, platform_specific().core_pd_sel())) {
|
||||
platform().region_alloc().free(virt_ptr, 4096);
|
||||
return false;
|
||||
}
|
||||
|
||||
return res;
|
||||
/* try to assign MSI to device */
|
||||
bool res = associate(irq_sel, msi_addr, msi_data, sig_cap, virt_addr);
|
||||
|
||||
unmap_local(Nova::Mem_crd(virt_addr >> 12, 0, Rights(true, true, true)));
|
||||
platform().region_alloc().free(virt_ptr, 4096);
|
||||
|
||||
return res;
|
||||
},
|
||||
[&] (Range_allocator::Alloc_error) {
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -217,7 +220,7 @@ Irq_session_component::Irq_session_component(Range_allocator &irq_alloc,
|
||||
throw Service_denied();
|
||||
}
|
||||
|
||||
if (irq_alloc.alloc_addr(1, irq_number).error()) {
|
||||
if (irq_alloc.alloc_addr(1, irq_number).failed()) {
|
||||
error("unavailable IRQ ", irq_number, " requested");
|
||||
throw Service_denied();
|
||||
}
|
||||
|
||||
@@ -80,18 +80,21 @@ addr_t Platform::_map_pages(addr_t const phys_addr, addr_t const pages,
|
||||
addr_t const size = pages << get_page_size_log2();
|
||||
|
||||
/* try to reserve contiguous virtual area */
|
||||
void *core_local_ptr = nullptr;
|
||||
if (region_alloc().alloc_aligned(size + (guard_page ? get_page_size() : 0),
|
||||
&core_local_ptr, get_page_size_log2()).error())
|
||||
return 0;
|
||||
return region_alloc().alloc_aligned(size + (guard_page ? get_page_size() : 0),
|
||||
get_page_size_log2()).convert<addr_t>(
|
||||
[&] (void *core_local_ptr) {
|
||||
|
||||
addr_t const core_local_addr = reinterpret_cast<addr_t>(core_local_ptr);
|
||||
addr_t const core_local_addr = reinterpret_cast<addr_t>(core_local_ptr);
|
||||
|
||||
int res = map_local(_core_pd_sel, *__main_thread_utcb, phys_addr,
|
||||
core_local_addr, pages,
|
||||
Nova::Rights(true, true, false), true);
|
||||
int res = map_local(_core_pd_sel, *__main_thread_utcb, phys_addr,
|
||||
core_local_addr, pages,
|
||||
Nova::Rights(true, true, false), true);
|
||||
|
||||
return res ? 0 : core_local_addr;
|
||||
return res ? 0 : core_local_addr;
|
||||
},
|
||||
|
||||
[&] (Allocator::Alloc_error) {
|
||||
return 0UL; });
|
||||
}
|
||||
|
||||
|
||||
@@ -661,126 +664,113 @@ Platform::Platform()
|
||||
|
||||
_init_rom_modules();
|
||||
|
||||
auto export_pages_as_rom_module = [&] (auto rom_name, size_t pages, auto content_fn)
|
||||
{
|
||||
/* export x86 platform specific infos */
|
||||
size_t const bytes = pages << get_page_size_log2();
|
||||
ram_alloc().alloc_aligned(bytes, get_page_size_log2()).with_result(
|
||||
|
||||
unsigned const pages = 1;
|
||||
void * phys_ptr = nullptr;
|
||||
if (ram_alloc().alloc_aligned(get_page_size(), &phys_ptr,
|
||||
get_page_size_log2()).ok()) {
|
||||
[&] (void *phys_ptr) {
|
||||
|
||||
addr_t const phys_addr = reinterpret_cast<addr_t>(phys_ptr);
|
||||
addr_t const core_local_addr = _map_pages(phys_addr, pages);
|
||||
addr_t const phys_addr = reinterpret_cast<addr_t>(phys_ptr);
|
||||
char * const core_local_ptr = (char *)_map_pages(phys_addr, pages);
|
||||
|
||||
if (!core_local_addr) {
|
||||
ram_alloc().free(phys_ptr);
|
||||
} else {
|
||||
if (!core_local_ptr) {
|
||||
warning("failed to export ", rom_name, " as ROM module");
|
||||
ram_alloc().free(phys_ptr, bytes);
|
||||
return;
|
||||
}
|
||||
|
||||
Genode::Xml_generator xml(reinterpret_cast<char *>(core_local_addr),
|
||||
pages << get_page_size_log2(),
|
||||
"platform_info", [&] ()
|
||||
{
|
||||
xml.node("kernel", [&] () {
|
||||
xml.attribute("name", "nova");
|
||||
xml.attribute("acpi", true);
|
||||
xml.attribute("msi" , true);
|
||||
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));
|
||||
|
||||
/* leave the ROM backing store mapped within core */
|
||||
},
|
||||
|
||||
[&] (Range_allocator::Alloc_error) {
|
||||
warning("failed to allocate physical memory for exporting ",
|
||||
rom_name, " as ROM module"); });
|
||||
};
|
||||
|
||||
export_pages_as_rom_module("platform_info", 1,
|
||||
[&] (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);
|
||||
});
|
||||
if (efi_sys_tab_phy) {
|
||||
xml.node("efi-system-table", [&] () {
|
||||
xml.attribute("address", String<32>(Hex(efi_sys_tab_phy)));
|
||||
});
|
||||
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", [&] () {
|
||||
|
||||
xml.attribute("revision", 2); /* XXX */
|
||||
xml.attribute("revision", 2); /* XXX */
|
||||
|
||||
if (rsdt)
|
||||
xml.attribute("rsdt", String<32>(Hex(rsdt)));
|
||||
if (rsdt)
|
||||
xml.attribute("rsdt", String<32>(Hex(rsdt)));
|
||||
|
||||
if (xsdt)
|
||||
xml.attribute("xsdt", String<32>(Hex(xsdt)));
|
||||
if (xsdt)
|
||||
xml.attribute("xsdt", String<32>(Hex(xsdt)));
|
||||
});
|
||||
xml.node("affinity-space", [&] () {
|
||||
xml.attribute("width", _cpus.width());
|
||||
xml.attribute("height", _cpus.height());
|
||||
});
|
||||
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.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);
|
||||
});
|
||||
xml.node("affinity-space", [&] () {
|
||||
xml.attribute("width", _cpus.width());
|
||||
xml.attribute("height", _cpus.height());
|
||||
});
|
||||
xml.node("hardware", [&] () {
|
||||
xml.node("features", [&] () {
|
||||
xml.attribute("svm", hip.has_feature_svm());
|
||||
xml.attribute("vmx", hip.has_feature_vmx());
|
||||
});
|
||||
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.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);
|
||||
});
|
||||
xml.node("tsc", [&] () {
|
||||
xml.attribute("invariant", cpuid_invariant_tsc());
|
||||
xml.attribute("freq_khz" , hip.tsc_freq);
|
||||
});
|
||||
xml.node("hardware", [&] () {
|
||||
xml.node("features", [&] () {
|
||||
xml.attribute("svm", hip.has_feature_svm());
|
||||
xml.attribute("vmx", hip.has_feature_vmx());
|
||||
});
|
||||
xml.node("tsc", [&] () {
|
||||
xml.attribute("invariant", cpuid_invariant_tsc());
|
||||
xml.attribute("freq_khz" , hip.tsc_freq);
|
||||
});
|
||||
xml.node("cpus", [&] () {
|
||||
hip.for_each_enabled_cpu([&](Hip::Cpu_desc const &cpu, unsigned i) {
|
||||
xml.node("cpu", [&] () {
|
||||
xml.attribute("id", i);
|
||||
xml.attribute("package", cpu.package);
|
||||
xml.attribute("core", cpu.core);
|
||||
xml.attribute("thread", cpu.thread);
|
||||
xml.attribute("family", String<5>(Hex(cpu.family)));
|
||||
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)));
|
||||
});
|
||||
xml.node("cpus", [&] () {
|
||||
hip.for_each_enabled_cpu([&](Hip::Cpu_desc const &cpu, unsigned i) {
|
||||
xml.node("cpu", [&] () {
|
||||
xml.attribute("id", i);
|
||||
xml.attribute("package", cpu.package);
|
||||
xml.attribute("core", cpu.core);
|
||||
xml.attribute("thread", cpu.thread);
|
||||
xml.attribute("family", String<5>(Hex(cpu.family)));
|
||||
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)));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
unmap_local(*__main_thread_utcb, core_local_addr, pages);
|
||||
region_alloc().free(reinterpret_cast<void *>(core_local_addr),
|
||||
pages * get_page_size());
|
||||
|
||||
_rom_fs.insert(new (core_mem_alloc())
|
||||
Rom_module(phys_addr, pages * get_page_size(),
|
||||
"platform_info"));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/* core log as ROM module */
|
||||
{
|
||||
void * phys_ptr = nullptr;
|
||||
unsigned const pages = 4;
|
||||
size_t const log_size = pages << get_page_size_log2();
|
||||
|
||||
if (ram_alloc().alloc_aligned(log_size, &phys_ptr,
|
||||
get_page_size_log2()).ok()) {
|
||||
|
||||
addr_t const phys_addr = reinterpret_cast<addr_t>(phys_ptr);
|
||||
|
||||
addr_t const virt = _map_pages(phys_addr, pages, true);
|
||||
if (virt) {
|
||||
memset(reinterpret_cast<void *>(virt), 0, log_size);
|
||||
|
||||
_rom_fs.insert(new (core_mem_alloc()) Rom_module(phys_addr, log_size,
|
||||
"core_log"));
|
||||
|
||||
init_core_log( Core_log_range { virt, log_size } );
|
||||
} else
|
||||
ram_alloc().free(phys_ptr);
|
||||
}
|
||||
}
|
||||
export_pages_as_rom_module("core_log", 4,
|
||||
[&] (char * const ptr, size_t const size) {
|
||||
init_core_log( Core_log_range { (addr_t)ptr, size } );
|
||||
});
|
||||
|
||||
/* export hypervisor log memory */
|
||||
if (hyp_log && hyp_log_size)
|
||||
@@ -831,8 +821,12 @@ Platform::Platform()
|
||||
for (unsigned i = 0; i < 32; i++)
|
||||
{
|
||||
void * phys_ptr = nullptr;
|
||||
if (ram_alloc().alloc_aligned(get_page_size(), &phys_ptr,
|
||||
get_page_size_log2()).error())
|
||||
|
||||
ram_alloc().alloc_aligned(get_page_size(), get_page_size_log2()).with_result(
|
||||
[&] (void *ptr) { phys_ptr = ptr; },
|
||||
[&] (Range_allocator::Alloc_error) { /* covered by nullptr test below */ });
|
||||
|
||||
if (phys_ptr == nullptr)
|
||||
break;
|
||||
|
||||
addr_t phys_addr = reinterpret_cast<addr_t>(phys_ptr);
|
||||
|
||||
@@ -40,12 +40,17 @@ static inline void * alloc_region(Dataspace_component &ds, const size_t size)
|
||||
void *virt_addr = 0;
|
||||
size_t align_log2 = log2(ds.size());
|
||||
for (; align_log2 >= get_page_size_log2(); align_log2--) {
|
||||
if (platform().region_alloc().alloc_aligned(size,
|
||||
&virt_addr, align_log2).ok())
|
||||
break;
|
||||
|
||||
platform().region_alloc().alloc_aligned(size, align_log2).with_result(
|
||||
[&] (void *ptr) { virt_addr = ptr; },
|
||||
[&] (Range_allocator::Alloc_error) { /* try next iteration */ }
|
||||
);
|
||||
if (virt_addr)
|
||||
return virt_addr;
|
||||
}
|
||||
|
||||
return virt_addr;
|
||||
error("alloc_region of size ", size, " unexpectedly failed");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -92,7 +92,8 @@ Trace::Source::Info Vm_session_component::Vcpu::trace_source_info() const
|
||||
warning("sc_ctrl failed res=", res);
|
||||
|
||||
return { _label, String<5>("vCPU"),
|
||||
Trace::Execution_time(sc_time, sc_time),
|
||||
Trace::Execution_time(sc_time, sc_time,
|
||||
Nova::Qpd::DEFAULT_QUANTUM, _priority),
|
||||
_location };
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ CC_OPT += -DCONFIG_MEMORY_DYN_MIN=0x1c00000 \
|
||||
CC_OPT_PIC :=
|
||||
ifeq ($(filter-out $(SPECS),32bit),)
|
||||
override CC_MARCH = -m32
|
||||
CC_WARN += -Wframe-larger-than=96
|
||||
CC_WARN += -Wframe-larger-than=104
|
||||
CC_OPT += -mpreferred-stack-boundary=2 -mregparm=3
|
||||
else
|
||||
ifeq ($(filter-out $(SPECS),64bit),)
|
||||
|
||||
@@ -64,17 +64,16 @@ struct Nova_vcpu : Rpc_client<Vm_session::Native_vcpu>, Noncopyable
|
||||
|
||||
Vcpu_state _vcpu_state __attribute__((aligned(0x10))) { };
|
||||
|
||||
uint8_t _fpu_ep[512] __attribute__((aligned(0x10)));
|
||||
|
||||
enum Remote_state_requested {
|
||||
NONE = 0,
|
||||
PAUSE = 1,
|
||||
RUN = 2
|
||||
} _remote { NONE };
|
||||
|
||||
inline void _read_nova_state(Nova::Utcb &utcb, unsigned exit_reason);
|
||||
inline void _read_nova_state(Nova::Utcb &, unsigned exit_reason,
|
||||
uint8_t const &);
|
||||
|
||||
inline void _write_nova_state(Nova::Utcb &utcb);
|
||||
inline void _write_nova_state(Nova::Utcb &);
|
||||
|
||||
addr_t _sm_sel() const {
|
||||
return Nova::NUM_INITIAL_PT_RESERVED + _id_elem.id().value * 4; }
|
||||
@@ -82,7 +81,8 @@ struct Nova_vcpu : Rpc_client<Vm_session::Native_vcpu>, Noncopyable
|
||||
addr_t _ec_sel() const { return _sm_sel() + 1; }
|
||||
|
||||
/**
|
||||
* NOVA badge with 16-bit exit reason and 16-bit artificial vCPU I
|
||||
* NOVA badge with 15-bit exit reason, 1-bit fpu usage and
|
||||
* 16-bit artificial vCPU I
|
||||
*/
|
||||
struct Badge
|
||||
{
|
||||
@@ -91,15 +91,19 @@ struct Nova_vcpu : Rpc_client<Vm_session::Native_vcpu>, Noncopyable
|
||||
Badge(unsigned long value)
|
||||
: _value((uint32_t)value) { }
|
||||
|
||||
Badge(uint16_t vcpu_id, uint16_t exit_reason)
|
||||
: _value((uint32_t)(vcpu_id << 16) | exit_reason) { }
|
||||
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)
|
||||
) { }
|
||||
|
||||
uint16_t exit_reason() const { return (uint16_t)( _value & 0xffff); }
|
||||
uint16_t exit_reason() const { return (uint16_t)( _value & 0x7fff); }
|
||||
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 &utcb, uint16_t exit_reason);
|
||||
bool _handle_exit(Nova::Utcb &, uint16_t exit_reason, uint8_t const &);
|
||||
|
||||
__attribute__((regparm(1))) static void _exit_entry(addr_t badge);
|
||||
|
||||
@@ -109,8 +113,6 @@ struct Nova_vcpu : Rpc_client<Vm_session::Native_vcpu>, Noncopyable
|
||||
(void)exit;
|
||||
(void)config;
|
||||
|
||||
return Nova::Mtd(Nova::Mtd::ALL);
|
||||
|
||||
Genode::addr_t mtd = 0;
|
||||
|
||||
mtd |= Nova::Mtd::ACDB;
|
||||
@@ -133,6 +135,7 @@ struct Nova_vcpu : Rpc_client<Vm_session::Native_vcpu>, Noncopyable
|
||||
mtd |= Nova::Mtd::INJ;
|
||||
mtd |= Nova::Mtd::STA;
|
||||
mtd |= Nova::Mtd::TSC;
|
||||
mtd |= Nova::Mtd::TSC_AUX;
|
||||
mtd |= Nova::Mtd::EFER;
|
||||
mtd |= Nova::Mtd::PDPTE;
|
||||
mtd |= Nova::Mtd::SYSCALL_SWAPGS;
|
||||
@@ -172,7 +175,8 @@ struct Nova_vcpu : Rpc_client<Vm_session::Native_vcpu>, Noncopyable
|
||||
};
|
||||
|
||||
|
||||
void Nova_vcpu::_read_nova_state(Nova::Utcb &utcb, unsigned exit_reason)
|
||||
void Nova_vcpu::_read_nova_state(Nova::Utcb &utcb, unsigned exit_reason,
|
||||
uint8_t const &fpu_at_exit)
|
||||
{
|
||||
typedef Genode::Vcpu_state::Segment Segment;
|
||||
typedef Genode::Vcpu_state::Range Range;
|
||||
@@ -181,10 +185,9 @@ void Nova_vcpu::_read_nova_state(Nova::Utcb &utcb, unsigned exit_reason)
|
||||
state().exit_reason = exit_reason;
|
||||
|
||||
if (utcb.mtd & Nova::Mtd::FPU) {
|
||||
state().fpu.charge([] (Vcpu_state::Fpu::State &fpu) {
|
||||
asm volatile ("fxsave %0" : "=m" (fpu) :: "memory");
|
||||
state().fpu.charge([&] (Vcpu_state::Fpu::State &fpu) {
|
||||
memcpy(&fpu, &fpu_at_exit, sizeof(fpu));
|
||||
});
|
||||
asm volatile ("fxrstor %0" : : "m" (*_fpu_ep) : "memory");
|
||||
}
|
||||
|
||||
if (utcb.mtd & Nova::Mtd::ACDB) {
|
||||
@@ -314,6 +317,10 @@ void Nova_vcpu::_read_nova_state(Nova::Utcb &utcb, unsigned exit_reason)
|
||||
state().tsc_offset.charge(utcb.tsc_off);
|
||||
}
|
||||
|
||||
if (utcb.mtd & Nova::Mtd::TSC_AUX) {
|
||||
state().tsc_aux.charge(utcb.tsc_aux);
|
||||
}
|
||||
|
||||
if (utcb.mtd & Nova::Mtd::EFER) {
|
||||
state().efer.charge(utcb.read_efer());
|
||||
}
|
||||
@@ -506,6 +513,11 @@ void Nova_vcpu::_write_nova_state(Nova::Utcb &utcb)
|
||||
utcb.tsc_off = state().tsc_offset.value();
|
||||
}
|
||||
|
||||
if (state().tsc_aux.charged()) {
|
||||
utcb.mtd |= Nova::Mtd::TSC_AUX;
|
||||
utcb.tsc_aux = state().tsc_aux.value();
|
||||
}
|
||||
|
||||
if (state().efer.charged()) {
|
||||
utcb.mtd |= Nova::Mtd::EFER;
|
||||
utcb.write_efer(state().efer.value());
|
||||
@@ -539,11 +551,8 @@ void Nova_vcpu::_write_nova_state(Nova::Utcb &utcb)
|
||||
utcb.write_tpr_threshold(state().tpr_threshold.value());
|
||||
}
|
||||
|
||||
if (_use_guest_fpu || state().fpu.charged()) {
|
||||
asm volatile ("fxsave %0" : "=m" (*_fpu_ep) :: "memory");
|
||||
}
|
||||
|
||||
if (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");
|
||||
});
|
||||
@@ -581,7 +590,7 @@ void Nova_vcpu::run()
|
||||
* 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)
|
||||
bool Nova_vcpu::_handle_exit(Nova::Utcb &utcb, uint16_t exit_reason, uint8_t const &fpu)
|
||||
{
|
||||
/* reset blocking state */
|
||||
bool const previous_blocked = _block;
|
||||
@@ -595,7 +604,7 @@ bool Nova_vcpu::_handle_exit(Nova::Utcb &utcb, uint16_t exit_reason)
|
||||
|
||||
/* transform state from NOVA to Genode */
|
||||
if (exit_reason != VM_EXIT_RECALL || !previous_blocked)
|
||||
_read_nova_state(utcb, exit_reason);
|
||||
_read_nova_state(utcb, exit_reason, fpu);
|
||||
|
||||
if (exit_reason == VM_EXIT_RECALL) {
|
||||
if (previous_blocked)
|
||||
@@ -653,6 +662,10 @@ bool Nova_vcpu::_handle_exit(Nova::Utcb &utcb, uint16_t exit_reason)
|
||||
|
||||
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<Nova::Utcb *>(myself.utcb());
|
||||
|
||||
@@ -662,7 +675,8 @@ void Nova_vcpu::_exit_entry(addr_t badge)
|
||||
try {
|
||||
_vcpu_space().apply<Nova_vcpu>(vcpu_id, [&] (Nova_vcpu &vcpu)
|
||||
{
|
||||
bool const block = vcpu._handle_exit(utcb, exit_reason);
|
||||
bool const block = vcpu._handle_exit(utcb, exit_reason,
|
||||
*_fpu_at_exit);
|
||||
|
||||
if (block) {
|
||||
Nova::reply(myself.stack_top(), vcpu._sm_sel());
|
||||
@@ -729,7 +743,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 };
|
||||
Badge const badge { vcpu_id, exit_reason, !!(mtd.value() & Nova::Mtd::FPU) };
|
||||
native_pd.imprint_rpc_cap(vm_exit_cap, badge.value());
|
||||
|
||||
return reinterpret_cap_cast<Signal_context>(vm_exit_cap);
|
||||
|
||||
@@ -1 +1 @@
|
||||
2021-10-13 c15d5658974ba0ae9980eb6e762431ba55ded1c4
|
||||
2021-11-29 2edd7e47571313187be2e2087479f9ef3906a1d6
|
||||
|
||||
@@ -24,10 +24,8 @@ Core_region_map::attach(Dataspace_capability ds_cap, size_t size,
|
||||
off_t offset, bool use_local_addr,
|
||||
Region_map::Local_addr, bool, bool)
|
||||
{
|
||||
using namespace Okl4;
|
||||
return _ep.apply(ds_cap, [&] (Dataspace_component *ds) -> void * {
|
||||
|
||||
auto lambda = [&] (Dataspace_component *ds) -> void *
|
||||
{
|
||||
if (!ds)
|
||||
throw Invalid_dataspace();
|
||||
|
||||
@@ -48,21 +46,25 @@ Core_region_map::attach(Dataspace_capability ds_cap, size_t size,
|
||||
}
|
||||
|
||||
/* allocate range in core's virtual address space */
|
||||
void *virt_addr;
|
||||
if (!platform().region_alloc().alloc(page_rounded_size, &virt_addr)) {
|
||||
error("could not allocate virtual address range in core of size ",
|
||||
page_rounded_size);
|
||||
return nullptr;
|
||||
}
|
||||
Range_allocator &virt_alloc = platform().region_alloc();
|
||||
return virt_alloc.try_alloc(page_rounded_size).convert<void *>(
|
||||
|
||||
/* map the dataspace's physical pages to corresponding virtual addresses */
|
||||
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 virt_addr;
|
||||
};
|
||||
[&] (void *virt_addr) -> void * {
|
||||
|
||||
return _ep.apply(ds_cap, lambda);
|
||||
/* 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 virt_addr;
|
||||
},
|
||||
|
||||
[&] (Range_allocator::Alloc_error) -> void * {
|
||||
error("could not allocate virtual address range in core of size ",
|
||||
page_rounded_size);
|
||||
return nullptr;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@ Irq_session_component::Irq_session_component(Range_allocator &irq_alloc,
|
||||
if (msi)
|
||||
throw Service_denied();
|
||||
|
||||
if (irq_alloc.alloc_addr(1, _irq_number).error()) {
|
||||
if (irq_alloc.alloc_addr(1, _irq_number).failed()) {
|
||||
error("unavailable IRQ ", Hex(_irq_number), " requested");
|
||||
throw Service_denied();
|
||||
}
|
||||
|
||||
@@ -189,52 +189,66 @@ Platform::Platform()
|
||||
|
||||
/* core log as ROM module */
|
||||
{
|
||||
void * core_local_ptr = nullptr;
|
||||
void * phys_ptr = nullptr;
|
||||
unsigned const pages = 1;
|
||||
size_t const log_size = pages << get_page_size_log2();
|
||||
unsigned const align = get_page_size_log2();
|
||||
|
||||
ram_alloc().alloc_aligned(log_size, &phys_ptr, get_page_size_log2());
|
||||
addr_t const phys_addr = reinterpret_cast<addr_t>(phys_ptr);
|
||||
ram_alloc().alloc_aligned(log_size, align).with_result(
|
||||
|
||||
/* let one page free after the log buffer */
|
||||
region_alloc().alloc_aligned(log_size, &core_local_ptr, get_page_size_log2());
|
||||
addr_t const core_local_addr = reinterpret_cast<addr_t>(core_local_ptr);
|
||||
[&] (void *phys) {
|
||||
addr_t const phys_addr = reinterpret_cast<addr_t>(phys);
|
||||
|
||||
map_local(phys_addr, core_local_addr, pages);
|
||||
memset(core_local_ptr, 0, log_size);
|
||||
region_alloc().alloc_aligned(log_size, align). with_result(
|
||||
|
||||
_rom_fs.insert(new (core_mem_alloc()) Rom_module(phys_addr, log_size,
|
||||
"core_log"));
|
||||
[&] (void *ptr) {
|
||||
|
||||
init_core_log(Core_log_range { core_local_addr, log_size } );
|
||||
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"));
|
||||
|
||||
init_core_log(Core_log_range { (addr_t)ptr, log_size } );
|
||||
},
|
||||
[&] (Range_allocator::Alloc_error) { }
|
||||
);
|
||||
},
|
||||
[&] (Range_allocator::Alloc_error) { }
|
||||
);
|
||||
}
|
||||
|
||||
/* export platform specific infos */
|
||||
{
|
||||
void * core_local_ptr = nullptr;
|
||||
void * phys_ptr = nullptr;
|
||||
unsigned const pages = 1;
|
||||
size_t const size = pages << get_page_size_log2();
|
||||
|
||||
if (ram_alloc().alloc_aligned(size, &phys_ptr, get_page_size_log2()).ok()) {
|
||||
addr_t const phys_addr = reinterpret_cast<addr_t>(phys_ptr);
|
||||
ram_alloc().alloc_aligned(size, get_page_size_log2()).with_result(
|
||||
|
||||
/* let one page free after the log buffer */
|
||||
region_alloc().alloc_aligned(size, &core_local_ptr, get_page_size_log2());
|
||||
addr_t const core_local_addr = reinterpret_cast<addr_t>(core_local_ptr);
|
||||
[&] (void *phys_ptr) {
|
||||
addr_t const phys_addr = reinterpret_cast<addr_t>(phys_ptr);
|
||||
|
||||
if (map_local(phys_addr, core_local_addr, pages)) {
|
||||
/* let one page free after the log buffer */
|
||||
region_alloc().alloc_aligned(size, get_page_size_log2()).with_result(
|
||||
|
||||
Genode::Xml_generator xml(reinterpret_cast<char *>(core_local_addr),
|
||||
size, "platform_info", [&] () {
|
||||
xml.node("kernel", [&] () { xml.attribute("name", "okl4"); });
|
||||
});
|
||||
[&] (void *core_local_ptr) {
|
||||
addr_t const core_local_addr = reinterpret_cast<addr_t>(core_local_ptr);
|
||||
|
||||
_rom_fs.insert(new (core_mem_alloc()) Rom_module(phys_addr, size,
|
||||
"platform_info"));
|
||||
}
|
||||
}
|
||||
if (map_local(phys_addr, core_local_addr, pages)) {
|
||||
|
||||
Xml_generator xml(reinterpret_cast<char *>(core_local_addr),
|
||||
size, "platform_info", [&] () {
|
||||
xml.node("kernel", [&] () { xml.attribute("name", "okl4"); });
|
||||
});
|
||||
|
||||
_rom_fs.insert(new (core_mem_alloc()) Rom_module(phys_addr, size,
|
||||
"platform_info"));
|
||||
}
|
||||
},
|
||||
[&] (Range_allocator::Alloc_error) { }
|
||||
);
|
||||
},
|
||||
[&] (Range_allocator::Alloc_error) { }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,31 +38,41 @@ void Ram_dataspace_factory::_clear_ds (Dataspace_component &ds)
|
||||
{
|
||||
size_t page_rounded_size = (ds.size() + get_page_size() - 1) & get_page_mask();
|
||||
|
||||
struct Guard
|
||||
{
|
||||
Range_allocator &virt_alloc;
|
||||
struct { void *virt_ptr = nullptr; };
|
||||
|
||||
Guard(Range_allocator &virt_alloc) : virt_alloc(virt_alloc) { }
|
||||
|
||||
~Guard() { if (virt_ptr) virt_alloc.free(virt_ptr); }
|
||||
|
||||
} guard(platform().region_alloc());
|
||||
|
||||
/* allocate range in core's virtual address space */
|
||||
void *virt_addr;
|
||||
if (!platform().region_alloc().alloc(page_rounded_size, &virt_addr)) {
|
||||
error("could not allocate virtual address range in core of size ",
|
||||
page_rounded_size);
|
||||
platform().region_alloc().try_alloc(page_rounded_size).with_result(
|
||||
[&] (void *ptr) { guard.virt_ptr = ptr; },
|
||||
[&] (Range_allocator::Alloc_error e) {
|
||||
error("could not allocate virtual address range in core of size ",
|
||||
page_rounded_size, ", error=", e); });
|
||||
|
||||
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)virt_addr, num_pages)) {
|
||||
error("core-local memory mapping failed, error=", Okl4::L4_ErrorCode());
|
||||
if (!map_local(ds.phys_addr(), (addr_t)guard.virt_ptr, num_pages)) {
|
||||
error("core-local memory mapping failed");
|
||||
return;
|
||||
}
|
||||
|
||||
/* clear dataspace */
|
||||
size_t num_longwords = page_rounded_size/sizeof(long);
|
||||
for (long *dst = (long *)virt_addr; num_longwords--;)
|
||||
for (long *dst = (long *)guard.virt_ptr; num_longwords--;)
|
||||
*dst++ = 0;
|
||||
|
||||
/* unmap dataspace from core */
|
||||
if (!unmap_local((addr_t)virt_addr, num_pages))
|
||||
error("could not unmap core-local address range at ", virt_addr, ", "
|
||||
if (!unmap_local((addr_t)guard.virt_ptr, num_pages))
|
||||
error("could not unmap core-local address range at ", guard.virt_ptr, ", "
|
||||
"error=", Okl4::L4_ErrorCode());
|
||||
|
||||
/* free core's virtual address space */
|
||||
platform().region_alloc().free(virt_addr, page_rounded_size);
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
2021-10-13 2b72c9c5d111051ff6e274a9231c096fb7d70fed
|
||||
2021-11-29 c35c9e382e0e54a0fb975e26b88ed0de3d7a027e
|
||||
|
||||
@@ -60,28 +60,30 @@ addr_t Io_mem_session_component::_map_local(addr_t base, size_t size)
|
||||
{
|
||||
using namespace Pistachio;
|
||||
|
||||
addr_t local_base;
|
||||
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 */
|
||||
size_t alignment = (size >= get_super_page_size()) ? get_super_page_size_log2()
|
||||
: get_page_size_log2();
|
||||
/* align large I/O dataspaces on a super-page boundary within core */
|
||||
size_t const align = (size >= get_super_page_size())
|
||||
? get_super_page_size_log2()
|
||||
: get_page_size_log2();
|
||||
|
||||
/* special case for the null page */
|
||||
if (is_conventional_memory(base))
|
||||
local_base = base;
|
||||
return platform().region_alloc().alloc_aligned(size, align).convert<addr_t>(
|
||||
[&] (void *ptr) { return (addr_t)ptr; },
|
||||
[&] (Range_allocator::Alloc_error) -> addr_t {
|
||||
error(__func__, ": alloc_aligned failed!");
|
||||
return 0; });
|
||||
};
|
||||
|
||||
else {
|
||||
addr_t const local_base = (addr_t)alloc_virt_range();
|
||||
|
||||
/* find appropriate region for mapping */
|
||||
void *result = 0;
|
||||
if (platform().region_alloc().alloc_aligned(size, &result, alignment).error())
|
||||
error(__func__, ": alloc_aligned failed!");
|
||||
if (!local_base)
|
||||
return 0;
|
||||
|
||||
local_base = (addr_t)result;
|
||||
}
|
||||
|
||||
unsigned offset = 0;
|
||||
while (size) {
|
||||
for (unsigned offset = 0; size; ) {
|
||||
|
||||
size_t page_size = get_page_size();
|
||||
if (can_use_super_page(base + offset, size))
|
||||
|
||||
@@ -133,7 +133,7 @@ Irq_session_component::Irq_session_component(Range_allocator &irq_alloc,
|
||||
if (msi)
|
||||
throw Service_denied();
|
||||
|
||||
if (irq_alloc.alloc_addr(1, _irq_number).error()) {
|
||||
if (irq_alloc.alloc_addr(1, _irq_number).failed()) {
|
||||
error("unavailable IRQ ", Hex(_irq_number), " requested");
|
||||
throw Service_denied();
|
||||
}
|
||||
|
||||
@@ -605,51 +605,42 @@ Platform::Platform()
|
||||
|
||||
core_pd().bind_thread(core_thread);
|
||||
|
||||
/* core log as ROM module */
|
||||
auto export_page_as_rom_module = [&] (auto rom_name, auto content_fn)
|
||||
{
|
||||
void * phys_ptr = nullptr;
|
||||
unsigned const pages = 1;
|
||||
size_t const log_size = pages << get_page_size_log2();
|
||||
size_t const size = 1 << get_page_size_log2();
|
||||
ram_alloc().alloc_aligned(size, get_page_size_log2()).with_result(
|
||||
|
||||
ram_alloc().alloc_aligned(log_size, &phys_ptr, get_page_size_log2());
|
||||
addr_t const phys_addr = reinterpret_cast<addr_t>(phys_ptr);
|
||||
[&] (void *phys_ptr) {
|
||||
|
||||
void * const core_local_ptr = phys_ptr;
|
||||
addr_t const core_local_addr = phys_addr;
|
||||
/* core-local memory is one-to-one mapped physical RAM */
|
||||
addr_t const phys_addr = reinterpret_cast<addr_t>(phys_ptr);
|
||||
void * const core_local_ptr = phys_ptr;
|
||||
|
||||
/* let one page free after the log buffer */
|
||||
region_alloc().remove_range(core_local_addr, log_size + get_page_size());
|
||||
region_alloc().remove_range((addr_t)core_local_ptr, size);
|
||||
memset(core_local_ptr, 0, size);
|
||||
content_fn(core_local_ptr, size);
|
||||
|
||||
memset(core_local_ptr, 0, log_size);
|
||||
_rom_fs.insert(new (core_mem_alloc())
|
||||
Rom_module(phys_addr, size, rom_name));
|
||||
},
|
||||
[&] (Range_allocator::Alloc_error) {
|
||||
warning("failed to export ", rom_name, " as ROM module"); }
|
||||
);
|
||||
};
|
||||
|
||||
_rom_fs.insert(new (core_mem_alloc()) Rom_module(phys_addr, log_size,
|
||||
"core_log"));
|
||||
|
||||
init_core_log(Core_log_range { core_local_addr, log_size } );
|
||||
}
|
||||
/* core log as ROM module */
|
||||
export_page_as_rom_module("core_log",
|
||||
[&] (void *core_local_ptr, size_t size) {
|
||||
init_core_log(Core_log_range { (addr_t)core_local_ptr, size } ); });
|
||||
|
||||
/* export platform specific infos */
|
||||
{
|
||||
void * phys_ptr = nullptr;
|
||||
size_t const size = 1 << get_page_size_log2();
|
||||
|
||||
if (ram_alloc().alloc_aligned(size, &phys_ptr,
|
||||
get_page_size_log2()).ok()) {
|
||||
addr_t const phys_addr = reinterpret_cast<addr_t>(phys_ptr);
|
||||
addr_t const core_local_addr = phys_addr;
|
||||
|
||||
region_alloc().remove_range(core_local_addr, size);
|
||||
|
||||
Genode::Xml_generator xml(reinterpret_cast<char *>(core_local_addr),
|
||||
size, "platform_info", [&] () {
|
||||
xml.node("kernel", [&] () { xml.attribute("name", "pistachio"); });
|
||||
});
|
||||
|
||||
_rom_fs.insert(new (core_mem_alloc()) Rom_module(phys_addr, size,
|
||||
"platform_info"));
|
||||
}
|
||||
}
|
||||
|
||||
export_page_as_rom_module("platform_info",
|
||||
[&] (void *core_local_ptr, size_t size) {
|
||||
Xml_generator xml(reinterpret_cast<char *>(core_local_ptr),
|
||||
size, "platform_info",
|
||||
[&] () {
|
||||
xml.node("kernel", [&] () {
|
||||
xml.attribute("name", "pistachio"); }); }); });
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
2021-10-13 e6d9b433aacab2435854c06b6be6e460e5bc0dba
|
||||
2021-11-29 38db6c16cb9a86e9586cb4c6744de1d3253c187e
|
||||
|
||||
@@ -1 +1 @@
|
||||
2021-10-13 47f688dc1a3cf0cdd01d50c78200f6c673bbd8a7
|
||||
2021-11-29 312d15c5cc7ba2ad3fc672b22a875f56c48e4665
|
||||
|
||||
@@ -1 +1 @@
|
||||
2021-10-13 8156c9f37aebd3f73047484d66d1a85a669f871d
|
||||
2021-11-29 5fd017a250665ddaff280b47a32fe0255d141c44
|
||||
|
||||
@@ -26,7 +26,8 @@ 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)
|
||||
{
|
||||
auto lambda = [&] (Dataspace_component *ds) -> Local_addr {
|
||||
return _ep.apply(ds_cap, [&] (Dataspace_component *ds) -> Local_addr {
|
||||
|
||||
if (!ds)
|
||||
throw Invalid_dataspace();
|
||||
|
||||
@@ -46,21 +47,22 @@ Core_region_map::attach(Dataspace_capability ds_cap, size_t size, off_t offset,
|
||||
}
|
||||
|
||||
/* allocate range in core's virtual address space */
|
||||
void *virt_addr;
|
||||
if (!platform().region_alloc().alloc(page_rounded_size, &virt_addr)) {
|
||||
error("could not allocate virtual address range in core of size ",
|
||||
page_rounded_size);
|
||||
return nullptr;
|
||||
}
|
||||
return platform().region_alloc().try_alloc(page_rounded_size).convert<Local_addr>(
|
||||
[&] (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_addr, num_pages);
|
||||
/* 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_addr;
|
||||
};
|
||||
|
||||
return _ep.apply(ds_cap, lambda);
|
||||
return virt_ptr;
|
||||
},
|
||||
[&] (Range_allocator::Alloc_error) -> Local_addr {
|
||||
error("could not allocate virtual address range in core of size ",
|
||||
page_rounded_size);
|
||||
return nullptr;
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -51,21 +51,17 @@ class Genode::Static_allocator : public Allocator
|
||||
|
||||
class Alloc_failed { };
|
||||
|
||||
bool alloc(size_t size, void **out_addr) override
|
||||
Alloc_result try_alloc(size_t size) override
|
||||
{
|
||||
*out_addr = nullptr;
|
||||
|
||||
if (size > sizeof(Elem_space)) {
|
||||
error("unexpected allocation size of ", size);
|
||||
return false;
|
||||
return Alloc_error::DENIED;
|
||||
}
|
||||
|
||||
try {
|
||||
*out_addr = &_elements[_used.alloc()]; }
|
||||
return &_elements[_used.alloc()]; }
|
||||
catch (typename Bit_allocator<MAX>::Out_of_indices) {
|
||||
return false; }
|
||||
|
||||
return true;
|
||||
return Alloc_error::DENIED; }
|
||||
}
|
||||
|
||||
size_t overhead(size_t) const override { return 0; }
|
||||
|
||||
@@ -33,17 +33,17 @@ struct Genode::Untyped_memory
|
||||
|
||||
static inline addr_t alloc_pages(Range_allocator &phys_alloc, size_t num_pages)
|
||||
{
|
||||
void *out_ptr = nullptr;
|
||||
Range_allocator::Alloc_return alloc_ret =
|
||||
phys_alloc.alloc_aligned(num_pages*get_page_size(), &out_ptr,
|
||||
get_page_size_log2());
|
||||
size_t const size = num_pages*get_page_size();
|
||||
unsigned const align = get_page_size_log2();
|
||||
|
||||
if (alloc_ret.error()) {
|
||||
error(__PRETTY_FUNCTION__, ": allocation of untyped memory failed");
|
||||
throw Phys_alloc_failed();
|
||||
}
|
||||
return phys_alloc.alloc_aligned(size, align).convert<addr_t>(
|
||||
|
||||
return (addr_t)out_ptr;
|
||||
[&] (void *ptr) {
|
||||
return (addr_t)ptr; },
|
||||
|
||||
[&] (Range_allocator::Alloc_error) -> addr_t {
|
||||
error(__PRETTY_FUNCTION__, ": allocation of untyped memory failed");
|
||||
throw Phys_alloc_failed(); });
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ Irq_session_component::Irq_session_component(Range_allocator &irq_alloc,
|
||||
if (msi)
|
||||
throw Service_denied();
|
||||
|
||||
if (irq_alloc.alloc_addr(1, _irq_number).error()) {
|
||||
if (irq_alloc.alloc_addr(1, _irq_number).failed()) {
|
||||
error("unavailable IRQ ", _irq_number, " requested");
|
||||
throw Service_denied();
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user