Tag release 19.11
-----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEsIWqvdxEKaxX80hspyRgNBfs1rcFAl3fpmAACgkQpyRgNBfs 1rcezQ//ZoYChufO6m2CByuPUbITql12b6oyOjmvcw16NW+Nsf2EodwMeCk/9yyM kWIxqOtXp1yFPGNf8ebEkTu5YXYMkHrUds4V6nQ4nQnyk7VnQmR3XTnqP8Sr27Hp fHi7Dddjxufexeyb6bwis04mK4PeFWXk/D6H4nh6ZeaR30g/GQ+Wt4N64a+HcQ1g kLMKuLlooOoq0L9q8IVLAtQoKNR1LP6x0FKGH8B6elwns8rXna2fRSlCB+W7qLwl K/pQadaIkwQNj8TEXuQxdGOR1GIrTbUz9ExS6U1yPXjqK06CunDZqsn+Cv5G7p+5 ybMaViXwDGilZjhNLTjAbPhqhoOVu+yDB5gwzKiYt6/gTKP8N+VUpXKhGpzu/0ya wEt2b/43vmPm1NsBQQFU6vmjyW0W0iOl+a1tetv/qFo4mzQNesbVlu6t91b0EAjp C0JzZj9UHj/QkKgLIPkWMVWyz+VtODUeFhMLV6+86wzFmqSNhbaL0K/1LvX3AHZR 5M/sjMRdtRL9U7Xv/LTn/Sgisk5wT2wfI9dpkAZALZjm22751mSTv9XhdLC/+XpA 0F7cfSg36DphYsyPmSQ9+Q79rpU+bvuuTbqAsLdYcflMaW4bsIOd4j5Lk3adIPbN EE0uu+CD1GbqpKy+vLr+2EIlYpVNRTQKLklmkmhb+ZBuvUo00cU= =4dhl -----END PGP SIGNATURE----- Merge tag '19.11' Tag release 19.11
This commit is contained in:
commit
3d68a520cb
|
@ -391,6 +391,22 @@ Platforms
|
||||||
laptops.
|
laptops.
|
||||||
|
|
||||||
|
|
||||||
|
System management
|
||||||
|
#################
|
||||||
|
|
||||||
|
:Remote management of Sculpt OS via Puppet:
|
||||||
|
|
||||||
|
[https://en.wikipedia.org/wiki/Puppet_(company)#Puppet - Puppet] is a
|
||||||
|
software-configuration management tool for administering a large amount
|
||||||
|
of machines from one central place. Genode's
|
||||||
|
[https://genode.org/download/sculpt - Sculpt OS] lends itself to such
|
||||||
|
an approach of remote configuration management by the means of the
|
||||||
|
"config" file system (for configuring components and deployments) and
|
||||||
|
the "report" file system (for obtaining the runtime state of components).
|
||||||
|
The project would explore the application of the Puppet approach and tools
|
||||||
|
to Sculpt OS.
|
||||||
|
|
||||||
|
|
||||||
Optimizations
|
Optimizations
|
||||||
#############
|
#############
|
||||||
|
|
||||||
|
|
48
doc/news.txt
48
doc/news.txt
|
@ -3,6 +3,54 @@
|
||||||
Genode News
|
Genode News
|
||||||
===========
|
===========
|
||||||
|
|
||||||
|
Genode OS Framework release 19.11 | 2019-11-28
|
||||||
|
##############################################
|
||||||
|
|
||||||
|
| Following this year's theme of "bridging worlds", Genode 19.11 adds the
|
||||||
|
| ability to use popular build tools like CMake for application development,
|
||||||
|
| introduces a new virtual-machine monitor for 64-bit ARM, and enhances
|
||||||
|
| POSIX compatibility. As another highlight, it features the first version
|
||||||
|
| of our custom block-device encrypter.
|
||||||
|
|
||||||
|
Block-device encryption is a feature often requested by users of our Sculpt OS.
|
||||||
|
Until now, we deliberately left this topic unaddressed because we felt that a
|
||||||
|
profound answer was beyond our expertise. However, during the past year, we
|
||||||
|
dived deep into it. The result is the prototype for a new block encrypter that
|
||||||
|
encrypts data but also protects integrity and freshness. For us, the
|
||||||
|
implementation of the encrypter is especially intriguing because - with about
|
||||||
|
7000 lines of code - it is Genode's first non-trivial component written in the
|
||||||
|
[https://en.wikipedia.org/wiki/SPARK_(programming_language) - SPARK]
|
||||||
|
programming language.
|
||||||
|
|
||||||
|
The second major addition is a new virtual machine monitor (VMM) for 64-bit
|
||||||
|
ARM platforms such as the NXP i.MX8. It leverages the
|
||||||
|
[https://genode.org/documentation/articles/arm_virtualization - proof of concept]
|
||||||
|
we developed in 2015 for ARMv7, which we pursued as a technology exploration.
|
||||||
|
In contrast, our aspiration with the new VMM is a product-quality solution.
|
||||||
|
|
||||||
|
In our [https://genode.org/about/road-map - road map] for 2019, we stated
|
||||||
|
the "bridging of worlds" as our overall theme for this year. On that account,
|
||||||
|
the current release moves the project forward on two levels. First, by
|
||||||
|
successively increasing the scope of POSIX compatibility, we reduce the
|
||||||
|
friction when porting existing application software to Genode. We managed
|
||||||
|
to bridge several gaps in our POSIX support that we considered as impossible
|
||||||
|
to cover some years ago. In particular, we identified ways to emulate certain
|
||||||
|
POSIX signals, ioctl calls, and fork/execve semantics. This way, popular
|
||||||
|
software such as bash, coreutils, or Vim can now be executed as regular
|
||||||
|
Genode components with no additional runtime environment (like Noux or a VMM)
|
||||||
|
required.
|
||||||
|
|
||||||
|
At a higher level, the current release introduces new tooling especially
|
||||||
|
geared at the development and porting of application software. Compared to
|
||||||
|
Genode's regular development tools, which were designed for whole-system
|
||||||
|
development, the new tool called Goa relieves the developer from the
|
||||||
|
complexity of Genode's custom build system and instead promotes the use of
|
||||||
|
popular commodity solutions like CMake.
|
||||||
|
|
||||||
|
These and more topics are described in the
|
||||||
|
[https:/documentation/release-notes/19.11 - release documentation of version 19.11...]
|
||||||
|
|
||||||
|
|
||||||
Genode OS Framework release 19.08 | 2019-08-28
|
Genode OS Framework release 19.08 | 2019-08-28
|
||||||
##############################################
|
##############################################
|
||||||
|
|
||||||
|
|
|
@ -143,8 +143,8 @@ corresponds to Shift, '<mod2>' to Control, '<mod3>' to AltGr, and '<mod4>' to
|
||||||
Caps Lock.
|
Caps Lock.
|
||||||
|
|
||||||
! <mod1> <key name="KEY_LEFTSHIFT"/> <key name="KEY_RIGHTSHIFT"/> </mod1>
|
! <mod1> <key name="KEY_LEFTSHIFT"/> <key name="KEY_RIGHTSHIFT"/> </mod1>
|
||||||
! <mod2> <key name="KEY_LEFTCTRL"/> <key name="KEY_RIGHTCTRL"/> </mod4>
|
! <mod2> <key name="KEY_LEFTCTRL"/> <key name="KEY_RIGHTCTRL"/> </mod2>
|
||||||
! <mod3> <key name="KEY_RIGHTALT"/> </mod4> <!-- AltGr -->
|
! <mod3> <key name="KEY_RIGHTALT"/> </mod3> <!-- AltGr -->
|
||||||
! <mod4> <rom name="capslock"/> </mod4>
|
! <mod4> <rom name="capslock"/> </mod4>
|
||||||
|
|
||||||
As outlined above, the '<key>' nodes generated by xkb2ifcfg always use the
|
As outlined above, the '<key>' nodes generated by xkb2ifcfg always use the
|
||||||
|
|
815
doc/release_notes-19-11.txt
Normal file
815
doc/release_notes-19-11.txt
Normal file
|
@ -0,0 +1,815 @@
|
||||||
|
|
||||||
|
|
||||||
|
===============================================
|
||||||
|
Release notes for the Genode OS Framework 19.11
|
||||||
|
===============================================
|
||||||
|
|
||||||
|
Genode Labs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
On our [https://genode.org/about/road-map - road map] for this year, we stated
|
||||||
|
"bridging worlds" as our guiding theme of 2019. The current release pays
|
||||||
|
tribute to this ambition on several accounts.
|
||||||
|
|
||||||
|
First, acknowledging the role of POSIX in the real world outside the heavens
|
||||||
|
of Genode, the release vastly improves our (optional) C runtime with respect
|
||||||
|
to the emulation of POSIX signals, execve, and ioctl calls. With the line of
|
||||||
|
work described in Section [C runtime with improved POSIX compatibility], we
|
||||||
|
hope to greatly reduce the friction when porting and hosting existing
|
||||||
|
application software directly on Genode.
|
||||||
|
|
||||||
|
Second, we identified the process of porting or developing application
|
||||||
|
software worth improving. Our existing tools were primarily geared to
|
||||||
|
operating-system development, not application development. Application
|
||||||
|
developers demand different work flows and tools, including the freedom to use
|
||||||
|
a build system of their choice.
|
||||||
|
Section [New tooling for bridging existing build systems with Genode]
|
||||||
|
introduces our new take on this productivity issue.
|
||||||
|
|
||||||
|
Third, in cases where the porting of software to Genode is considered
|
||||||
|
infeasible, virtualization comes to the rescue. With the current release, a
|
||||||
|
new virtual machine monitor for the 64-bit ARM architecture enters the
|
||||||
|
framework. It is presented in Section [Virtualization of 64-bit ARM platforms].
|
||||||
|
|
||||||
|
As another goal for 2019, we envisioned a solution for block-level device
|
||||||
|
encryption, which is a highly anticipated feature among Genode users. We are
|
||||||
|
proud to present the preliminary result of our year-long development in
|
||||||
|
Section [Preliminary block-device encrypter].
|
||||||
|
|
||||||
|
|
||||||
|
Preliminary block-device encrypter
|
||||||
|
##################################
|
||||||
|
|
||||||
|
Over the past year, we worked on implementing a block-device encryption
|
||||||
|
component that makes use of the
|
||||||
|
[https://en.wikipedia.org/wiki/SPARK_(programming_language) - SPARK]
|
||||||
|
programming language for its core logic. In contrast to common
|
||||||
|
block-device encryption techniques where normally is little done besides
|
||||||
|
the encryption of the on-disk blocks, the _consistent block encrypter (CBE)_
|
||||||
|
aims for more. It combines multiple techniques to ensure integrity -
|
||||||
|
the detection of unauthorized modifications of the block-device -
|
||||||
|
and robustness against data loss. Robustness is achieved by keeping snapshots
|
||||||
|
of old states of the device that remain unaffected by the further operation of
|
||||||
|
the device. A copy-on-write mechanism (only the differential changes to the
|
||||||
|
last snapshot are stored) is employed to maintain this snapshot history with
|
||||||
|
low overhead. To be able to access all states of the device in the same manner,
|
||||||
|
some kind of translation from virtual blocks to blocks on the device is needed.
|
||||||
|
Hash-trees, where each node contains the hash of its sub-nodes, combine the
|
||||||
|
aspect of translating blocks and ensuring their integrity in an elegant way.
|
||||||
|
During the tree traversal, the computed hash of each node can be easily checked
|
||||||
|
against the hash stored in the parent node.
|
||||||
|
|
||||||
|
The CBE does not perform any cryptography by itself but delegates
|
||||||
|
cryptographic operations to another entity. It neither knows nor cares about
|
||||||
|
the used algorithm. Of all the nodes in the virtual block device (VBD), only
|
||||||
|
the leaf nodes, which contain the data, are encrypted. All other nodes, which
|
||||||
|
only contain meta-data, are stored unencrypted.
|
||||||
|
|
||||||
|
Design
|
||||||
|
------
|
||||||
|
|
||||||
|
As depicted in Figure [cbe_trees], all information describing the various
|
||||||
|
parts of the CBE is stored in the superblock. The referenced VBD is a set of
|
||||||
|
several hash trees, each representing a certain device state including the
|
||||||
|
current working state. Only the tree of the current working state is used to
|
||||||
|
write data to the block device. All other trees represent snapshots of older
|
||||||
|
states and are immutable. Each stored device state has a generation number
|
||||||
|
that provides the chronological order of the states.
|
||||||
|
|
||||||
|
As you can see, in the depicted situation, there exist four device states - the
|
||||||
|
snapshot with generation 3 is the oldest, followed by two newer snapshots and
|
||||||
|
generation 6 that marks the working state of the virtual device. The tree with
|
||||||
|
generation 6 is the current working tree. Each tree contains all changes done
|
||||||
|
to the VBD since the previous generation (for generation 6 the red nodes). All
|
||||||
|
parts of a tree that didn't change since the previous generation are references
|
||||||
|
into older trees (for generation 6 the gray nodes). Note that in the picture,
|
||||||
|
nodes that are not relevant for generation 6 are omitted to keep it manageable.
|
||||||
|
The actual data blocks of the virtual device are the leaf nodes of the trees,
|
||||||
|
shown as squares.
|
||||||
|
|
||||||
|
[image cbe_trees]
|
||||||
|
|
||||||
|
Whenever a block request from the client would override data blocks in
|
||||||
|
generation 6 that are still referenced from an older generation, new blocks for
|
||||||
|
storing the changes are needed. Here is where the so-called _Free Tree_ enters
|
||||||
|
the picture. This tree contains and manages the spare blocks. Spare blocks are
|
||||||
|
a certain amount of blocks that the CBE has in addition to the number of blocks
|
||||||
|
needed for initializing the virtual device. So, after having initialized a
|
||||||
|
virtual device, they remain unused and are only referenced by the Free Tree.
|
||||||
|
Therefore, in case the VBD needs new blocks, it consults the Free Tree (red
|
||||||
|
arrow).
|
||||||
|
|
||||||
|
In the depicted situation, writing the first data block (red square) would
|
||||||
|
require allocating 4 new blocks as all nodes in the branch leading to the
|
||||||
|
corresponding leaf node - including the leaf node itself - have to be written.
|
||||||
|
In contrast, writing the second data block would require allocating only one
|
||||||
|
new block as the inner nodes (red circles) now already exist. Subsequent write
|
||||||
|
requests affecting only the new blocks will not trigger further block
|
||||||
|
allocations because they still belong to the current generation and will be
|
||||||
|
changed in-place. To make them immutable we have to create a new snapshot.
|
||||||
|
|
||||||
|
The blocks in generation 5 that were replaced by the change to generation 6
|
||||||
|
(blue nodes) are not needed for the working state of the virtual device
|
||||||
|
anymore. They are therefore, in exchange for the allocated blocks, added to
|
||||||
|
the Free Tree. But don't be fooled by the name, they are not free for
|
||||||
|
allocation yet, but marked as "reserved" only. This means, they are
|
||||||
|
potentially still part of a snapshot (as is the case in our example) but the
|
||||||
|
Free Tree shall keep checking, because once all snapshots that referenced the
|
||||||
|
blue blocks have disappeared, they become free blocks and can be allocated
|
||||||
|
again.
|
||||||
|
|
||||||
|
To create a new snapshot, we first have to make all changes done to the VBDs
|
||||||
|
working state as well as the Free Tree persistent by writing all corresponding
|
||||||
|
blocks to the block-device. After that, the new superblock state is written to
|
||||||
|
the block-device. To safeguard this operation, the CBE always maintains several
|
||||||
|
older states of the superblock on the block device. In case writing the new
|
||||||
|
state of the superblock fails, the CBE could fall back to the last state that,
|
||||||
|
in our example, would contain only generations 3, 4, and 5. Finally, the
|
||||||
|
current generation of the superblock in RAM is incremented by one (in the
|
||||||
|
example to generation 7). Thereby, generation 6 becomes immutable.
|
||||||
|
|
||||||
|
A question that remains is when to create snapshots. Triggering a snapshot
|
||||||
|
according to some heuristics inside the CBE might result in unnecessary
|
||||||
|
overhead. For instance, the inner nodes of the tree change frequently during a
|
||||||
|
sequential operation. We might not want them to be re-allocated all the time.
|
||||||
|
Therefore, the creation of a snapshot must be triggered explicitly from the
|
||||||
|
outside world. This way, we can accommodate different strategies, for
|
||||||
|
instance, client-triggered, time-based, or based on the amount of data
|
||||||
|
written.
|
||||||
|
|
||||||
|
When creating a snapshot, it can be specified whether it shall be disposable
|
||||||
|
or persistent. A disposable snapshot will be removed automatically by the CBE
|
||||||
|
in two situations, either
|
||||||
|
|
||||||
|
* When there are not enough usable nodes in the Free Tree left to
|
||||||
|
satisfy a write request, or
|
||||||
|
* When creating a new snapshot and all slots in the superblock that might
|
||||||
|
reference snapshots are already occupied.
|
||||||
|
|
||||||
|
A persistent snapshot, or quarantine snapshot, on the other hand will never be
|
||||||
|
removed automatically. Its removal must be requested explicitly.
|
||||||
|
|
||||||
|
During initialization, the CBE selects the most recent superblock and reads the
|
||||||
|
last generation value from it. The current generation (or working state
|
||||||
|
generation) is then set to the value incremented by one. Since all old blocks,
|
||||||
|
that are still referenced by a snapshot, are never changed again, overall
|
||||||
|
consistency is guaranteed for every generation whose superblock was stored
|
||||||
|
safely on disk.
|
||||||
|
|
||||||
|
Implementation
|
||||||
|
--------------
|
||||||
|
|
||||||
|
Although we aimed for a SPARK implementation of the CBE, we saw several
|
||||||
|
obstacles with developing it in SPARK right from the beginning. These obstacles
|
||||||
|
mainly came from the fact that none of us was experienced in designing
|
||||||
|
complex software in SPARK. So we started by conducting a rapid design-space
|
||||||
|
exploration using our mother tongue (C++) while using only language features
|
||||||
|
that can be mapped 1:1 to SPARK concepts. Additionally, we applied a clear
|
||||||
|
design methodology that allowed us to keep implementation-to-test cycles
|
||||||
|
small and perform a seamless and gradual translation into SPARK:
|
||||||
|
|
||||||
|
* _Control flow_
|
||||||
|
|
||||||
|
The core logic of the CBE is a big state machine that doesn't block. On each
|
||||||
|
external event, the state machine gets poked to update itself accordingly.
|
||||||
|
C++ can call SPARK but SPARK never calls C++. The SPARK code therefore
|
||||||
|
evolves as self-contained library.
|
||||||
|
|
||||||
|
* _Modularity_
|
||||||
|
|
||||||
|
The complex state machine of the CBE as a whole is split-up into smaller
|
||||||
|
manageable sub-state-machines, working independently from each other. These
|
||||||
|
modules don't call each other directly. Instead, an additional superior
|
||||||
|
module handles the interplay. This is done by constantly iterating over all
|
||||||
|
modules with the following procedure until no further progress can be made:
|
||||||
|
|
||||||
|
# Try to enter requests of other modules into the current one
|
||||||
|
# Poke the state machine of the current module
|
||||||
|
# The current module may have generated requests - Try to enter them into
|
||||||
|
the targeted modules
|
||||||
|
# The current module may have finished requests - Acknowledge them at the
|
||||||
|
modules they came from
|
||||||
|
|
||||||
|
Each module is represented through a class (C++) respectively a package with
|
||||||
|
a private state record (SPARK).
|
||||||
|
|
||||||
|
* _No global state_
|
||||||
|
|
||||||
|
There are no static (C++) or package (SPARK) variables. All state is kept in
|
||||||
|
members of objects (C++) respectively records (SPARK). All packages are pure
|
||||||
|
and sub-programs have no side-effects. Therefore, memory management and
|
||||||
|
communication with other components is left to OS glue-code outside the
|
||||||
|
core logic.
|
||||||
|
|
||||||
|
This approach worked out well. Module by module, we were able to translate the
|
||||||
|
C++ prototype to SPARK without long untested phases, rendering all regression
|
||||||
|
bugs manageable. In Genode, the CBE library is currently integrated through
|
||||||
|
the CBE-VFS plugin. Figure [cbe_modules] depicts its current structure and the
|
||||||
|
integration via VFS plugin.
|
||||||
|
|
||||||
|
[image cbe_modules]
|
||||||
|
|
||||||
|
The green and blue boxes each represent an Ada/SPARK package. The translation
|
||||||
|
to SPARK started at the bottom of the picture moving up to the more abstract
|
||||||
|
levels until it reached the Library module. This is the module that handles
|
||||||
|
the interplay of all other modules. Its interface is the front end of the CBE
|
||||||
|
library. So, all green packages are now completely written in SPARK and
|
||||||
|
together form the CBE library. Positioned above, the CXX library in blue is
|
||||||
|
brought in by a separate library and exports the CBE interface to C++. This
|
||||||
|
way, the CBE can also be used in other environments including pure SPARK
|
||||||
|
programs. The CXX Library package is not written in SPARK but Ada and performs
|
||||||
|
all the conversions and checks required to meet the preconditions set by the
|
||||||
|
SPARK packages below.
|
||||||
|
|
||||||
|
At the C++ side, we have the VFS plugin. Even at this level, the already
|
||||||
|
mentioned procedure applies: The plugin continuously tries to enter requests
|
||||||
|
coming from the VFS client (above) into the CBE (below), pokes the CBE state
|
||||||
|
machine, and puts thereby generated block/crypto requests of the CBE into the
|
||||||
|
corresponding back-ends (left). This process is repeated until there is no
|
||||||
|
further progress without waiting for an external event.
|
||||||
|
|
||||||
|
Current state
|
||||||
|
-------------
|
||||||
|
|
||||||
|
In its current state, the CBE library is still pretty much in flux and is not
|
||||||
|
meant for productive use.
|
||||||
|
|
||||||
|
As the Free Tree does not employ copy-on-write semantics for its meta-data, a
|
||||||
|
crash, software- or hardware-wise, will corrupt the tree structure and renders
|
||||||
|
the CBE unusable on the next start.
|
||||||
|
|
||||||
|
This issue is subject to ongoing work. That being said, there are
|
||||||
|
components that, besides being used for testing, show how the interface of the
|
||||||
|
CBE library lends itself to be integrated in components in different ways. At
|
||||||
|
the moment, there are two components making use of the CBE library as
|
||||||
|
block-device provider.
|
||||||
|
|
||||||
|
The first one is the aforementioned CBE-VFS plugin. Besides r/w access to the
|
||||||
|
working tree and r/o access to all persistent snapshots, it also provides a
|
||||||
|
management interface where persistent snapshots can be created or discarded.
|
||||||
|
Its current layout is illustrated by Figure [cbe_vfs]. The VFS plugin
|
||||||
|
generates three top directories in its root directory. The first one is the
|
||||||
|
_control_ directory. It contains several pseudo files for managing the CBE:
|
||||||
|
|
||||||
|
[image cbe_vfs]
|
||||||
|
|
||||||
|
:'key': set a key by writing a string into the file.
|
||||||
|
:'create_snapshot': writing 'true' to this file will attempt to create
|
||||||
|
a new snapshot. (Eventually the snapshot will
|
||||||
|
appear in the 'snapshots' directory if it could be
|
||||||
|
created successfully.)
|
||||||
|
:'discard_snapshot': writing a snapshot ID into this file will discard
|
||||||
|
the snapshot
|
||||||
|
|
||||||
|
The second is the 'current' directory. It gives access to the current
|
||||||
|
working tree of the CBE and contains the following file:
|
||||||
|
|
||||||
|
:'data': this file represents the virtual block device and gives
|
||||||
|
read and write access to the data stored by the CBE.
|
||||||
|
|
||||||
|
The third and last is the 'snapshots' directory. For each persistent snapshot,
|
||||||
|
there is a sub-directory named after the ID of the snapshot. This directory,
|
||||||
|
like the 'current' directory, contains a 'data' file. This file, however,
|
||||||
|
gives only read access to the data belonging to the snapshot.
|
||||||
|
|
||||||
|
The CBE-VFS plugin itself uses the VFS to access the underlying block device.
|
||||||
|
It utilizes the file specified in its configuration. Here is a '<vfs>'
|
||||||
|
snippet that shows a configured CBE-VFS plugin where the block device is
|
||||||
|
provided by the block VFS plugin.
|
||||||
|
|
||||||
|
! <vfs>
|
||||||
|
! <dir name="dev">
|
||||||
|
! <block name="block"/>
|
||||||
|
! <cbe name="cbe" block="/dev/block"/>
|
||||||
|
! </dir>
|
||||||
|
! </vfs>
|
||||||
|
|
||||||
|
An exemplary ready-to-use run script can be found in the CBE repository
|
||||||
|
at _run/cbe_vfs_snaps.run_. This run script uses a bash script to
|
||||||
|
automatically perform a few operations on the CBE using the VFS plugin.
|
||||||
|
Afterwards it will drop the user into a shell where further operations
|
||||||
|
can be performed manually, e.g.:
|
||||||
|
|
||||||
|
! dd if=/dev/zero of=/dev/cbe/current/data bs=4K
|
||||||
|
|
||||||
|
The second component is the CBE server. In contrast to the CBE-VFS plugin,
|
||||||
|
it is just a simple block-session proxy component that uses a block connection
|
||||||
|
as back end to access a block-device. It provides a front-end block session to
|
||||||
|
its client, creates disposable snapshots every few seconds, and uses the
|
||||||
|
'External_Crypto' library to encrypt the data blocks using AES-CBC-ESSIV. The
|
||||||
|
used key is a plain passphrase. The following snippet illustrates its
|
||||||
|
configuration:
|
||||||
|
|
||||||
|
! <start name="cbe">
|
||||||
|
! <resource name="RAM" quantum="4M"/>
|
||||||
|
! <provides><service name="Block"/></provides>
|
||||||
|
! <config sync_interval="5" passphrase="All your base are belong to us"/>
|
||||||
|
! </start>
|
||||||
|
|
||||||
|
The _run/cbe.run_ run script in the CBE repository showcases the use of the
|
||||||
|
CBE server.
|
||||||
|
|
||||||
|
Both run scripts will create the initial CBE state in a RAM-backed
|
||||||
|
block device that is then accessed by the CBE server or the CBE-VFS
|
||||||
|
plugin.
|
||||||
|
|
||||||
|
The run-script and the code itself can be found on the
|
||||||
|
[https://github.com/cnuke/cbe/tree/cbe_19.11 - cbe/cbe_19.11] branch on
|
||||||
|
GitHub. If you intend to try it out, you have to checkout
|
||||||
|
the corresponding
|
||||||
|
[https://github.com/cnuke/genode/tree/cbe_19.11 - genode/cbe_19.11]
|
||||||
|
branch in the Genode repository as well.
|
||||||
|
|
||||||
|
Future plans
|
||||||
|
------------
|
||||||
|
|
||||||
|
Besides addressing the current shortcomings and getting the CBE library
|
||||||
|
production-ready so that it can be used in Sculpt, there are still
|
||||||
|
a few features that are currently unimplemented. For one we would like
|
||||||
|
to add support for making it possible to resize the VBD as well as the
|
||||||
|
Free Tree. For now the geometry is fixed at initialization time and cannot
|
||||||
|
be changed afterwards. Furthermore, we would like to enable re-keying,
|
||||||
|
i.e., changing the used cryptographic key and re-encrypting the tree
|
||||||
|
set of the VBD afterwards. In addition to implementing those features, the
|
||||||
|
overall tooling for the CBE needs to be improved. E.g., there is currently
|
||||||
|
no proper initialization component. For now, we rely on a component
|
||||||
|
that was built merely as a test vehicle to generate the initial trees.
|
||||||
|
|
||||||
|
|
||||||
|
Virtualization of 64-bit ARM platforms
|
||||||
|
######################################
|
||||||
|
|
||||||
|
Genode has a long history regarding support of all kinds of
|
||||||
|
virtualization-related techniques including
|
||||||
|
[https://genode.org/documentation/release-notes/9.11#Paravirtualized_Linux_on_Genode_OKL4 - para-virtualization],
|
||||||
|
[https://genode.org/documentation/articles/trustzone - TrustZone],
|
||||||
|
hardware-assisted virtualization on
|
||||||
|
[https://genode.org/documentation/articles/arm_virtualization - ARM],
|
||||||
|
[https://genode.org/documentation/release-notes/13.02#Full_virtualization_on_NOVA_x86 - x86],
|
||||||
|
up to the full virtualization stack of
|
||||||
|
[https://genode.org/documentation/release-notes/14.02#VirtualBox_on_top_of_the_NOVA_microhypervisor - VirtualBox].
|
||||||
|
|
||||||
|
We regard those techniques as welcome stop-gap solutions for using non-trivial
|
||||||
|
existing software stacks on top of Genode's clean-slate OS architecture. The
|
||||||
|
[https://genode.org/documentation/release-notes/19.05#Kernel-agnostic_virtual-machine_monitors - recent]
|
||||||
|
introduction of a kernel-agnostic interface to control virtual machines (VM)
|
||||||
|
ushered a new level for the construction respectively porting of
|
||||||
|
virtual-machine monitors (VMM). By introducing a new ARMv8-compliant VMM
|
||||||
|
developed from scratch, we continue this line of work.
|
||||||
|
|
||||||
|
The new VMM builds upon our existing proof-of-concept (PoC) implementation for
|
||||||
|
ARMv7 as introduced in release
|
||||||
|
[https://genode.org/documentation/release-notes/15.02#Virtualization_on_ARM - 15.02].
|
||||||
|
In contrast to the former PoC implementation, however, it aims to be complete
|
||||||
|
to a greater extent. Currently, it comprises device models for the following
|
||||||
|
virtual hardware:
|
||||||
|
|
||||||
|
* RAM
|
||||||
|
* System Bus
|
||||||
|
* CPU
|
||||||
|
* Generic Interrupt Controller v2 and v3
|
||||||
|
* Generic Timer
|
||||||
|
* PL011 UART (limited)
|
||||||
|
* Pass-through devices
|
||||||
|
|
||||||
|
The VMM is able to load diverse 64-bit Linux kernels including
|
||||||
|
Device-Tree-Binary (DTB) and Initramfs. Currently, the implementation uses a
|
||||||
|
fixed memory layout for the guest-physical memory view, which needs to be
|
||||||
|
reflected by the DTB used by the guest OS. An example device-tree source file
|
||||||
|
can be found at _repos/os/src/server/vmm/spec/arm_v8/virt.dts_. The actual VMM
|
||||||
|
is located in the same directory.
|
||||||
|
|
||||||
|
Although support for multi-core VMs is already considered internally, it is
|
||||||
|
not yet finished. Further outstanding features that are already in development
|
||||||
|
are Virtio device model support for networking and console. As the first - and
|
||||||
|
by now only - back end, we tied the VMM to the ARMv8 broadened Kernel-agnostic
|
||||||
|
VM-session interface as implemented by Genode's custom base-hw kernel. As a
|
||||||
|
side effect of this work, we consolidated the generic VM session interface
|
||||||
|
slightly. The RPC call to create a new virtual-CPU now returns an identifier
|
||||||
|
for identification.
|
||||||
|
|
||||||
|
The VMM has a strict dependency on ARM's hardware virtualization support
|
||||||
|
(EL2), which comprises extensions for the ARMv8-A CPU, ARM's generic timer,
|
||||||
|
and ARM's GIC. This rules out the Raspberry Pi 3 board as a base platform
|
||||||
|
because it does not include a GIC but a custom interrupt-controller without
|
||||||
|
hardware-assisted virtualization of interrupts. To give the new VMM a try, we
|
||||||
|
recommend using the run script _repos/os/run/vmm_arm.run_ as a starting point
|
||||||
|
for executing the VMM on top of the i.MX8 Evaluation Kit board.
|
||||||
|
|
||||||
|
|
||||||
|
New tooling for bridging existing build systems with Genode
|
||||||
|
###########################################################
|
||||||
|
|
||||||
|
Genode's development tools are powerful and intimidating at the same time.
|
||||||
|
Being designed from the perspective of a whole-systems developer, they put
|
||||||
|
emphasis on the modularity of the code base (separating concerns like
|
||||||
|
different kernels or system abstraction levels), transitive dependency
|
||||||
|
tracking between libraries, scripting of a wide variety of system-integration
|
||||||
|
tasks, and the continuous integration of complete Genode-based
|
||||||
|
operating-system scenarios. Those tools are a two-edged sword though.
|
||||||
|
|
||||||
|
On the one hand, the tools are key for the productivity of seasoned Genode
|
||||||
|
developers once the potential of the tools is fully understood and leveraged.
|
||||||
|
For example, during the development of Sculpt OS, we are able to
|
||||||
|
change an arbitrary line of code in any system component and can test-drive
|
||||||
|
the resulting Sculpt system on real hardware within a couple of seconds.
|
||||||
|
As another example, the almost seamless switching from one OS kernel to
|
||||||
|
another has become a daily routine that we just take for granted without
|
||||||
|
even thinking about it.
|
||||||
|
|
||||||
|
On the other hand, the sophistication of the tools stands in the way of
|
||||||
|
application developers who are focused on a particular component instead
|
||||||
|
of the holistic Genode system. In this case, the powerful system-integration
|
||||||
|
features remain unused but the complexity of the tools and the build system
|
||||||
|
prevails. Speaking of build systems, this topic is ripe of emotions
|
||||||
|
anyway. _Developers use to hate build systems._ Forcing Genode's build
|
||||||
|
system down the throats of application developers is probably not the best
|
||||||
|
idea to make Genode popular.
|
||||||
|
|
||||||
|
This line of thoughts prompted us to re-approach the tooling for Genode from
|
||||||
|
the perspective of an application developer. The intermediate result is a new
|
||||||
|
tool called Goa:
|
||||||
|
|
||||||
|
:Goa project at GitHub:
|
||||||
|
|
||||||
|
[https://github.com/nfeske/goa]
|
||||||
|
|
||||||
|
Unlike Genode's regular tools, Goa's work flow is project-centered. A project
|
||||||
|
is a directory that may contain source code, data, instructions how to
|
||||||
|
download source codes from a 3rd party, descriptions of system scenarios, or
|
||||||
|
combinations thereof. Goa is independent from Genode's regular build system.
|
||||||
|
It combines Genode's package management (depot) with commodity build systems
|
||||||
|
such a CMake. In addition to building and test-driving application software
|
||||||
|
directly on a Linux-based development system, Goa is able to aid the process
|
||||||
|
of exporting and packaging the software in the format expected by Genode
|
||||||
|
systems like Sculpt OS.
|
||||||
|
|
||||||
|
At the current stage, Goa should be considered as work in progress. It's a new
|
||||||
|
approach and its success is anything but proven. That said, if you are
|
||||||
|
interested in developing or porting application software for Genode, your
|
||||||
|
feedback would be especially valuable. As a starting point, you may find the
|
||||||
|
following introductory article helpful:
|
||||||
|
|
||||||
|
:Goa - streamlining the development of Genode applications:
|
||||||
|
|
||||||
|
[https://genodians.org/nfeske/2019-11-25-goa]
|
||||||
|
|
||||||
|
|
||||||
|
Base framework and OS-level infrastructure
|
||||||
|
##########################################
|
||||||
|
|
||||||
|
File-system session
|
||||||
|
===================
|
||||||
|
|
||||||
|
The file-system session interface received a much anticipated update.
|
||||||
|
|
||||||
|
Writing modification times
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
The new operation WRITE_TIMESTAMP allows a client to update the modification
|
||||||
|
time of a file-system node. The time is defined by the client to keep
|
||||||
|
file-system servers free from time-related concerns. The VFS server implements
|
||||||
|
the operation by forwarding it to the VFS plugin interface. At present, this
|
||||||
|
new interface is implemented by the rump VFS plugin to store modification
|
||||||
|
times on EXT2 file systems.
|
||||||
|
|
||||||
|
|
||||||
|
Enhanced file-status info
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
The status of a file-system node as returned by the 'File_system::Status'
|
||||||
|
operation has been revisited. First, we replaced the fairly opaque "mode" bits -
|
||||||
|
which were an ad-hoc attempt to stay compatible with Unix - with the explicit
|
||||||
|
notion of 'readable', 'writeable', and 'executable' attributes. We completely
|
||||||
|
dropped the notion of users and groups. Second, we added the distinction
|
||||||
|
between *continuous* and *transactional* files to allow for the robust
|
||||||
|
implementation of continuous write operations across component boundaries. A
|
||||||
|
continuous file can be written-to via a sequence of arbitrarily sized chunks
|
||||||
|
of data. For such files, a client can split a large write operation into any
|
||||||
|
number of smaller operations in accordance to the size of the used I/O
|
||||||
|
buffers. In contrast, a write to a transactional file is regarded as a
|
||||||
|
distinct operation. The canonical example of a transactional file is a
|
||||||
|
socket-control pseudo file.
|
||||||
|
|
||||||
|
|
||||||
|
Virtual file-system infrastructure
|
||||||
|
==================================
|
||||||
|
|
||||||
|
First fragments of a front-end API
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The VFS is mostly used indirectly via the C runtime. However, it is also
|
||||||
|
useful for a few components that use the Genode API directly without any
|
||||||
|
libc. To accommodate such users of the VFS, we introduced the front-end
|
||||||
|
API at _os/vfs.h_ that covers a variety of current use cases. Currently, those
|
||||||
|
use cases revolve around the watching, reading, and parsing of files and
|
||||||
|
file-system structures - as performed by Sculpt's deployment mechanism.
|
||||||
|
Writing to files is not covered.
|
||||||
|
|
||||||
|
|
||||||
|
Improved file-watching support
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
All pseudo files that use the VFS-internal 'Readonly_value_file_system'
|
||||||
|
utility have become able to deliver watch notifications. This change enables
|
||||||
|
VFS clients to respond to VFS-plugin events (think of terminal resize)
|
||||||
|
dynamically.
|
||||||
|
|
||||||
|
Speaking of the *terminal VFS plugin*, the current release enhances the plugin
|
||||||
|
in several respects. First, it now delivers status information such as the
|
||||||
|
terminal size via pseudo files. Second, we equipped the VFS terminal file
|
||||||
|
system with the ability to detect user interrupts in the incoming data stream,
|
||||||
|
and propagate this information via the new pseudo file '.terminal/interrupts'.
|
||||||
|
Each time, the user presses control-c in the terminal, the value stored in
|
||||||
|
this pseudo file is increased. Thereby, a VFS client can watch this file to
|
||||||
|
get notified about the occurrences of user interrupts.
|
||||||
|
|
||||||
|
|
||||||
|
VFS plugin for emulating POSIX pipes
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
We added a new VFS plugin for emulating POSIX pipes. The new plugin creates
|
||||||
|
pipes between pairs of VFS handles. It replaces the deprecated libc_pipe
|
||||||
|
plugin. In contrast to the libc_pipe plugin, which was limited to pipes within
|
||||||
|
one component, the new VFS plugin can also be used to establish pipes between
|
||||||
|
different components by mounting the plugin at a shared VFS server.
|
||||||
|
|
||||||
|
|
||||||
|
C runtime with improved POSIX compatibility
|
||||||
|
===========================================
|
||||||
|
|
||||||
|
Within Genode, we used to think of POSIX as a legacy that is best avoided.
|
||||||
|
In fact, the foundational components of the framework do not depend on a
|
||||||
|
C runtime at all. However, higher up the software stack - at the latest when
|
||||||
|
3rd-party libraries enter the picture - a working C runtime is unavoidable. In
|
||||||
|
this statement, the term "working" is rather muddy though. Since we have never
|
||||||
|
fully embraced POSIX, we were content with cutting corners here and there. For
|
||||||
|
example, given Genode's architecture, supporting 'fork' and 'execve' seemed
|
||||||
|
totally out of question because those mechanisms would go against the grain of
|
||||||
|
Genode.
|
||||||
|
|
||||||
|
However, our growing aspiration to bridge the gap between existing popular
|
||||||
|
applications and Genode made us re-evaluate our stance towards POSIX.
|
||||||
|
All technical criticism aside, POSIX is immensely useful because it is
|
||||||
|
a universally accepted stable interface. To dissolve friction between
|
||||||
|
Genode and popular application software, we have to satisfy the application's
|
||||||
|
expectations. This ignited a series of developments, in particular
|
||||||
|
the added support for 'fork' and 'execve' - of all things - in
|
||||||
|
[https://genode.org/documentation/release-notes/19.08#Consolidation_of_the_C_runtime_and_Noux - Genode 19.08],
|
||||||
|
which was nothing short of surprising, even to us.
|
||||||
|
The current release continues this line of development and brings the
|
||||||
|
following improvements.
|
||||||
|
|
||||||
|
|
||||||
|
Execve
|
||||||
|
------
|
||||||
|
|
||||||
|
The libc's 'execve' implementation got enhanced to evaluate the path of the
|
||||||
|
executable binary according to the information found on the VFS, in particular
|
||||||
|
by traversing directories and following symbolic links. This enables the libc
|
||||||
|
to execute files stored at sub directories of the file system.
|
||||||
|
|
||||||
|
Furthermore, 'execve' received handling for *executing shell scripts* by
|
||||||
|
parsing the shebang marker at the beginning of the executable file. This way,
|
||||||
|
the 'execve' mechanism of the libc reaches parity with the feature set of the
|
||||||
|
Noux runtime that we traditionally used to host Unix software on top of
|
||||||
|
Genode.
|
||||||
|
|
||||||
|
|
||||||
|
Modification-time handling
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
By default, the libc uses the just added facility for updating the timestamp
|
||||||
|
of file-system nodes when closing a written-to file, which clears the path
|
||||||
|
towards using tools like 'make' that rely on file-modifications times.
|
||||||
|
|
||||||
|
The libc's mechanism can be explicitly disabled by specifying
|
||||||
|
! <libc update_mtime="no"...>
|
||||||
|
This is useful for applications that have no legitimate access to a time
|
||||||
|
source.
|
||||||
|
|
||||||
|
|
||||||
|
Emulation of 'ioctl' operations via pseudo files
|
||||||
|
------------------------------------------------
|
||||||
|
|
||||||
|
With the current release, we introduce a new scheme of handling ioctl
|
||||||
|
operations, which maps 'ioctl' calls to pseudo-file accesses, similar to how
|
||||||
|
the libc already maps socket calls to socket-fs operations.
|
||||||
|
|
||||||
|
A device file can be accompanied with a (hidden) directory that is named after
|
||||||
|
the device file and hosts pseudo files for triggering the various device
|
||||||
|
operations. For example, for accessing a terminal, the directory structure
|
||||||
|
looks like this:
|
||||||
|
|
||||||
|
! /dev/terminal
|
||||||
|
! /dev/.terminal/info
|
||||||
|
! /dev/.terminal/rows
|
||||||
|
! /dev/.terminal/columns
|
||||||
|
! /dev/.terminal/interrupts
|
||||||
|
|
||||||
|
The 'info' file contains device information in XML format. The type of the XML
|
||||||
|
node corresponds to the device type. Whenever the libc receives a TIOCGWINSZ
|
||||||
|
ioctl for _/dev/terminal_, it reads the content of _/dev/.terminal/info_ to
|
||||||
|
obtain the terminal-size information. In this case, the _info_ file looks as
|
||||||
|
follows:
|
||||||
|
|
||||||
|
! <terminal rows="25" columns="80/>
|
||||||
|
|
||||||
|
Following this scheme, VFS plugins can support ioctl operations by providing
|
||||||
|
an ioctl directory in addition to the actual device file.
|
||||||
|
|
||||||
|
|
||||||
|
Emulation of POSIX signals
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
Even though there is no notion of POSIX signals at the Genode level, we
|
||||||
|
can reasonably emulate certain POSIX signals at the libc level. The current
|
||||||
|
release introduces the first bunch of such emulated signals:
|
||||||
|
|
||||||
|
:SIGWINCH: If 'stdout' is connected to a terminal, the libc watches the
|
||||||
|
terminal's ioctl pseudo file _.terminal/info_. Whenever the terminal
|
||||||
|
size changes, the POSIX signal SIGWINCH is delivered to the application.
|
||||||
|
With this improvement, Vim becomes able to dynamically adjust itself
|
||||||
|
to changed window dimensions when started as a native Genode component
|
||||||
|
(w/o the Noux runtime environment).
|
||||||
|
|
||||||
|
:SIGINT: If 'stdin' is connected to a terminal, the libc watches the
|
||||||
|
terminal's pseudo file _.terminal/interrupts_. Since, the terminal VFS
|
||||||
|
plugin modifies the file for each occurred user interrupt (control-c),
|
||||||
|
the libc is able to reflect such an event as SIGINT signal to the
|
||||||
|
application.
|
||||||
|
|
||||||
|
:Process-local signal delivery: The libc's implementation of 'kill' got
|
||||||
|
enhanced with the ability to submit signals to the local process.
|
||||||
|
|
||||||
|
|
||||||
|
Support for arbitrarily large write operations
|
||||||
|
----------------------------------------------
|
||||||
|
|
||||||
|
The number of bytes written by a single 'write' call used to be constrained by
|
||||||
|
the file's underlying I/O buffer size. Even though our libc correctly returned
|
||||||
|
this information to the application, we found that real-world applications
|
||||||
|
rarely check the return value of 'write' because partial writes do usually not
|
||||||
|
occur on popular POSIX systems. Thanks to the added distinction between
|
||||||
|
continuous and transactional files as described in Section
|
||||||
|
[File-system session], we became able to improve the libc's write operation to
|
||||||
|
iterate on partial writes to continuous files until the original write count
|
||||||
|
is reached. The split of large write operations into small partial writes as
|
||||||
|
dictated by the VFS infrastructure becomes invisible to the libc-using
|
||||||
|
application.
|
||||||
|
|
||||||
|
|
||||||
|
Input-event handling
|
||||||
|
====================
|
||||||
|
|
||||||
|
In Genode 19.08, we undertook a comprehensive rework of our keyboard-event
|
||||||
|
handling in the light of localization and also promised to tie up remaining
|
||||||
|
loose ends soon.
|
||||||
|
|
||||||
|
First, we again dived into our character generators for a thorough check of
|
||||||
|
our stack of keyboards and fixed remaining inconsistencies in French and
|
||||||
|
German layouts. En passant, we also increased the default RAM quotas for
|
||||||
|
the input filter to 1280K in our recipes to cope with the increased
|
||||||
|
layout-configuration sizes in corner cases.
|
||||||
|
|
||||||
|
Next - and more importantly - we subdued the monsters lurking in our Qt5
|
||||||
|
keyboard back end and enabled transparent support for system-wide keyboard
|
||||||
|
layout configuration for Qt5 components. One important change during this work
|
||||||
|
was to move the handling of control key sequences into the clients. For
|
||||||
|
example, the graphical terminal and Qt5 interpret key events in combination
|
||||||
|
with the CTRL modifier based on characters and, thus, support CTRL-A with
|
||||||
|
AZERTY and QWERTY layouts correctly. As a result we removed all CTRL modifier
|
||||||
|
(mod2) configurations from our character-generator configurations.
|
||||||
|
|
||||||
|
Finally we'd like to point out one important change of our rework that
|
||||||
|
repeatedly led to surprises: For keys without character mappings the reworked
|
||||||
|
character-generator mechanism emits invalid codepoints in contrast to
|
||||||
|
codepoints with value 0. For that reason, components interpreting character
|
||||||
|
events should check 'Codepoint::valid()' to prevent the processing of invalid
|
||||||
|
characters (and not the frequent pattern of 'codepoint.value != 0').
|
||||||
|
|
||||||
|
|
||||||
|
NIC router
|
||||||
|
==========
|
||||||
|
|
||||||
|
The NIC router has received the ability to report the link state of its NIC
|
||||||
|
interfaces (downlinks and uplinks). To control this mechanism, there are two
|
||||||
|
new boolean attributes 'link_state' and 'link_state_triggers' in the <report>
|
||||||
|
tag of the NIC router configuration. If the former is set to "true", the report
|
||||||
|
will contain the current link state for each interface:
|
||||||
|
|
||||||
|
! <domain name="domain1">
|
||||||
|
! <interface label="uplink1" link_state="false"/>
|
||||||
|
! <interface label="downlink1" link_state="true"/>
|
||||||
|
! </domain>
|
||||||
|
! <domain name="domain2">
|
||||||
|
! <interface label="downlink2" link_state="true"/>
|
||||||
|
! </domain>
|
||||||
|
|
||||||
|
The second attribute decides whether to trigger a report update each time the
|
||||||
|
link state of an interface changes. By default, both attributes are set to
|
||||||
|
"false".
|
||||||
|
|
||||||
|
|
||||||
|
Device drivers
|
||||||
|
==============
|
||||||
|
|
||||||
|
Platform driver on x86
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
During our enablement of Genode on a
|
||||||
|
[https://genodians.org/chelmuth/2019-10-21-sculpt-elitebook - recent notebook],
|
||||||
|
we spotted some PC platform shortcomings, we address with this release. Most
|
||||||
|
prominently we added support for
|
||||||
|
[https://en.wikipedia.org/wiki/PCI_configuration_space#Bus_enumeration - 64-bit PCI base address registers]
|
||||||
|
to the x86 platform driver. This allows the use of PCI devices that are
|
||||||
|
assigned to physical I/O-memory regions beyond 4 GiB by the boot firmware.
|
||||||
|
|
||||||
|
|
||||||
|
Wireless driver
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
We added the firmware images for the 5000 and 9000 series of Intel wireless
|
||||||
|
devices to the firmware white-list in the _wifi_drv_ component. Such devices
|
||||||
|
as 5100AGN, 5300AGN and 5350AGN as well as 9461, 9462 and 9560 should now be
|
||||||
|
usable on Genode.
|
||||||
|
|
||||||
|
|
||||||
|
Libraries and applications
|
||||||
|
##########################
|
||||||
|
|
||||||
|
VirtualBox improvements
|
||||||
|
=======================
|
||||||
|
|
||||||
|
The GUI handling of our VirtualBox port got improved to react on window-size
|
||||||
|
changes more instantly. The effect is that an interactive adjustment of the
|
||||||
|
window size, e.g., on Sculpt, becomes quickly visible to the user. Still, the
|
||||||
|
VM may take some time to adjust to the resolution change, which ultimately
|
||||||
|
depends on the behavior of the driver of the VirtualBox guest additions.
|
||||||
|
|
||||||
|
|
||||||
|
Updated 3rd-party software
|
||||||
|
==========================
|
||||||
|
|
||||||
|
With the addition of the 64-bit ARM architecture (AARCH64) with the
|
||||||
|
[https://genode.org/documentation/release-notes/19.05#Broadened_CPU_architecture_support_and_updated_tool_chain - 19.05]
|
||||||
|
release, it became necessary to update the libraries the Genode tool chain
|
||||||
|
(gcc) depends on in order to support AARCH64 properly. This concerns the GNU
|
||||||
|
multi precision arithmetic library (gmp), which has been updated from version
|
||||||
|
4.3.2 to 6.1.2, as well as the libraries that depend on it: Multi precision
|
||||||
|
floating point (mpfr) and multi precision complex arithmetic (mpc). All those
|
||||||
|
old versions did not offer support for the AARCH64 architecture, which is a
|
||||||
|
requirement to make Genode self hosting. Targets for building binutils and GCC
|
||||||
|
within Genode for AARCH64 are in place, GNU make is in place, and even code
|
||||||
|
coverage (gcov) has been added. This work puts AARCH64 in line with other
|
||||||
|
supported CPU architectures and emphasizes our interest in the ARM 64-bit
|
||||||
|
architecture.
|
||||||
|
|
||||||
|
|
||||||
|
Platforms
|
||||||
|
#########
|
||||||
|
|
||||||
|
Execution on bare hardware (base-hw)
|
||||||
|
====================================
|
||||||
|
|
||||||
|
With the previous release, Genode's base-hw kernel got extended to support the
|
||||||
|
ARMv8-A architecture in principle. The first hardware supported was the
|
||||||
|
Raspberry Pi 3 as well as the i.MX8 evaluation kit (EVK). But only a single
|
||||||
|
CPU-core was usable at that time. Now, we lifted this limitation. On both
|
||||||
|
boards, all four CPU-cores are available henceforth.
|
||||||
|
|
||||||
|
|
||||||
|
Removed components
|
||||||
|
##################
|
||||||
|
|
||||||
|
The current release removes the following components:
|
||||||
|
|
||||||
|
:gems/src/app/launcher:
|
||||||
|
|
||||||
|
The graphical launcher remained unused for a few years now. It is not
|
||||||
|
suitable for systems as flexible as Sculpt OS.
|
||||||
|
|
||||||
|
:os/src/app/cli_monitor:
|
||||||
|
|
||||||
|
CLI monitor was a runtime environment with a custom command-line interface
|
||||||
|
to start and stop subsystems. It was part of the user interface of our
|
||||||
|
first take on a Genode-based desktop OS called
|
||||||
|
[https://genode.org/documentation/release-notes/15.11#Genode_as_desktop_OS - Turmvilla].
|
||||||
|
|
||||||
|
Nowadays, we use standard command-line tools like Vim to edit init
|
||||||
|
configurations dynamically, which is more flexible and - at the same time -
|
||||||
|
alleviates the need for a custom CLI. The CLI-monitor component was too
|
||||||
|
limited for use cases like Sculpt anyway.
|
||||||
|
|
||||||
|
Along with the CLI monitor, we removed the ancient (and untested for long
|
||||||
|
time) _terminal_mux.run_ script, which was the only remaining user of the CLI
|
||||||
|
monitor.
|
||||||
|
|
||||||
|
:fatfs_fs, rump_fs, and libc_fatfs plugin:
|
||||||
|
|
||||||
|
The stand-alone file-system servers fatfs_fs and rump_fs as well as the
|
||||||
|
fatfs libc plugin have been superseded by the fatfs and rump VFS plugins.
|
||||||
|
The stand-alone servers can be replaced by using the VFS server plus the
|
||||||
|
corresponding VFS plugin as a drop-in replacement.
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-09-19 b0d371ca01b27c5b09fd55732681ab9e2cede5d5
|
2019-11-25 c7e2a3eca5820b2304b4520d0fc831ede73691f2
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-09-19 59410c274229c50f68d0fd65d52cc730a4b0f55b
|
2019-11-25 9a459c4fd8a907810d91041751affcf3e119fcb1
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-09-19 30eff00614afebb83d4be10a61d8d0f3b3fa8c33
|
2019-11-25 d8ff4913b8aa117aef77a7918bc82808e38a4ee7
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-09-19 e2ce197e4ed2239ed2688c8bab5ea98f5e87d439
|
2019-11-25 a750c8988106d5c26e46dcceb1f76bfd7bfa1457
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-09-19 d3481851efe9091caf413496883a03875a298b90
|
2019-11-25 0c0a26b6ddb0ee5261f0be30f229e9ce04b61eda
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-09-19 c842719c606b0ec3eed05255761665737cecf208
|
2019-11-25 bce6f0a8f1f46f8edf62ef2180dbfc949123432d
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-09-19 d3bf4e77c5f352efcf384b57be11668d6047ecf3
|
2019-11-25 307d01e531dbbcd672463a4ea090f40bb399cae8
|
||||||
|
|
|
@ -108,7 +108,7 @@ class Genode::Vm_session_component
|
||||||
void attach(Dataspace_capability, addr_t, Attach_attr) override;
|
void attach(Dataspace_capability, addr_t, Attach_attr) override;
|
||||||
void attach_pic(addr_t) override { }
|
void attach_pic(addr_t) override { }
|
||||||
void detach(addr_t, size_t) override;
|
void detach(addr_t, size_t) override;
|
||||||
void _create_vcpu(Thread_capability);
|
Vcpu_id _create_vcpu(Thread_capability);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _CORE__VM_SESSION_COMPONENT_H_ */
|
#endif /* _CORE__VM_SESSION_COMPONENT_H_ */
|
||||||
|
|
|
@ -107,10 +107,12 @@ Vcpu::~Vcpu()
|
||||||
_ram_alloc.free(_ds_cap);
|
_ram_alloc.free(_ds_cap);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Vm_session_component::_create_vcpu(Thread_capability cap)
|
Vm_session::Vcpu_id Vm_session_component::_create_vcpu(Thread_capability cap)
|
||||||
{
|
{
|
||||||
|
Vcpu_id ret;
|
||||||
|
|
||||||
if (!cap.valid())
|
if (!cap.valid())
|
||||||
return;
|
return ret;
|
||||||
|
|
||||||
auto lambda = [&] (Cpu_thread_component *thread) {
|
auto lambda = [&] (Cpu_thread_component *thread) {
|
||||||
if (!thread)
|
if (!thread)
|
||||||
|
@ -146,10 +148,11 @@ void Vm_session_component::_create_vcpu(Thread_capability cap)
|
||||||
}
|
}
|
||||||
|
|
||||||
_vcpus.insert(vcpu);
|
_vcpus.insert(vcpu);
|
||||||
_id_alloc++;
|
ret.id = _id_alloc++;
|
||||||
};
|
};
|
||||||
|
|
||||||
_ep.apply(cap, lambda);
|
_ep.apply(cap, lambda);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Dataspace_capability Vm_session_component::_cpu_state(Vcpu_id const vcpu_id)
|
Dataspace_capability Vm_session_component::_cpu_state(Vcpu_id const vcpu_id)
|
||||||
|
|
|
@ -50,7 +50,6 @@ static bool svm_np() { return svm_features() & (1U << 0); }
|
||||||
struct Vcpu;
|
struct Vcpu;
|
||||||
|
|
||||||
static Genode::Registry<Genode::Registered<Vcpu> > vcpus;
|
static Genode::Registry<Genode::Registered<Vcpu> > vcpus;
|
||||||
static unsigned vcpu_id = 0;
|
|
||||||
|
|
||||||
struct Vcpu : Genode::Thread
|
struct Vcpu : Genode::Thread
|
||||||
{
|
{
|
||||||
|
@ -202,7 +201,7 @@ struct Vcpu : Genode::Thread
|
||||||
Semaphore _wake_up { 0 };
|
Semaphore _wake_up { 0 };
|
||||||
Semaphore &_handler_ready;
|
Semaphore &_handler_ready;
|
||||||
Allocator &_alloc;
|
Allocator &_alloc;
|
||||||
Vm_session_client::Vcpu_id _id;
|
Vm_session_client::Vcpu_id _id { Vm_session_client::Vcpu_id::INVALID };
|
||||||
addr_t _state { 0 };
|
addr_t _state { 0 };
|
||||||
addr_t _task { 0 };
|
addr_t _task { 0 };
|
||||||
enum Virt const _vm_type;
|
enum Virt const _vm_type;
|
||||||
|
@ -1184,20 +1183,20 @@ struct Vcpu : Genode::Thread
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Vcpu(Env &env, Signal_context_capability &cap,
|
Vcpu(Env &env, Signal_context_capability &cap,
|
||||||
Semaphore &handler_ready,
|
Semaphore &handler_ready, enum Virt type,
|
||||||
Vm_session_client::Vcpu_id &id, enum Virt type,
|
|
||||||
Allocator &alloc, Affinity::Location location)
|
Allocator &alloc, Affinity::Location location)
|
||||||
:
|
:
|
||||||
Thread(env, "vcpu_thread", STACK_SIZE, location, Weight(), env.cpu()),
|
Thread(env, "vcpu_thread", STACK_SIZE, location, Weight(), env.cpu()),
|
||||||
_signal(cap), _handler_ready(handler_ready), _alloc(alloc),
|
_signal(cap), _handler_ready(handler_ready), _alloc(alloc),
|
||||||
_id(id), _vm_type(type)
|
_vm_type(type)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
Allocator &allocator() const { return _alloc; }
|
Allocator &allocator() const { return _alloc; }
|
||||||
|
|
||||||
bool match(Vm_session_client::Vcpu_id id) { return id.id == _id.id; }
|
bool match(Vm_session_client::Vcpu_id id) { return id.id == _id.id; }
|
||||||
|
|
||||||
Genode::Vm_session_client::Vcpu_id id() const { return _id; }
|
Genode::Vm_session_client::Vcpu_id id() const { return _id; }
|
||||||
|
void id(Genode::Vm_session_client::Vcpu_id id) { _id = id; }
|
||||||
|
|
||||||
void assign_ds_state(Region_map &rm, Dataspace_capability cap)
|
void assign_ds_state(Region_map &rm, Dataspace_capability cap)
|
||||||
{
|
{
|
||||||
|
@ -1266,12 +1265,10 @@ Vm_session_client::Vcpu_id
|
||||||
Vm_session_client::create_vcpu(Allocator &alloc, Env &env,
|
Vm_session_client::create_vcpu(Allocator &alloc, Env &env,
|
||||||
Vm_handler_base &handler)
|
Vm_handler_base &handler)
|
||||||
{
|
{
|
||||||
Vm_session_client::Vcpu_id id = { vcpu_id };
|
|
||||||
|
|
||||||
enum Virt vm_type = virt_type(env);
|
enum Virt vm_type = virt_type(env);
|
||||||
if (vm_type == Virt::UNKNOWN) {
|
if (vm_type == Virt::UNKNOWN) {
|
||||||
Genode::error("unsupported hardware virtualisation");
|
Genode::error("unsupported hardware virtualisation");
|
||||||
return id;
|
return Vm_session::Vcpu_id();
|
||||||
}
|
}
|
||||||
|
|
||||||
Thread * ep = reinterpret_cast<Thread *>(&handler._rpc_ep);
|
Thread * ep = reinterpret_cast<Thread *>(&handler._rpc_ep);
|
||||||
|
@ -1279,17 +1276,17 @@ Vm_session_client::create_vcpu(Allocator &alloc, Env &env,
|
||||||
|
|
||||||
/* create thread that switches modes between thread/cpu */
|
/* create thread that switches modes between thread/cpu */
|
||||||
Vcpu * vcpu = new (alloc) Registered<Vcpu>(vcpus, env, handler._cap,
|
Vcpu * vcpu = new (alloc) Registered<Vcpu>(vcpus, env, handler._cap,
|
||||||
handler._done, id, vm_type,
|
handler._done, vm_type,
|
||||||
alloc, location);
|
alloc, location);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
/* now it gets actually valid - vcpu->cap() becomes valid */
|
/* now it gets actually valid - vcpu->cap() becomes valid */
|
||||||
vcpu->start();
|
vcpu->start();
|
||||||
|
|
||||||
call<Rpc_exception_handler>(handler._cap, vcpu->id());
|
|
||||||
|
|
||||||
/* instruct core to let it become a vCPU */
|
/* instruct core to let it become a vCPU */
|
||||||
call<Rpc_create_vcpu>(vcpu->cap());
|
vcpu->id(call<Rpc_create_vcpu>(vcpu->cap()));
|
||||||
|
|
||||||
|
call<Rpc_exception_handler>(handler._cap, vcpu->id());
|
||||||
|
|
||||||
vcpu->assign_ds_state(env.rm(), call<Rpc_cpu_state>(vcpu->id()));
|
vcpu->assign_ds_state(env.rm(), call<Rpc_cpu_state>(vcpu->id()));
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
|
@ -1299,9 +1296,7 @@ Vm_session_client::create_vcpu(Allocator &alloc, Env &env,
|
||||||
destroy(alloc, vcpu);
|
destroy(alloc, vcpu);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
return vcpu->id();
|
||||||
vcpu_id ++;
|
|
||||||
return id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Vm_session_client::run(Vcpu_id vcpu_id)
|
void Vm_session_client::run(Vcpu_id vcpu_id)
|
||||||
|
|
109
repos/base-hw/include/spec/arm_64/cpu/vm_state_virtualization.h
Normal file
109
repos/base-hw/include/spec/arm_64/cpu/vm_state_virtualization.h
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
/*
|
||||||
|
* \brief CPU, PIC, and timer context of a virtual machine
|
||||||
|
* \author Stefan Kalkowski
|
||||||
|
* \date 2015-02-10
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015-2017 Genode Labs GmbH
|
||||||
|
*
|
||||||
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INCLUDE__SPEC__ARM_64__CPU__VM_STATE_VIRTUALIZATION_H_
|
||||||
|
#define _INCLUDE__SPEC__ARM_64__CPU__VM_STATE_VIRTUALIZATION_H_
|
||||||
|
|
||||||
|
/* Genode includes */
|
||||||
|
#include <cpu/cpu_state.h>
|
||||||
|
|
||||||
|
namespace Genode
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* CPU context of a virtual machine
|
||||||
|
*/
|
||||||
|
struct Vm_state;
|
||||||
|
|
||||||
|
using uint128_t = __uint128_t;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Genode::Vm_state : Genode::Cpu_state
|
||||||
|
{
|
||||||
|
Genode::uint64_t pstate { 0 };
|
||||||
|
Genode::uint64_t exception_type { 0 };
|
||||||
|
Genode::uint64_t esr_el2 { 0 };
|
||||||
|
|
||||||
|
/** Fpu registers **/
|
||||||
|
Genode::uint128_t q[32] { 0 };
|
||||||
|
Genode::uint32_t fpcr { 0 };
|
||||||
|
Genode::uint32_t fpsr { 0 };
|
||||||
|
|
||||||
|
Genode::uint64_t elr_el1 { 0 };
|
||||||
|
Genode::uint64_t sp_el1 { 0 };
|
||||||
|
Genode::uint32_t spsr_el1 { 0 };
|
||||||
|
Genode::uint32_t esr_el1 { 0 };
|
||||||
|
|
||||||
|
Genode::uint64_t sctlr_el1 { 0 };
|
||||||
|
Genode::uint64_t actlr_el1 { 0 };
|
||||||
|
Genode::uint64_t vbar_el1 { 0 };
|
||||||
|
Genode::uint32_t cpacr_el1 { 0 };
|
||||||
|
Genode::uint32_t afsr0_el1 { 0 };
|
||||||
|
Genode::uint32_t afsr1_el1 { 0 };
|
||||||
|
Genode::uint32_t contextidr_el1 { 0 };
|
||||||
|
|
||||||
|
Genode::uint64_t ttbr0_el1 { 0 };
|
||||||
|
Genode::uint64_t ttbr1_el1 { 0 };
|
||||||
|
Genode::uint64_t tcr_el1 { 0 };
|
||||||
|
Genode::uint64_t mair_el1 { 0 };
|
||||||
|
Genode::uint64_t amair_el1 { 0 };
|
||||||
|
Genode::uint64_t far_el1 { 0 };
|
||||||
|
Genode::uint64_t par_el1 { 0 };
|
||||||
|
|
||||||
|
Genode::uint64_t tpidrro_el0 { 0 };
|
||||||
|
Genode::uint64_t tpidr_el0 { 0 };
|
||||||
|
Genode::uint64_t tpidr_el1 { 0 };
|
||||||
|
|
||||||
|
Genode::uint64_t vmpidr_el2 { 0 };
|
||||||
|
|
||||||
|
Genode::uint64_t far_el2 { 0 };
|
||||||
|
Genode::uint64_t hpfar_el2 { 0 };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timer related registers
|
||||||
|
*/
|
||||||
|
struct Timer {
|
||||||
|
Genode::uint64_t offset { 0 };
|
||||||
|
Genode::uint64_t compare { 0 };
|
||||||
|
Genode::uint32_t control { 0 };
|
||||||
|
Genode::uint32_t kcontrol { 0 };
|
||||||
|
bool irq { false };
|
||||||
|
} timer {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interrupt related values
|
||||||
|
*/
|
||||||
|
struct Pic
|
||||||
|
{
|
||||||
|
unsigned last_irq { 1023 };
|
||||||
|
unsigned virtual_irq { 1023 };
|
||||||
|
} irqs {};
|
||||||
|
|
||||||
|
/**************************
|
||||||
|
** Platform information **
|
||||||
|
**************************/
|
||||||
|
|
||||||
|
Genode::uint64_t id_aa64isar0_el1 { 0 };
|
||||||
|
Genode::uint64_t id_aa64isar1_el1 { 0 };
|
||||||
|
Genode::uint64_t id_aa64mmfr0_el1 { 0 };
|
||||||
|
Genode::uint64_t id_aa64mmfr1_el1 { 0 };
|
||||||
|
Genode::uint64_t id_aa64mmfr2_el1 { 0 };
|
||||||
|
Genode::uint64_t id_aa64pfr0_el1 { 0 };
|
||||||
|
Genode::uint64_t id_aa64pfr1_el1 { 0 };
|
||||||
|
Genode::uint64_t id_aa64zfr0_el1 { 0 };
|
||||||
|
|
||||||
|
Genode::uint32_t ccsidr_inst_el1[7] { 0 };
|
||||||
|
Genode::uint32_t ccsidr_data_el1[7] { 0 };
|
||||||
|
Genode::uint64_t clidr_el1 { 0 };
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _INCLUDE__SPEC__ARM_64__CPU__VM_STATE_VIRTUALIZATION_H_ */
|
|
@ -17,6 +17,7 @@ SRC_CC += lib/base/heap.cc
|
||||||
SRC_CC += lib/base/registry.cc
|
SRC_CC += lib/base/registry.cc
|
||||||
SRC_CC += lib/base/log.cc
|
SRC_CC += lib/base/log.cc
|
||||||
SRC_CC += lib/base/output.cc
|
SRC_CC += lib/base/output.cc
|
||||||
|
SRC_CC += lib/base/raw_output.cc
|
||||||
SRC_CC += lib/base/slab.cc
|
SRC_CC += lib/base/slab.cc
|
||||||
SRC_CC += lib/base/sleep.cc
|
SRC_CC += lib/base/sleep.cc
|
||||||
SRC_CC += lib/base/sliced_heap.cc
|
SRC_CC += lib/base/sliced_heap.cc
|
||||||
|
|
|
@ -6,16 +6,16 @@
|
||||||
|
|
||||||
# add include paths
|
# add include paths
|
||||||
INC_DIR += $(REP_DIR)/src/core/spec/arndale
|
INC_DIR += $(REP_DIR)/src/core/spec/arndale
|
||||||
INC_DIR += $(REP_DIR)/src/core/spec/arm_v7/virtualization
|
INC_DIR += $(REP_DIR)/src/core/spec/arm/virtualization
|
||||||
|
|
||||||
# add C++ sources
|
# add C++ sources
|
||||||
SRC_CC += kernel/vm_thread_on.cc
|
SRC_CC += kernel/vm_thread_on.cc
|
||||||
SRC_CC += spec/arm/gicv2.cc
|
SRC_CC += spec/arm/gicv2.cc
|
||||||
SRC_CC += spec/arm_v7/virtualization/kernel/vm.cc
|
SRC_CC += spec/arm_v7/virtualization/kernel/vm.cc
|
||||||
SRC_CC += spec/arm_v7/virtualization/platform_services.cc
|
SRC_CC += spec/arm/virtualization/platform_services.cc
|
||||||
SRC_CC += spec/arm_v7/virtualization/vm_session_component.cc
|
SRC_CC += spec/arm/virtualization/vm_session_component.cc
|
||||||
SRC_CC += spec/arm_v7/vm_session_component.cc
|
|
||||||
SRC_CC += vm_session_common.cc
|
SRC_CC += vm_session_common.cc
|
||||||
|
SRC_CC += vm_session_component.cc
|
||||||
|
|
||||||
# add assembly sources
|
# add assembly sources
|
||||||
SRC_S += spec/arm_v7/virtualization/exception_vector.s
|
SRC_S += spec/arm_v7/virtualization/exception_vector.s
|
||||||
|
|
|
@ -5,7 +5,8 @@ SRC_CC += kernel/vm_thread_on.cc
|
||||||
SRC_CC += spec/arm_v7/trustzone/kernel/vm.cc
|
SRC_CC += spec/arm_v7/trustzone/kernel/vm.cc
|
||||||
SRC_CC += spec/arm_v7/trustzone/platform_services.cc
|
SRC_CC += spec/arm_v7/trustzone/platform_services.cc
|
||||||
SRC_CC += spec/arm_v7/trustzone/vm_session_component.cc
|
SRC_CC += spec/arm_v7/trustzone/vm_session_component.cc
|
||||||
SRC_CC += spec/arm_v7/vm_session_component.cc
|
SRC_CC += vm_session_common.cc
|
||||||
|
SRC_CC += vm_session_component.cc
|
||||||
|
|
||||||
SRC_S += spec/arm_v7/trustzone/exception_vector.s
|
SRC_S += spec/arm_v7/trustzone/exception_vector.s
|
||||||
|
|
||||||
|
|
|
@ -6,17 +6,18 @@
|
||||||
|
|
||||||
# add include paths
|
# add include paths
|
||||||
INC_DIR += $(REP_DIR)/src/core/spec/imx7d_sabre
|
INC_DIR += $(REP_DIR)/src/core/spec/imx7d_sabre
|
||||||
INC_DIR += $(REP_DIR)/src/core/spec/arm_v7/virtualization
|
INC_DIR += $(REP_DIR)/src/core/spec/arm/virtualization
|
||||||
|
|
||||||
# add C++ sources
|
# add C++ sources
|
||||||
SRC_CC += kernel/vm_thread_on.cc
|
SRC_CC += kernel/vm_thread_on.cc
|
||||||
SRC_CC += spec/arm/generic_timer.cc
|
SRC_CC += spec/arm/generic_timer.cc
|
||||||
SRC_CC += spec/arm/gicv2.cc
|
SRC_CC += spec/arm/gicv2.cc
|
||||||
SRC_CC += spec/arm_v7/virtualization/kernel/vm.cc
|
SRC_CC += spec/arm_v7/virtualization/kernel/vm.cc
|
||||||
SRC_CC += spec/arm_v7/virtualization/platform_services.cc
|
SRC_CC += spec/arm/virtualization/gicv2.cc
|
||||||
SRC_CC += spec/arm_v7/virtualization/vm_session_component.cc
|
SRC_CC += spec/arm/virtualization/platform_services.cc
|
||||||
SRC_CC += spec/arm_v7/vm_session_component.cc
|
SRC_CC += spec/arm/virtualization/vm_session_component.cc
|
||||||
SRC_CC += vm_session_common.cc
|
SRC_CC += vm_session_common.cc
|
||||||
|
SRC_CC += vm_session_component.cc
|
||||||
|
|
||||||
# add assembly sources
|
# add assembly sources
|
||||||
SRC_S += spec/arm_v7/virtualization/exception_vector.s
|
SRC_S += spec/arm_v7/virtualization/exception_vector.s
|
||||||
|
|
|
@ -17,7 +17,8 @@ SRC_CC += spec/arm/imx_tzic.cc
|
||||||
SRC_CC += spec/arm_v7/trustzone/kernel/vm.cc
|
SRC_CC += spec/arm_v7/trustzone/kernel/vm.cc
|
||||||
SRC_CC += spec/arm_v7/trustzone/platform_services.cc
|
SRC_CC += spec/arm_v7/trustzone/platform_services.cc
|
||||||
SRC_CC += spec/arm_v7/trustzone/vm_session_component.cc
|
SRC_CC += spec/arm_v7/trustzone/vm_session_component.cc
|
||||||
SRC_CC += spec/arm_v7/vm_session_component.cc
|
SRC_CC += vm_session_common.cc
|
||||||
|
SRC_CC += vm_session_component.cc
|
||||||
|
|
||||||
# add assembly sources
|
# add assembly sources
|
||||||
SRC_S += spec/arm_v7/trustzone/exception_vector.s
|
SRC_S += spec/arm_v7/trustzone/exception_vector.s
|
||||||
|
|
|
@ -7,6 +7,8 @@ SRC_CC += lib/base/arm_64/kernel/interface.cc
|
||||||
SRC_CC += spec/64bit/memory_map.cc
|
SRC_CC += spec/64bit/memory_map.cc
|
||||||
SRC_S += bootstrap/spec/arm_64/crt0.s
|
SRC_S += bootstrap/spec/arm_64/crt0.s
|
||||||
|
|
||||||
|
NR_OF_CPUS = 4
|
||||||
|
|
||||||
vpath spec/64bit/memory_map.cc $(BASE_DIR)/../base-hw/src/lib/hw
|
vpath spec/64bit/memory_map.cc $(BASE_DIR)/../base-hw/src/lib/hw
|
||||||
|
|
||||||
include $(BASE_DIR)/../base-hw/lib/mk/bootstrap-hw.inc
|
include $(BASE_DIR)/../base-hw/lib/mk/bootstrap-hw.inc
|
||||||
|
|
|
@ -8,4 +8,6 @@ SRC_S += bootstrap/spec/arm_64/crt0.s
|
||||||
|
|
||||||
vpath spec/64bit/memory_map.cc $(BASE_DIR)/../base-hw/src/lib/hw
|
vpath spec/64bit/memory_map.cc $(BASE_DIR)/../base-hw/src/lib/hw
|
||||||
|
|
||||||
|
NR_OF_CPUS = 4
|
||||||
|
|
||||||
include $(BASE_DIR)/../base-hw/lib/mk/bootstrap-hw.inc
|
include $(BASE_DIR)/../base-hw/lib/mk/bootstrap-hw.inc
|
||||||
|
|
|
@ -1,24 +1,32 @@
|
||||||
INC_DIR += $(REP_DIR)/src/core/spec/imx8q_evk
|
INC_DIR += $(REP_DIR)/src/core/spec/imx8q_evk
|
||||||
INC_DIR += $(REP_DIR)/src/core/spec/arm_v8
|
INC_DIR += $(REP_DIR)/src/core/spec/arm_v8
|
||||||
|
INC_DIR += $(REP_DIR)/src/core/spec/arm/virtualization
|
||||||
|
|
||||||
# add C++ sources
|
# add C++ sources
|
||||||
SRC_CC += kernel/cpu_up.cc
|
SRC_CC += kernel/cpu_mp.cc
|
||||||
SRC_CC += kernel/lock.cc
|
SRC_CC += kernel/vm_thread_on.cc
|
||||||
SRC_CC += kernel/vm_thread_off.cc
|
|
||||||
SRC_CC += platform_services.cc
|
|
||||||
SRC_CC += spec/64bit/memory_map.cc
|
SRC_CC += spec/64bit/memory_map.cc
|
||||||
SRC_CC += spec/arm/generic_timer.cc
|
SRC_CC += spec/arm/generic_timer.cc
|
||||||
SRC_CC += spec/arm/gicv3.cc
|
SRC_CC += spec/arm/gicv3.cc
|
||||||
|
SRC_CC += spec/arm/kernel/lock.cc
|
||||||
SRC_CC += spec/arm/platform_support.cc
|
SRC_CC += spec/arm/platform_support.cc
|
||||||
SRC_CC += spec/arm_v8/cpu.cc
|
SRC_CC += spec/arm_v8/cpu.cc
|
||||||
SRC_CC += spec/arm_v8/kernel/cpu.cc
|
SRC_CC += spec/arm_v8/kernel/cpu.cc
|
||||||
SRC_CC += spec/arm_v8/kernel/thread.cc
|
SRC_CC += spec/arm_v8/kernel/thread.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
|
#add assembly sources
|
||||||
SRC_S += spec/arm_v8/exception_vector.s
|
SRC_S += spec/arm_v8/exception_vector.s
|
||||||
SRC_S += spec/arm_v8/crt0.s
|
SRC_S += spec/arm_v8/crt0.s
|
||||||
|
SRC_S += spec/arm_v8/virtualization/exception_vector.s
|
||||||
|
|
||||||
vpath spec/64bit/memory_map.cc $(BASE_DIR)/../base-hw/src/lib/hw
|
vpath spec/64bit/memory_map.cc $(BASE_DIR)/../base-hw/src/lib/hw
|
||||||
|
|
||||||
|
NR_OF_CPUS = 4
|
||||||
|
|
||||||
# include less specific configuration
|
# include less specific configuration
|
||||||
include $(REP_DIR)/lib/mk/core-hw.inc
|
include $(REP_DIR)/lib/mk/core-hw.inc
|
||||||
|
|
|
@ -2,17 +2,17 @@ INC_DIR += $(REP_DIR)/src/core/spec/rpi3
|
||||||
INC_DIR += $(REP_DIR)/src/core/spec/arm_v8
|
INC_DIR += $(REP_DIR)/src/core/spec/arm_v8
|
||||||
|
|
||||||
# add C++ sources
|
# add C++ sources
|
||||||
SRC_CC += platform_services.cc
|
SRC_CC += kernel/cpu_mp.cc
|
||||||
SRC_CC += kernel/vm_thread_off.cc
|
SRC_CC += kernel/vm_thread_off.cc
|
||||||
SRC_CC += kernel/cpu_up.cc
|
SRC_CC += platform_services.cc
|
||||||
SRC_CC += kernel/lock.cc
|
SRC_CC += spec/64bit/memory_map.cc
|
||||||
SRC_CC += spec/arm_v8/cpu.cc
|
|
||||||
SRC_CC += spec/arm_v8/kernel/thread.cc
|
|
||||||
SRC_CC += spec/arm_v8/kernel/cpu.cc
|
|
||||||
SRC_CC += spec/arm/platform_support.cc
|
|
||||||
SRC_CC += spec/arm/bcm2837_pic.cc
|
SRC_CC += spec/arm/bcm2837_pic.cc
|
||||||
SRC_CC += spec/arm/generic_timer.cc
|
SRC_CC += spec/arm/generic_timer.cc
|
||||||
SRC_CC += spec/64bit/memory_map.cc
|
SRC_CC += spec/arm/kernel/lock.cc
|
||||||
|
SRC_CC += spec/arm/platform_support.cc
|
||||||
|
SRC_CC += spec/arm_v8/cpu.cc
|
||||||
|
SRC_CC += spec/arm_v8/kernel/cpu.cc
|
||||||
|
SRC_CC += spec/arm_v8/kernel/thread.cc
|
||||||
|
|
||||||
#add assembly sources
|
#add assembly sources
|
||||||
SRC_S += spec/arm_v8/exception_vector.s
|
SRC_S += spec/arm_v8/exception_vector.s
|
||||||
|
@ -20,5 +20,7 @@ SRC_S += spec/arm_v8/crt0.s
|
||||||
|
|
||||||
vpath spec/64bit/memory_map.cc $(BASE_DIR)/../base-hw/src/lib/hw
|
vpath spec/64bit/memory_map.cc $(BASE_DIR)/../base-hw/src/lib/hw
|
||||||
|
|
||||||
|
NR_OF_CPUS = 4
|
||||||
|
|
||||||
# include less specific configuration
|
# include less specific configuration
|
||||||
include $(REP_DIR)/lib/mk/core-hw.inc
|
include $(REP_DIR)/lib/mk/core-hw.inc
|
||||||
|
|
|
@ -35,7 +35,10 @@ SRC_CC += spec/x86_64/muen/platform_services.cc
|
||||||
SRC_CC += spec/x86_64/muen/platform_support.cc
|
SRC_CC += spec/x86_64/muen/platform_support.cc
|
||||||
SRC_CC += spec/x86_64/muen/sinfo_instance.cc
|
SRC_CC += spec/x86_64/muen/sinfo_instance.cc
|
||||||
SRC_CC += spec/x86_64/muen/timer.cc
|
SRC_CC += spec/x86_64/muen/timer.cc
|
||||||
|
SRC_CC += spec/x86_64/muen/vm_session_component.cc
|
||||||
SRC_CC += spec/x86_64/platform_support_common.cc
|
SRC_CC += spec/x86_64/platform_support_common.cc
|
||||||
|
SRC_CC += vm_session_common.cc
|
||||||
|
SRC_CC += vm_session_component.cc
|
||||||
|
|
||||||
SRC_CC += spec/64bit/memory_map.cc
|
SRC_CC += spec/64bit/memory_map.cc
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-07-08 abc6d82ca4a240319850c788f29cde2655eab1d1
|
2019-11-25 6593319a4dec74af9dc15554139e4343ef4312a9
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-09-19 1c57558662fd8474e71ac732af797c3585322017
|
2019-11-25 c60d834ce54a46a946c36249784e734e06274d97
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-09-19 47d633f15a78dba4ce4a0ece9fd301ec59476d18
|
2019-11-25 e9232754efd81c14aa65d4852d276852f591f3e5
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-09-19 a922228b96330109da7ddb61450a385ef485a93b
|
2019-11-25 2ab0250606cee0da4f08ac08f7f33c743f32c88c
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-09-19 d4514d968b7e55b42247e0231ad95bd77e92d253
|
2019-11-25 7780e0570ac0277d678dee76a579a9d9f9a1a776
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-09-19 742a48fd23606d2b6763b2f4f2ae4a199e3d6e56
|
2019-11-25 2dee497b7892f706236fdbfabae53bbd4e62463b
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-09-19 16b8071d8d3eee712181720ddf018c26e72f0f56
|
2019-11-25 efd164d66086a998484d7413c5416e3aa128e560
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-09-19 b1342fe0f4a662c502b296b11d2524d64d2a482e
|
2019-11-25 25f54b8744778f0860ac2a93c11ee6b1cd16d0c9
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-09-19 f5acd9b2761cb465a885ecff6ddb436bacff0788
|
2019-11-25 ceeaef3ad58fc5b88cf4686aa42f50fd254063e3
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-09-19 b078e13e4c53a1b0db0bd0336d64b3abf50e88e3
|
2019-11-25 aee36abdef456d2d1c6bba023f16cbca08eceabe
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-09-19 cdaaf832a7be3789c06a88888b11fafe6044b6ac
|
2019-11-25 ede7ce464c3f4b8486fd93413088a1b83fbf796a
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-09-19 2f375cd8feabedf1fcee6228faef30a8165e9f5b
|
2019-11-25 2bea4132b9ab877e802cfb81ad3c62bda0c2bc50
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-09-19 e66163f4025a92d475058a1ab1aeb911dd0c7540
|
2019-11-25 807893480c51457cad7e00e1275eff9749c91c68
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-09-19 fdbdc1b821fdf215203eae20dd1d5482f60f2685
|
2019-11-25 6a3f12cd6429f5d5bcf617cdd3ea9d345e8614ad
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-09-19 f2def44f31f4491e5ad1e13e3d980608e647fb91
|
2019-11-25 a318db7d985930e3f58ce3bccce290bc13aaedab
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-09-19 30958dd0b796aed5ea5a80d43fc660fa230eed34
|
2019-11-25 75f1b89ea50fdfd0a69c33dee4ba1e120d49fad5
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
/* base-internal includes */
|
/* base-internal includes */
|
||||||
#include <base/internal/globals.h>
|
#include <base/internal/globals.h>
|
||||||
#include <base/internal/output.h>
|
#include <base/internal/output.h>
|
||||||
|
#include <base/internal/raw_write_string.h>
|
||||||
#include <base/internal/unmanaged_singleton.h>
|
#include <base/internal/unmanaged_singleton.h>
|
||||||
|
|
||||||
#include <board.h>
|
#include <board.h>
|
||||||
|
@ -57,3 +58,5 @@ struct Buffer
|
||||||
Genode::Log &Genode::Log::log() {
|
Genode::Log &Genode::Log::log() {
|
||||||
return unmanaged_singleton<Buffer>()->log; }
|
return unmanaged_singleton<Buffer>()->log; }
|
||||||
|
|
||||||
|
|
||||||
|
void Genode::raw_write_string(char const *str) { log(str); }
|
||||||
|
|
|
@ -47,7 +47,6 @@ class Bootstrap::Platform
|
||||||
Mmio_space const core_mmio;
|
Mmio_space const core_mmio;
|
||||||
unsigned cpus { NR_OF_CPUS };
|
unsigned cpus { NR_OF_CPUS };
|
||||||
::Board::Boot_info info { };
|
::Board::Boot_info info { };
|
||||||
::Board::Pic pic { };
|
|
||||||
|
|
||||||
Board();
|
Board();
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
unsigned Bootstrap::Platform::enable_mmu()
|
unsigned Bootstrap::Platform::enable_mmu()
|
||||||
{
|
{
|
||||||
|
::Board::Pic pic { };
|
||||||
::Board::Cpu::Sctlr::init();
|
::Board::Cpu::Sctlr::init();
|
||||||
::Board::Cpu::enable_mmu_and_caches((addr_t)core_pd->table_base);
|
::Board::Cpu::enable_mmu_and_caches((addr_t)core_pd->table_base);
|
||||||
|
|
||||||
|
|
|
@ -118,7 +118,7 @@ unsigned Bootstrap::Platform::enable_mmu()
|
||||||
Actlr::disable_smp();
|
Actlr::disable_smp();
|
||||||
|
|
||||||
/* locally initialize interrupt controller */
|
/* locally initialize interrupt controller */
|
||||||
board.pic.init_cpu_local();
|
::Board::Pic pic { };
|
||||||
|
|
||||||
Cpu::invalidate_data_cache();
|
Cpu::invalidate_data_cache();
|
||||||
data_cache_invalidated.inc();
|
data_cache_invalidated.inc();
|
||||||
|
|
|
@ -13,8 +13,41 @@
|
||||||
|
|
||||||
#include <board.h>
|
#include <board.h>
|
||||||
|
|
||||||
void Board::Pic::init_cpu_local()
|
Hw::Gicv2::Gicv2()
|
||||||
|
: _distr(Board::Cpu_mmio::IRQ_CONTROLLER_DISTR_BASE),
|
||||||
|
_cpui (Board::Cpu_mmio::IRQ_CONTROLLER_CPU_BASE),
|
||||||
|
_last_iar(Cpu_interface::Iar::Irq_id::bits(spurious_id)),
|
||||||
|
_max_irq(_distr.max_irq())
|
||||||
{
|
{
|
||||||
|
static bool distributor_initialized = false;
|
||||||
|
|
||||||
|
if (!distributor_initialized) {
|
||||||
|
distributor_initialized = true;
|
||||||
|
|
||||||
|
/* disable device */
|
||||||
|
_distr.write<Distributor::Ctlr>(0);
|
||||||
|
|
||||||
|
/* configure every shared peripheral interrupt */
|
||||||
|
for (unsigned i = min_spi; i <= _max_irq; i++) {
|
||||||
|
if (Board::NON_SECURE) {
|
||||||
|
_distr.write<Distributor::Igroupr::Group_status>(1, i);
|
||||||
|
}
|
||||||
|
_distr.write<Distributor::Icfgr::Edge_triggered>(0, i);
|
||||||
|
_distr.write<Distributor::Ipriorityr::Priority>(0, i);
|
||||||
|
_distr.write<Distributor::Icenabler::Clear_enable>(1, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* enable device */
|
||||||
|
Distributor::Ctlr::access_t v = 0;
|
||||||
|
if (Board::NON_SECURE) {
|
||||||
|
Distributor::Ctlr::Enable_grp0::set(v, 1);
|
||||||
|
Distributor::Ctlr::Enable_grp1::set(v, 1);
|
||||||
|
} else {
|
||||||
|
Distributor::Ctlr::Enable::set(v, 1);
|
||||||
|
}
|
||||||
|
_distr.write<Distributor::Ctlr>(v);
|
||||||
|
}
|
||||||
|
|
||||||
if (Board::NON_SECURE) {
|
if (Board::NON_SECURE) {
|
||||||
_cpui.write<Cpu_interface::Ctlr>(0);
|
_cpui.write<Cpu_interface::Ctlr>(0);
|
||||||
|
|
||||||
|
@ -40,34 +73,3 @@ void Board::Pic::init_cpu_local()
|
||||||
}
|
}
|
||||||
_cpui.write<Cpu_interface::Ctlr>(v);
|
_cpui.write<Cpu_interface::Ctlr>(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Hw::Gicv2::Gicv2()
|
|
||||||
: _distr(Board::Cpu_mmio::IRQ_CONTROLLER_DISTR_BASE),
|
|
||||||
_cpui (Board::Cpu_mmio::IRQ_CONTROLLER_CPU_BASE),
|
|
||||||
_last_iar(Cpu_interface::Iar::Irq_id::bits(spurious_id)),
|
|
||||||
_max_irq(_distr.max_irq())
|
|
||||||
{
|
|
||||||
/* disable device */
|
|
||||||
_distr.write<Distributor::Ctlr>(0);
|
|
||||||
|
|
||||||
/* configure every shared peripheral interrupt */
|
|
||||||
for (unsigned i = min_spi; i <= _max_irq; i++) {
|
|
||||||
if (Board::NON_SECURE) {
|
|
||||||
_distr.write<Distributor::Igroupr::Group_status>(1, i);
|
|
||||||
}
|
|
||||||
_distr.write<Distributor::Icfgr::Edge_triggered>(0, i);
|
|
||||||
_distr.write<Distributor::Ipriorityr::Priority>(0, i);
|
|
||||||
_distr.write<Distributor::Icenabler::Clear_enable>(1, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* enable device */
|
|
||||||
Distributor::Ctlr::access_t v = 0;
|
|
||||||
if (Board::NON_SECURE) {
|
|
||||||
Distributor::Ctlr::Enable_grp0::set(v, 1);
|
|
||||||
Distributor::Ctlr::Enable_grp1::set(v, 1);
|
|
||||||
} else {
|
|
||||||
Distributor::Ctlr::Enable::set(v, 1);
|
|
||||||
}
|
|
||||||
_distr.write<Distributor::Ctlr>(v);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
/*
|
|
||||||
* \brief Interrupt controller definitions for ARM
|
|
||||||
* \author Stefan Kalkowski
|
|
||||||
* \date 2017-02-22
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2017 Genode Labs GmbH
|
|
||||||
*
|
|
||||||
* This file is part of the Genode OS framework, which is distributed
|
|
||||||
* under the terms of the GNU Affero General Public License version 3.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _SRC__BOOTSTRAP__SPEC__ARM__GICV2_H_
|
|
||||||
#define _SRC__BOOTSTRAP__SPEC__ARM__GICV2_H_
|
|
||||||
|
|
||||||
#include <hw/spec/arm/gicv2.h>
|
|
||||||
|
|
||||||
namespace Board { struct Pic; }
|
|
||||||
|
|
||||||
struct Board::Pic : Hw::Gicv2
|
|
||||||
{
|
|
||||||
void init_cpu_local();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* _SRC__BOOTSTRAP__SPEC__ARM__GICV2_H_ */
|
|
|
@ -11,10 +11,12 @@
|
||||||
* under the terms of the GNU Affero General Public License version 3.
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <hw/spec/arm_64/memory_map.h>
|
||||||
#include <platform.h>
|
#include <platform.h>
|
||||||
|
|
||||||
using Board::Cpu;
|
using Board::Cpu;
|
||||||
|
|
||||||
|
extern "C" void * _crt0_enable_fpu;
|
||||||
|
|
||||||
static inline void prepare_non_secure_world()
|
static inline void prepare_non_secure_world()
|
||||||
{
|
{
|
||||||
|
@ -56,11 +58,54 @@ static inline void prepare_non_secure_world()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline void prepare_hypervisor()
|
static inline void prepare_hypervisor(Cpu::Ttbr::access_t const ttbr)
|
||||||
{
|
{
|
||||||
Cpu::Hcr::access_t scr = Cpu::Hcr::read();
|
using namespace Hw::Mm;
|
||||||
Cpu::Hcr::Rw::set(scr, 1); /* exec in aarch64 */
|
|
||||||
Cpu::Hcr::write(scr);
|
/* forbid trace access */
|
||||||
|
Cpu::Cptr_el2::access_t cptr = Cpu::Cptr_el2::read();
|
||||||
|
Cpu::Cptr_el2::Tta::set(cptr, 1);
|
||||||
|
Cpu::Cptr_el2::write(cptr);
|
||||||
|
|
||||||
|
/* allow physical counter/timer access without trapping */
|
||||||
|
Cpu::Cnthctl_el2::write(0b111);
|
||||||
|
|
||||||
|
/* forbid any 32bit access to coprocessor/sysregs */
|
||||||
|
Cpu::Hstr_el2::write(0xffff);
|
||||||
|
|
||||||
|
Cpu::Hcr_el2::access_t hcr = Cpu::Hcr_el2::read();
|
||||||
|
Cpu::Hcr_el2::Rw::set(hcr, 1); /* exec in aarch64 */
|
||||||
|
Cpu::Hcr_el2::write(hcr);
|
||||||
|
|
||||||
|
/* set hypervisor exception vector */
|
||||||
|
Cpu::Vbar_el2::write(el2_addr(hypervisor_exception_vector().base));
|
||||||
|
Genode::addr_t const stack_el2 = el2_addr(hypervisor_stack().base +
|
||||||
|
hypervisor_stack().size);
|
||||||
|
|
||||||
|
/* set hypervisor's translation table */
|
||||||
|
Cpu::Ttbr0_el2::write(ttbr);
|
||||||
|
|
||||||
|
Cpu::Tcr_el2::access_t tcr_el2 = 0;
|
||||||
|
Cpu::Tcr_el2::T0sz::set(tcr_el2, 25);
|
||||||
|
Cpu::Tcr_el2::Irgn0::set(tcr_el2, 1);
|
||||||
|
Cpu::Tcr_el2::Orgn0::set(tcr_el2, 1);
|
||||||
|
Cpu::Tcr_el2::Sh0::set(tcr_el2, 0b10);
|
||||||
|
|
||||||
|
/* prepare MMU usage by hypervisor code */
|
||||||
|
Cpu::Tcr_el2::write(tcr_el2);
|
||||||
|
|
||||||
|
/* set memory attributes in indirection register */
|
||||||
|
Cpu::Mair::access_t mair = 0;
|
||||||
|
Cpu::Mair::Attr0::set(mair, Cpu::Mair::NORMAL_MEMORY_UNCACHED);
|
||||||
|
Cpu::Mair::Attr1::set(mair, Cpu::Mair::DEVICE_MEMORY);
|
||||||
|
Cpu::Mair::Attr2::set(mair, Cpu::Mair::NORMAL_MEMORY_CACHED);
|
||||||
|
Cpu::Mair::Attr3::set(mair, Cpu::Mair::DEVICE_MEMORY);
|
||||||
|
Cpu::Mair_el2::write(mair);
|
||||||
|
|
||||||
|
Cpu::Vtcr_el2::access_t vtcr = 0;
|
||||||
|
Cpu::Vtcr_el2::T0sz::set(vtcr, 25);
|
||||||
|
Cpu::Vtcr_el2::Sl0::set(vtcr, 1); /* set to starting level 1 */
|
||||||
|
Cpu::Vtcr_el2::write(vtcr);
|
||||||
|
|
||||||
Cpu::Spsr::access_t pstate = 0;
|
Cpu::Spsr::access_t pstate = 0;
|
||||||
Cpu::Spsr::Sp::set(pstate, 1); /* select non-el0 stack pointer */
|
Cpu::Spsr::Sp::set(pstate, 1); /* select non-el0 stack pointer */
|
||||||
|
@ -71,27 +116,52 @@ static inline void prepare_hypervisor()
|
||||||
Cpu::Spsr::D::set(pstate, 1);
|
Cpu::Spsr::D::set(pstate, 1);
|
||||||
Cpu::Spsr_el2::write(pstate);
|
Cpu::Spsr_el2::write(pstate);
|
||||||
|
|
||||||
|
Cpu::Sctlr::access_t sctlr = Cpu::Sctlr_el2::read();
|
||||||
|
Cpu::Sctlr::M::set(sctlr, 1);
|
||||||
|
Cpu::Sctlr::A::set(sctlr, 0);
|
||||||
|
Cpu::Sctlr::C::set(sctlr, 1);
|
||||||
|
Cpu::Sctlr::Sa::set(sctlr, 0);
|
||||||
|
Cpu::Sctlr::I::set(sctlr, 1);
|
||||||
|
Cpu::Sctlr::Wxn::set(sctlr, 0);
|
||||||
|
Cpu::Sctlr_el2::write(sctlr);
|
||||||
|
|
||||||
asm volatile("mov x0, sp \n"
|
asm volatile("mov x0, sp \n"
|
||||||
"msr sp_el1, x0 \n"
|
"msr sp_el1, x0 \n"
|
||||||
"adr x0, 1f \n"
|
"adr x0, 1f \n"
|
||||||
"msr elr_el2, x0 \n"
|
"msr elr_el2, x0 \n"
|
||||||
|
"mov sp, %0 \n"
|
||||||
"eret \n"
|
"eret \n"
|
||||||
"1:");
|
"1:": : "r"(stack_el2): "x0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
unsigned Bootstrap::Platform::enable_mmu()
|
unsigned Bootstrap::Platform::enable_mmu()
|
||||||
{
|
{
|
||||||
|
static volatile bool primary_cpu = true;
|
||||||
|
bool primary = primary_cpu;
|
||||||
|
if (primary) primary_cpu = false;
|
||||||
|
|
||||||
|
Cpu::Ttbr::access_t ttbr =
|
||||||
|
Cpu::Ttbr::Baddr::masked((Genode::addr_t)core_pd->table_base);
|
||||||
|
|
||||||
while (Cpu::current_privilege_level() > Cpu::Current_el::EL1) {
|
while (Cpu::current_privilege_level() > Cpu::Current_el::EL1) {
|
||||||
if (Cpu::current_privilege_level() == Cpu::Current_el::EL3)
|
if (Cpu::current_privilege_level() == Cpu::Current_el::EL3) {
|
||||||
prepare_non_secure_world();
|
prepare_non_secure_world();
|
||||||
else
|
} else {
|
||||||
prepare_hypervisor();
|
::Board::Pic pic __attribute__((unused)) {};
|
||||||
|
prepare_hypervisor(ttbr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* primary cpu wakes up all others */
|
||||||
|
if (primary && NR_OF_CPUS > 1) Cpu::wake_up_all_cpus(&_crt0_enable_fpu);
|
||||||
|
|
||||||
/* enable performance counter for user-land */
|
/* enable performance counter for user-land */
|
||||||
Cpu::Pmuserenr_el0::write(0b1111);
|
Cpu::Pmuserenr_el0::write(0b1111);
|
||||||
|
|
||||||
|
/* enable user-level access of physical/virtual counter */
|
||||||
|
Cpu::Cntkctl_el1::write(0b11);
|
||||||
|
|
||||||
Cpu::Vbar_el1::write(Hw::Mm::supervisor_exception_vector().base);
|
Cpu::Vbar_el1::write(Hw::Mm::supervisor_exception_vector().base);
|
||||||
|
|
||||||
/* set memory attributes in indirection register */
|
/* set memory attributes in indirection register */
|
||||||
|
@ -100,9 +170,8 @@ unsigned Bootstrap::Platform::enable_mmu()
|
||||||
Cpu::Mair::Attr1::set(mair, Cpu::Mair::DEVICE_MEMORY);
|
Cpu::Mair::Attr1::set(mair, Cpu::Mair::DEVICE_MEMORY);
|
||||||
Cpu::Mair::Attr2::set(mair, Cpu::Mair::NORMAL_MEMORY_CACHED);
|
Cpu::Mair::Attr2::set(mair, Cpu::Mair::NORMAL_MEMORY_CACHED);
|
||||||
Cpu::Mair::Attr3::set(mair, Cpu::Mair::DEVICE_MEMORY);
|
Cpu::Mair::Attr3::set(mair, Cpu::Mair::DEVICE_MEMORY);
|
||||||
Cpu::Mair::write(mair);
|
Cpu::Mair_el1::write(mair);
|
||||||
|
|
||||||
Cpu::Ttbr::access_t ttbr = Cpu::Ttbr::Baddr::masked((Genode::addr_t)core_pd->table_base);
|
|
||||||
Cpu::Ttbr0_el1::write(ttbr);
|
Cpu::Ttbr0_el1::write(ttbr);
|
||||||
Cpu::Ttbr1_el1::write(ttbr);
|
Cpu::Ttbr1_el1::write(ttbr);
|
||||||
|
|
||||||
|
@ -119,13 +188,14 @@ unsigned Bootstrap::Platform::enable_mmu()
|
||||||
Cpu::Tcr_el1::As::set(tcr, 1);
|
Cpu::Tcr_el1::As::set(tcr, 1);
|
||||||
Cpu::Tcr_el1::write(tcr);
|
Cpu::Tcr_el1::write(tcr);
|
||||||
|
|
||||||
Cpu::Sctlr_el1::access_t sctlr = Cpu::Sctlr_el1::read();
|
Cpu::Sctlr::access_t sctlr = Cpu::Sctlr_el1::read();
|
||||||
Cpu::Sctlr_el1::C::set(sctlr, 1);
|
Cpu::Sctlr::C::set(sctlr, 1);
|
||||||
Cpu::Sctlr_el1::I::set(sctlr, 1);
|
Cpu::Sctlr::I::set(sctlr, 1);
|
||||||
Cpu::Sctlr_el1::A::set(sctlr, 0);
|
Cpu::Sctlr::A::set(sctlr, 0);
|
||||||
Cpu::Sctlr_el1::M::set(sctlr, 1);
|
Cpu::Sctlr::M::set(sctlr, 1);
|
||||||
Cpu::Sctlr_el1::Sa0::set(sctlr, 1);
|
Cpu::Sctlr::Sa0::set(sctlr, 1);
|
||||||
Cpu::Sctlr_el1::Sa::set(sctlr, 0);
|
Cpu::Sctlr::Sa::set(sctlr, 0);
|
||||||
|
Cpu::Sctlr::Uct::set(sctlr, 1);
|
||||||
Cpu::Sctlr_el1::write(sctlr);
|
Cpu::Sctlr_el1::write(sctlr);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -23,8 +23,19 @@
|
||||||
mrs x0, mpidr_el1
|
mrs x0, mpidr_el1
|
||||||
and x0, x0, #0b11111111
|
and x0, x0, #0b11111111
|
||||||
cbz x0, _crt0_fill_bss_zero
|
cbz x0, _crt0_fill_bss_zero
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hack for Qemu, which starts all cpus at once
|
||||||
|
*/
|
||||||
|
1:
|
||||||
|
ldr x1, =_crt0_qemu_start_secondary_cpus
|
||||||
|
ldr w1, [x1]
|
||||||
|
cbnz w1, _crt0_enable_fpu
|
||||||
wfe
|
wfe
|
||||||
b _start
|
b 1b
|
||||||
|
.global _crt0_qemu_start_secondary_cpus
|
||||||
|
_crt0_qemu_start_secondary_cpus:
|
||||||
|
.long 0
|
||||||
|
|
||||||
|
|
||||||
/***************************
|
/***************************
|
||||||
|
@ -32,12 +43,12 @@
|
||||||
***************************/
|
***************************/
|
||||||
|
|
||||||
_crt0_fill_bss_zero:
|
_crt0_fill_bss_zero:
|
||||||
ldr x0, =_bss_start
|
ldr x1, =_bss_start
|
||||||
ldr x1, =_bss_end
|
ldr x2, =_bss_end
|
||||||
1:
|
1:
|
||||||
cmp x1, x0
|
cmp x2, x1
|
||||||
b.eq _crt0_enable_fpu
|
b.eq _crt0_enable_fpu
|
||||||
str xzr, [x0], #8
|
str xzr, [x1], #8
|
||||||
b 1b
|
b 1b
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,20 +56,30 @@
|
||||||
** Enable FPU **
|
** Enable FPU **
|
||||||
****************/
|
****************/
|
||||||
|
|
||||||
|
.global _crt0_enable_fpu
|
||||||
_crt0_enable_fpu:
|
_crt0_enable_fpu:
|
||||||
mov x0, #0b11
|
mov x1, #0b11
|
||||||
lsl x0, x0, #20
|
lsl x1, x1, #20
|
||||||
msr cpacr_el1, x0
|
msr cpacr_el1, x1
|
||||||
|
|
||||||
|
|
||||||
/**********************
|
/**********************
|
||||||
** Initialize stack **
|
** Initialize stack **
|
||||||
**********************/
|
**********************/
|
||||||
|
|
||||||
ldr x0, =_crt0_start_stack
|
.set STACK_SIZE, 0x2000
|
||||||
mov sp, x0
|
|
||||||
|
ldr x1, =_crt0_start_stack
|
||||||
|
ldr x2, [x1]
|
||||||
|
mul x0, x0, x2
|
||||||
|
add x1, x1, x0
|
||||||
|
mov sp, x1
|
||||||
bl init
|
bl init
|
||||||
|
|
||||||
.p2align 4
|
.p2align 4
|
||||||
.space 0x4000
|
.rept NR_OF_CPUS
|
||||||
|
.space STACK_SIZE
|
||||||
|
.endr
|
||||||
_crt0_start_stack:
|
_crt0_start_stack:
|
||||||
|
.long STACK_SIZE
|
||||||
|
|
||||||
|
|
|
@ -17,11 +17,11 @@
|
||||||
#include <hw/spec/arm/arndale_board.h>
|
#include <hw/spec/arm/arndale_board.h>
|
||||||
#include <hw/spec/arm/lpae.h>
|
#include <hw/spec/arm/lpae.h>
|
||||||
#include <spec/arm/cpu.h>
|
#include <spec/arm/cpu.h>
|
||||||
#include <spec/arm/gicv2.h>
|
#include <hw/spec/arm/gicv2.h>
|
||||||
|
|
||||||
namespace Board {
|
namespace Board {
|
||||||
using namespace Hw::Arndale_board;
|
using namespace Hw::Arndale_board;
|
||||||
|
using Pic = Hw::Gicv2;
|
||||||
static constexpr bool NON_SECURE = true;
|
static constexpr bool NON_SECURE = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -155,7 +155,9 @@ unsigned Bootstrap::Platform::enable_mmu()
|
||||||
using namespace ::Board;
|
using namespace ::Board;
|
||||||
|
|
||||||
static volatile bool primary_cpu = true;
|
static volatile bool primary_cpu = true;
|
||||||
board.pic.init_cpu_local();
|
|
||||||
|
/* locally initialize interrupt controller */
|
||||||
|
::Board::Pic pic { };
|
||||||
|
|
||||||
prepare_nonsecure_world();
|
prepare_nonsecure_world();
|
||||||
prepare_hypervisor((addr_t)core_pd->table_base);
|
prepare_hypervisor((addr_t)core_pd->table_base);
|
||||||
|
|
|
@ -18,11 +18,11 @@
|
||||||
#include <spec/arm/cortex_a9_actlr.h>
|
#include <spec/arm/cortex_a9_actlr.h>
|
||||||
#include <spec/arm/cortex_a9_page_table.h>
|
#include <spec/arm/cortex_a9_page_table.h>
|
||||||
#include <spec/arm/cpu.h>
|
#include <spec/arm/cpu.h>
|
||||||
#include <spec/arm/gicv2.h>
|
#include <hw/spec/arm/gicv2.h>
|
||||||
|
|
||||||
namespace Board {
|
namespace Board {
|
||||||
using namespace Hw::Imx6q_sabrelite_board;
|
using namespace Hw::Imx6q_sabrelite_board;
|
||||||
|
using Pic = Hw::Gicv2;
|
||||||
struct L2_cache;
|
struct L2_cache;
|
||||||
|
|
||||||
static constexpr bool NON_SECURE = false;
|
static constexpr bool NON_SECURE = false;
|
||||||
|
|
|
@ -17,11 +17,11 @@
|
||||||
#include <hw/spec/arm/imx7d_sabre_board.h>
|
#include <hw/spec/arm/imx7d_sabre_board.h>
|
||||||
#include <hw/spec/arm/lpae.h>
|
#include <hw/spec/arm/lpae.h>
|
||||||
#include <spec/arm/cpu.h>
|
#include <spec/arm/cpu.h>
|
||||||
#include <spec/arm/gicv2.h>
|
#include <hw/spec/arm/gicv2.h>
|
||||||
|
|
||||||
namespace Board {
|
namespace Board {
|
||||||
using namespace Hw::Imx7d_sabre_board;
|
using namespace Hw::Imx7d_sabre_board;
|
||||||
|
using Pic = Hw::Gicv2;
|
||||||
static constexpr bool NON_SECURE = true;
|
static constexpr bool NON_SECURE = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -287,7 +287,9 @@ unsigned Bootstrap::Platform::enable_mmu()
|
||||||
{
|
{
|
||||||
static volatile bool primary_cpu = true;
|
static volatile bool primary_cpu = true;
|
||||||
static unsigned long timer_freq = Cpu::Cntfrq::read();
|
static unsigned long timer_freq = Cpu::Cntfrq::read();
|
||||||
board.pic.init_cpu_local();
|
|
||||||
|
/* locally initialize interrupt controller */
|
||||||
|
::Board::Pic pic { };
|
||||||
|
|
||||||
prepare_nonsecure_world(timer_freq);
|
prepare_nonsecure_world(timer_freq);
|
||||||
prepare_hypervisor((addr_t)core_pd->table_base);
|
prepare_hypervisor((addr_t)core_pd->table_base);
|
||||||
|
|
|
@ -21,7 +21,12 @@
|
||||||
|
|
||||||
namespace Board {
|
namespace Board {
|
||||||
using namespace Hw::Imx8q_evk_board;
|
using namespace Hw::Imx8q_evk_board;
|
||||||
using Cpu = Hw::Arm_64_cpu;
|
|
||||||
|
struct Cpu : Hw::Arm_64_cpu
|
||||||
|
{
|
||||||
|
static void wake_up_all_cpus(void*);
|
||||||
|
};
|
||||||
|
|
||||||
using Hw::Pic;
|
using Hw::Pic;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -24,4 +24,269 @@ Bootstrap::Platform::Board::Board()
|
||||||
Memory_region { ::Board::Cpu_mmio::IRQ_CONTROLLER_DISTR_BASE,
|
Memory_region { ::Board::Cpu_mmio::IRQ_CONTROLLER_DISTR_BASE,
|
||||||
::Board::Cpu_mmio::IRQ_CONTROLLER_DISTR_SIZE },
|
::Board::Cpu_mmio::IRQ_CONTROLLER_DISTR_SIZE },
|
||||||
Memory_region { ::Board::Cpu_mmio::IRQ_CONTROLLER_REDIST_BASE,
|
Memory_region { ::Board::Cpu_mmio::IRQ_CONTROLLER_REDIST_BASE,
|
||||||
::Board::Cpu_mmio::IRQ_CONTROLLER_REDIST_SIZE }) {}
|
::Board::Cpu_mmio::IRQ_CONTROLLER_REDIST_SIZE })
|
||||||
|
{
|
||||||
|
::Board::Pic pic {};
|
||||||
|
|
||||||
|
static volatile unsigned long initial_values[][2] {
|
||||||
|
// GPC values
|
||||||
|
{ 0x303A0004, 0x5050424 },
|
||||||
|
{ 0x303A0030, 0xEB22DE22 },
|
||||||
|
{ 0x303A0034, 0xFFFFF1C7 },
|
||||||
|
{ 0x303A0038, 0x7BFFBC00 },
|
||||||
|
{ 0x303A003C, 0xFA3BF12A },
|
||||||
|
{ 0x303A004C, 0xFFFFDFFF },
|
||||||
|
{ 0x303A01B4, 0x3980 },
|
||||||
|
{ 0x303A01CC, 0xFFFFBFFF },
|
||||||
|
{ 0x303A01D4, 0xFFFF7FFF },
|
||||||
|
{ 0x303A01DC, 0xFFFF7FFF },
|
||||||
|
{ 0x303A01FC, 0x107FF9F },
|
||||||
|
{ 0x303A080C, 0x1 },
|
||||||
|
{ 0x303A0840, 0x1 },
|
||||||
|
{ 0x303A084C, 0x1 },
|
||||||
|
{ 0x303A0880, 0x1 },
|
||||||
|
{ 0x303A088C, 0x1 },
|
||||||
|
{ 0x303A08C0, 0x1 },
|
||||||
|
{ 0x303A08CC, 0x1 },
|
||||||
|
{ 0x303A0C8C, 0x1 },
|
||||||
|
{ 0x303A0DCC, 0x1 },
|
||||||
|
{ 0x303A0E0C, 0x1 },
|
||||||
|
{ 0x303A0ECC, 0x1 },
|
||||||
|
{ 0x303A0F00, 0x1 },
|
||||||
|
{ 0x303A0F0C, 0x1 },
|
||||||
|
|
||||||
|
// CCM values
|
||||||
|
{ 0x303840B0, 0x2 },
|
||||||
|
{ 0x303840B4, 0x2 },
|
||||||
|
{ 0x303840B8, 0x2 },
|
||||||
|
{ 0x303840BC, 0x2 },
|
||||||
|
{ 0x303840C0, 0x2 },
|
||||||
|
{ 0x303840C4, 0x2 },
|
||||||
|
{ 0x303840C8, 0x2 },
|
||||||
|
{ 0x303840CC, 0x2 },
|
||||||
|
{ 0x303840D0, 0x2 },
|
||||||
|
{ 0x303840D4, 0x2 },
|
||||||
|
{ 0x303840D8, 0x2 },
|
||||||
|
{ 0x303840DC, 0x2 },
|
||||||
|
{ 0x303840E0, 0x2 },
|
||||||
|
{ 0x303840E4, 0x2 },
|
||||||
|
{ 0x303840E8, 0x2 },
|
||||||
|
{ 0x303840EC, 0x2 },
|
||||||
|
{ 0x303840F0, 0x2 },
|
||||||
|
{ 0x303840F4, 0x2 },
|
||||||
|
{ 0x303840F8, 0x2 },
|
||||||
|
{ 0x303840FC, 0x2 },
|
||||||
|
{ 0x30384250, 0x3 },
|
||||||
|
{ 0x30384254, 0x3 },
|
||||||
|
{ 0x30384258, 0x3 },
|
||||||
|
{ 0x3038425C, 0x3 },
|
||||||
|
{ 0x303843A0, 0x3 },
|
||||||
|
{ 0x303843A4, 0x3 },
|
||||||
|
{ 0x303843A8, 0x3 },
|
||||||
|
{ 0x303843AC, 0x3 },
|
||||||
|
{ 0x303844D0, 0x3 },
|
||||||
|
{ 0x303844D4, 0x3 },
|
||||||
|
{ 0x303844D8, 0x3 },
|
||||||
|
{ 0x303844DC, 0x3 },
|
||||||
|
{ 0x303844F0, 0x3 },
|
||||||
|
{ 0x303844F4, 0x3 },
|
||||||
|
{ 0x303844F8, 0x3 },
|
||||||
|
{ 0x303844FC, 0x3 },
|
||||||
|
{ 0x30384560, 0x0 },
|
||||||
|
{ 0x30384564, 0x0 },
|
||||||
|
{ 0x30384568, 0x0 },
|
||||||
|
{ 0x3038456C, 0x0 },
|
||||||
|
{ 0x303845D0, 0x3 },
|
||||||
|
{ 0x303845D4, 0x3 },
|
||||||
|
{ 0x303845D8, 0x3 },
|
||||||
|
{ 0x303845DC, 0x3 },
|
||||||
|
{ 0x30388010, 0x0 },
|
||||||
|
{ 0x30388014, 0x0 },
|
||||||
|
{ 0x30388018, 0x0 },
|
||||||
|
{ 0x3038801C, 0x0 },
|
||||||
|
{ 0x30388020, 0x0 },
|
||||||
|
{ 0x30388024, 0x0 },
|
||||||
|
{ 0x30388028, 0x0 },
|
||||||
|
{ 0x3038802C, 0x0 },
|
||||||
|
{ 0x30388030, 0x11000400 },
|
||||||
|
{ 0x30388034, 0x11000400 },
|
||||||
|
{ 0x30388038, 0x11000400 },
|
||||||
|
{ 0x3038803C, 0x11000400 },
|
||||||
|
{ 0x30388080, 0x11000000 },
|
||||||
|
{ 0x30388084, 0x11000000 },
|
||||||
|
{ 0x30388088, 0x11000000 },
|
||||||
|
{ 0x3038808C, 0x11000000 },
|
||||||
|
{ 0x30388090, 0x0 },
|
||||||
|
{ 0x30388094, 0x0 },
|
||||||
|
{ 0x30388098, 0x0 },
|
||||||
|
{ 0x3038809C, 0x0 },
|
||||||
|
{ 0x303880B0, 0x1100 },
|
||||||
|
{ 0x303880B4, 0x1100 },
|
||||||
|
{ 0x303880B8, 0x1100 },
|
||||||
|
{ 0x303880BC, 0x1100 },
|
||||||
|
{ 0x30388110, 0x0 },
|
||||||
|
{ 0x30388114, 0x0 },
|
||||||
|
{ 0x30388118, 0x0 },
|
||||||
|
{ 0x3038811C, 0x0 },
|
||||||
|
{ 0x30388180, 0x1000000 },
|
||||||
|
{ 0x30388184, 0x1000000 },
|
||||||
|
{ 0x30388188, 0x1000000 },
|
||||||
|
{ 0x3038818C, 0x1000000 },
|
||||||
|
{ 0x303881A0, 0x10000000 },
|
||||||
|
{ 0x303881A4, 0x10000000 },
|
||||||
|
{ 0x303881A8, 0x10000000 },
|
||||||
|
{ 0x303881AC, 0x10000000 },
|
||||||
|
{ 0x303881B0, 0x1000100 },
|
||||||
|
{ 0x303881B4, 0x1000100 },
|
||||||
|
{ 0x303881B8, 0x1000100 },
|
||||||
|
{ 0x303881BC, 0x1000100 },
|
||||||
|
{ 0x30388200, 0x1000000 },
|
||||||
|
{ 0x30388204, 0x1000000 },
|
||||||
|
{ 0x30388208, 0x1000000 },
|
||||||
|
{ 0x3038820C, 0x1000000 },
|
||||||
|
{ 0x30388220, 0x10000000 },
|
||||||
|
{ 0x30388224, 0x10000000 },
|
||||||
|
{ 0x30388228, 0x10000000 },
|
||||||
|
{ 0x3038822C, 0x10000000 },
|
||||||
|
{ 0x30388230, 0x1000100 },
|
||||||
|
{ 0x30388234, 0x1000100 },
|
||||||
|
{ 0x30388238, 0x1000100 },
|
||||||
|
{ 0x3038823C, 0x1000100 },
|
||||||
|
|
||||||
|
// CCMA values
|
||||||
|
{ 0x30360000, 0x88080 },
|
||||||
|
{ 0x30360004, 0x292A2FA6 },
|
||||||
|
{ 0x30360004, 0x292A2FA6 },
|
||||||
|
{ 0x30360008, 0x88080 },
|
||||||
|
{ 0x30360008, 0x88080 },
|
||||||
|
{ 0x3036000C, 0x10385BA3 },
|
||||||
|
{ 0x3036000C, 0x10385BA3 },
|
||||||
|
{ 0x30360010, 0x98080 },
|
||||||
|
{ 0x30360010, 0x98080 },
|
||||||
|
{ 0x30360014, 0x3FFFFF1A },
|
||||||
|
{ 0x30360014, 0x3FFFFF1A },
|
||||||
|
{ 0x30360018, 0x88081 },
|
||||||
|
{ 0x30360054, 0x2B9 },
|
||||||
|
|
||||||
|
// 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 },
|
||||||
|
{ 0x30330220, 0x10 },
|
||||||
|
{ 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 },
|
||||||
|
{ 0x3033033C, 0x9F },
|
||||||
|
{ 0x30330340, 0xDF },
|
||||||
|
{ 0x30330344, 0xDF },
|
||||||
|
{ 0x30330348, 0xDF },
|
||||||
|
{ 0x3033034C, 0xDF },
|
||||||
|
{ 0x30330350, 0xDF },
|
||||||
|
{ 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 },
|
||||||
|
{ 0x30330464, 0x49 },
|
||||||
|
{ 0x30330468, 0x49 },
|
||||||
|
{ 0x3033046C, 0x16 },
|
||||||
|
{ 0x30330484, 0x67 },
|
||||||
|
{ 0x30330488, 0x67 },
|
||||||
|
{ 0x3033048C, 0x67 },
|
||||||
|
{ 0x30330490, 0x67 },
|
||||||
|
{ 0x30330494, 0x76 },
|
||||||
|
{ 0x30330498, 0x76 },
|
||||||
|
{ 0x303304AC, 0x49 },
|
||||||
|
{ 0x303304B0, 0x49 },
|
||||||
|
{ 0x303304C8, 0x1 },
|
||||||
|
{ 0x303304CC, 0x4 },
|
||||||
|
{ 0x30330500, 0x1 },
|
||||||
|
{ 0x30330504, 0x2 },
|
||||||
|
{ 0x30340038, 0x49409600 },
|
||||||
|
{ 0x30340040, 0x49409200 }
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned num_values = sizeof(initial_values) / (2*sizeof(unsigned long));
|
||||||
|
for (unsigned i = 0; i < num_values; i++)
|
||||||
|
*((volatile Genode::uint32_t*)initial_values[i][0]) = (Genode::uint32_t)initial_values[i][1];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -18,11 +18,11 @@
|
||||||
#include <spec/arm/cortex_a9_actlr.h>
|
#include <spec/arm/cortex_a9_actlr.h>
|
||||||
#include <spec/arm/cortex_a9_page_table.h>
|
#include <spec/arm/cortex_a9_page_table.h>
|
||||||
#include <spec/arm/cpu.h>
|
#include <spec/arm/cpu.h>
|
||||||
#include <spec/arm/gicv2.h>
|
#include <hw/spec/arm/gicv2.h>
|
||||||
|
|
||||||
namespace Board {
|
namespace Board {
|
||||||
using namespace Hw::Nit6_solox_board;
|
using namespace Hw::Nit6_solox_board;
|
||||||
|
using Pic = Hw::Gicv2;
|
||||||
struct L2_cache;
|
struct L2_cache;
|
||||||
|
|
||||||
static constexpr bool NON_SECURE = false;
|
static constexpr bool NON_SECURE = false;
|
||||||
|
|
|
@ -17,10 +17,11 @@
|
||||||
#include <hw/spec/arm/odroid_xu_board.h>
|
#include <hw/spec/arm/odroid_xu_board.h>
|
||||||
#include <hw/spec/arm/lpae.h>
|
#include <hw/spec/arm/lpae.h>
|
||||||
#include <spec/arm/cpu.h>
|
#include <spec/arm/cpu.h>
|
||||||
#include <spec/arm/gicv2.h>
|
#include <hw/spec/arm/gicv2.h>
|
||||||
|
|
||||||
namespace Board {
|
namespace Board {
|
||||||
using namespace Hw::Odroid_xu_board;
|
using namespace Hw::Odroid_xu_board;
|
||||||
|
using Pic = Hw::Gicv2;
|
||||||
static constexpr bool NON_SECURE = false;
|
static constexpr bool NON_SECURE = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,9 @@ Bootstrap::Platform::Board::Board()
|
||||||
|
|
||||||
unsigned Bootstrap::Platform::enable_mmu()
|
unsigned Bootstrap::Platform::enable_mmu()
|
||||||
{
|
{
|
||||||
board.pic.init_cpu_local();
|
/* locally initialize interrupt controller */
|
||||||
|
::Board::Pic pic { };
|
||||||
|
|
||||||
Cpu::Sctlr::init();
|
Cpu::Sctlr::init();
|
||||||
Cpu::Cpsr::init();
|
Cpu::Cpsr::init();
|
||||||
Cpu::invalidate_data_cache();
|
Cpu::invalidate_data_cache();
|
||||||
|
|
|
@ -17,11 +17,11 @@
|
||||||
#include <hw/spec/arm/panda_board.h>
|
#include <hw/spec/arm/panda_board.h>
|
||||||
#include <spec/arm/cortex_a9_page_table.h>
|
#include <spec/arm/cortex_a9_page_table.h>
|
||||||
#include <spec/arm/cpu.h>
|
#include <spec/arm/cpu.h>
|
||||||
#include <spec/arm/gicv2.h>
|
#include <hw/spec/arm/gicv2.h>
|
||||||
|
|
||||||
namespace Board {
|
namespace Board {
|
||||||
using namespace Hw::Panda_board;
|
using namespace Hw::Panda_board;
|
||||||
|
using Pic = Hw::Gicv2;
|
||||||
static constexpr bool NON_SECURE = false;
|
static constexpr bool NON_SECURE = false;
|
||||||
|
|
||||||
class L2_cache;
|
class L2_cache;
|
||||||
|
|
|
@ -19,11 +19,13 @@
|
||||||
#include <spec/arm/cortex_a9_actlr.h>
|
#include <spec/arm/cortex_a9_actlr.h>
|
||||||
#include <spec/arm/cortex_a9_page_table.h>
|
#include <spec/arm/cortex_a9_page_table.h>
|
||||||
#include <spec/arm/cpu.h>
|
#include <spec/arm/cpu.h>
|
||||||
#include <spec/arm/gicv2.h>
|
#include <hw/spec/arm/gicv2.h>
|
||||||
|
|
||||||
namespace Board {
|
namespace Board {
|
||||||
using namespace Hw::Pbxa9_board;
|
using namespace Hw::Pbxa9_board;
|
||||||
|
|
||||||
|
using Pic = Hw::Gicv2;
|
||||||
|
|
||||||
static constexpr bool NON_SECURE = false;
|
static constexpr bool NON_SECURE = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,10 +16,7 @@
|
||||||
|
|
||||||
#include <hw/spec/riscv/board.h>
|
#include <hw/spec/riscv/board.h>
|
||||||
|
|
||||||
namespace Board {
|
namespace Board { using namespace Hw::Riscv_board; }
|
||||||
using namespace Hw::Riscv_board;
|
|
||||||
struct Pic {};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename E, unsigned B, unsigned S>
|
template <typename E, unsigned B, unsigned S>
|
||||||
void Sv39::Level_x_translation_table<E, B, S>::_translation_added(addr_t, size_t)
|
void Sv39::Level_x_translation_table<E, B, S>::_translation_added(addr_t, size_t)
|
||||||
|
|
|
@ -18,11 +18,7 @@
|
||||||
#include <hw/spec/arm/page_table.h>
|
#include <hw/spec/arm/page_table.h>
|
||||||
#include <spec/arm/cpu.h>
|
#include <spec/arm/cpu.h>
|
||||||
|
|
||||||
namespace Board {
|
namespace Board { using namespace Hw::Rpi_board; }
|
||||||
using namespace Hw::Rpi_board;
|
|
||||||
|
|
||||||
struct Pic {};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
constexpr unsigned Hw::Page_table::Descriptor_base::_device_tex() {
|
constexpr unsigned Hw::Page_table::Descriptor_base::_device_tex() {
|
||||||
|
|
|
@ -20,8 +20,13 @@
|
||||||
|
|
||||||
namespace Board {
|
namespace Board {
|
||||||
using namespace Hw::Rpi3_board;
|
using namespace Hw::Rpi3_board;
|
||||||
using Cpu = Hw::Arm_64_cpu;
|
|
||||||
struct Pic {};
|
struct Cpu : Hw::Arm_64_cpu
|
||||||
|
{
|
||||||
|
static void wake_up_all_cpus(void*);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Pic { }; /* dummy object */
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _BOOTSTRAP__SPEC__RPI3__BOARD_H_ */
|
#endif /* _BOOTSTRAP__SPEC__RPI3__BOARD_H_ */
|
||||||
|
|
|
@ -26,3 +26,12 @@ Bootstrap::Platform::Board::Board()
|
||||||
::Board::LOCAL_IRQ_CONTROLLER_SIZE },
|
::Board::LOCAL_IRQ_CONTROLLER_SIZE },
|
||||||
Memory_region { ::Board::IRQ_CONTROLLER_BASE,
|
Memory_region { ::Board::IRQ_CONTROLLER_BASE,
|
||||||
::Board::IRQ_CONTROLLER_SIZE }) {}
|
::Board::IRQ_CONTROLLER_SIZE }) {}
|
||||||
|
|
||||||
|
|
||||||
|
extern unsigned int _crt0_qemu_start_secondary_cpus;
|
||||||
|
|
||||||
|
void Board::Cpu::wake_up_all_cpus(void *)
|
||||||
|
{
|
||||||
|
_crt0_qemu_start_secondary_cpus = 1;
|
||||||
|
asm volatile("dsb #0; sev");
|
||||||
|
}
|
||||||
|
|
|
@ -38,6 +38,8 @@ Bootstrap::Platform::Board::Board()
|
||||||
Aipstz aipstz_1(AIPS_1_MMIO_BASE);
|
Aipstz aipstz_1(AIPS_1_MMIO_BASE);
|
||||||
Aipstz aipstz_2(AIPS_2_MMIO_BASE);
|
Aipstz aipstz_2(AIPS_2_MMIO_BASE);
|
||||||
|
|
||||||
|
Pic pic {};
|
||||||
|
|
||||||
/* set monitor mode exception vector entry */
|
/* set monitor mode exception vector entry */
|
||||||
Cpu::Mvbar::write(Hw::Mm::system_exception_vector().base);
|
Cpu::Mvbar::write(Hw::Mm::system_exception_vector().base);
|
||||||
|
|
||||||
|
|
|
@ -18,11 +18,13 @@
|
||||||
#include <spec/arm/cortex_a9_actlr.h>
|
#include <spec/arm/cortex_a9_actlr.h>
|
||||||
#include <spec/arm/cortex_a9_page_table.h>
|
#include <spec/arm/cortex_a9_page_table.h>
|
||||||
#include <spec/arm/cpu.h>
|
#include <spec/arm/cpu.h>
|
||||||
#include <spec/arm/gicv2.h>
|
#include <hw/spec/arm/gicv2.h>
|
||||||
|
|
||||||
namespace Board {
|
namespace Board {
|
||||||
using namespace Hw::Wand_quad_board;
|
using namespace Hw::Wand_quad_board;
|
||||||
|
|
||||||
|
using Pic = Hw::Gicv2;
|
||||||
|
|
||||||
struct L2_cache;
|
struct L2_cache;
|
||||||
|
|
||||||
static constexpr bool NON_SECURE = false;
|
static constexpr bool NON_SECURE = false;
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
namespace Board {
|
namespace Board {
|
||||||
using namespace Hw::Pc_board;
|
using namespace Hw::Pc_board;
|
||||||
using Cpu = Hw::X86_64_cpu;
|
using Cpu = Hw::X86_64_cpu;
|
||||||
struct Pic {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _SRC__BOOTSTRAP__SPEC__X86_64__BOARD_H_ */
|
#endif /* _SRC__BOOTSTRAP__SPEC__X86_64__BOARD_H_ */
|
||||||
|
|
|
@ -18,10 +18,11 @@
|
||||||
#include <spec/arm/cortex_a9_actlr.h>
|
#include <spec/arm/cortex_a9_actlr.h>
|
||||||
#include <spec/arm/cortex_a9_page_table.h>
|
#include <spec/arm/cortex_a9_page_table.h>
|
||||||
#include <spec/arm/cpu.h>
|
#include <spec/arm/cpu.h>
|
||||||
#include <spec/arm/gicv2.h>
|
#include <hw/spec/arm/gicv2.h>
|
||||||
|
|
||||||
namespace Board {
|
namespace Board {
|
||||||
using namespace Hw::Zynq_qemu_board;
|
using namespace Hw::Zynq_qemu_board;
|
||||||
|
using Pic = Hw::Gicv2;
|
||||||
static constexpr bool NON_SECURE = false;
|
static constexpr bool NON_SECURE = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
/* core includes */
|
/* core includes */
|
||||||
#include "kernel/irq.h"
|
#include "kernel/irq.h"
|
||||||
#include <irq_root.h>
|
#include <irq_root.h>
|
||||||
#include <irq_args.h>
|
|
||||||
#include <core_env.h>
|
#include <core_env.h>
|
||||||
|
|
||||||
/* base-internal includes */
|
/* base-internal includes */
|
||||||
|
@ -35,10 +34,7 @@ unsigned Irq_session_component::_find_irq_number(const char * const args)
|
||||||
|
|
||||||
void Irq_session_component::ack_irq()
|
void Irq_session_component::ack_irq()
|
||||||
{
|
{
|
||||||
using Kernel::User_irq;
|
if (_kobj.constructed()) Kernel::ack_irq(*_kobj);
|
||||||
if (!_sig_cap.valid()) { return; }
|
|
||||||
User_irq * const kirq = reinterpret_cast<User_irq*>(&_kernel_object);
|
|
||||||
Kernel::ack_irq(kirq);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -51,8 +47,8 @@ void Irq_session_component::sigh(Signal_context_capability cap)
|
||||||
|
|
||||||
_sig_cap = cap;
|
_sig_cap = cap;
|
||||||
|
|
||||||
if (Kernel::new_irq((addr_t)&_kernel_object, _irq_number,
|
if (!_kobj.create(_irq_number, _irq_args.trigger(), _irq_args.polarity(),
|
||||||
Capability_space::capid(_sig_cap)))
|
Capability_space::capid(_sig_cap)))
|
||||||
warning("invalid signal handler for IRQ ", _irq_number);
|
warning("invalid signal handler for IRQ ", _irq_number);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,18 +57,16 @@ Irq_session_component::~Irq_session_component()
|
||||||
{
|
{
|
||||||
using namespace Kernel;
|
using namespace Kernel;
|
||||||
|
|
||||||
User_irq * kirq = reinterpret_cast<User_irq*>(&_kernel_object);
|
|
||||||
_irq_alloc.free((void *)(addr_t)_irq_number);
|
_irq_alloc.free((void *)(addr_t)_irq_number);
|
||||||
if (_sig_cap.valid())
|
|
||||||
Kernel::delete_irq(kirq);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Irq_session_component::Irq_session_component(Range_allocator &irq_alloc,
|
Irq_session_component::Irq_session_component(Range_allocator &irq_alloc,
|
||||||
const char * const args)
|
const char * const args)
|
||||||
:
|
: _irq_args(args),
|
||||||
_irq_number(Platform::irq(_find_irq_number(args))), _irq_alloc(irq_alloc),
|
_irq_number(Platform::irq(_irq_args.irq_number())),
|
||||||
_is_msi(false), _address(0), _value(0)
|
_irq_alloc(irq_alloc),
|
||||||
|
_kobj(), _is_msi(false), _address(0), _value(0)
|
||||||
{
|
{
|
||||||
const long mmconf =
|
const long mmconf =
|
||||||
Arg_string::find_arg(args, "device_config_phys").long_value(0);
|
Arg_string::find_arg(args, "device_config_phys").long_value(0);
|
||||||
|
@ -89,8 +83,4 @@ Irq_session_component::Irq_session_component(Range_allocator &irq_alloc,
|
||||||
error("unavailable interrupt ", _irq_number, " requested");
|
error("unavailable interrupt ", _irq_number, " requested");
|
||||||
throw Service_denied();
|
throw Service_denied();
|
||||||
}
|
}
|
||||||
|
|
||||||
Irq_args const irq_args(args);
|
|
||||||
|
|
||||||
Kernel::irq_mode(_irq_number, irq_args.trigger(), irq_args.polarity());
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ namespace Kernel
|
||||||
class Vm;
|
class Vm;
|
||||||
class User_irq;
|
class User_irq;
|
||||||
using Native_utcb = Genode::Native_utcb;
|
using Native_utcb = Genode::Native_utcb;
|
||||||
|
template <typename T> class Core_object_identity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kernel names of the kernel calls
|
* Kernel names of the kernel calls
|
||||||
|
@ -60,15 +61,14 @@ namespace Kernel
|
||||||
constexpr Call_arg call_id_delete_obj() { return 122; }
|
constexpr Call_arg call_id_delete_obj() { return 122; }
|
||||||
constexpr Call_arg call_id_cancel_thread_blocking() { return 123; }
|
constexpr Call_arg call_id_cancel_thread_blocking() { return 123; }
|
||||||
constexpr Call_arg call_id_new_core_thread() { return 124; }
|
constexpr Call_arg call_id_new_core_thread() { return 124; }
|
||||||
constexpr Call_arg call_id_irq_mode() { return 125; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invalidate TLB entries for the `pd` in region `addr`, `sz`
|
* Invalidate TLB entries for the `pd` in region `addr`, `sz`
|
||||||
*/
|
*/
|
||||||
inline void invalidate_tlb(Pd * const pd, addr_t const addr,
|
inline void invalidate_tlb(Pd & pd, addr_t const addr,
|
||||||
size_t const sz)
|
size_t const sz)
|
||||||
{
|
{
|
||||||
call(call_id_invalidate_tlb(), (Call_arg)pd, (Call_arg)addr,
|
call(call_id_invalidate_tlb(), (Call_arg)&pd, (Call_arg)addr,
|
||||||
(Call_arg)sz);
|
(Call_arg)sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,9 +79,9 @@ namespace Kernel
|
||||||
* \param thread kernel object of the targeted thread
|
* \param thread kernel object of the targeted thread
|
||||||
* \param quota new CPU quota value
|
* \param quota new CPU quota value
|
||||||
*/
|
*/
|
||||||
inline void thread_quota(Kernel::Thread * const thread, size_t const quota)
|
inline void thread_quota(Kernel::Thread & thread, size_t const quota)
|
||||||
{
|
{
|
||||||
call(call_id_thread_quota(), (Call_arg)thread, (Call_arg)quota);
|
call(call_id_thread_quota(), (Call_arg)&thread, (Call_arg)quota);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -104,9 +104,9 @@ namespace Kernel
|
||||||
* continue the execution of a thread no matter what state the thread is
|
* continue the execution of a thread no matter what state the thread is
|
||||||
* in.
|
* in.
|
||||||
*/
|
*/
|
||||||
inline void pause_thread(Thread * const thread)
|
inline void pause_thread(Thread & thread)
|
||||||
{
|
{
|
||||||
call(call_id_pause_thread(), (Call_arg)thread);
|
call(call_id_pause_thread(), (Call_arg)&thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -115,9 +115,9 @@ namespace Kernel
|
||||||
*
|
*
|
||||||
* \param thread pointer to thread kernel object
|
* \param thread pointer to thread kernel object
|
||||||
*/
|
*/
|
||||||
inline void resume_thread(Thread * const thread)
|
inline void resume_thread(Thread & thread)
|
||||||
{
|
{
|
||||||
call(call_id_resume_thread(), (Call_arg)thread);
|
call(call_id_resume_thread(), (Call_arg)&thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -132,11 +132,11 @@ namespace Kernel
|
||||||
* \retval 0 suceeded
|
* \retval 0 suceeded
|
||||||
* \retval !=0 failed
|
* \retval !=0 failed
|
||||||
*/
|
*/
|
||||||
inline int start_thread(Thread * const thread, unsigned const cpu_id,
|
inline int start_thread(Thread & thread, unsigned const cpu_id,
|
||||||
Pd * const pd, Native_utcb * const utcb)
|
Pd & pd, Native_utcb & utcb)
|
||||||
{
|
{
|
||||||
return call(call_id_start_thread(), (Call_arg)thread, cpu_id,
|
return call(call_id_start_thread(), (Call_arg)&thread, cpu_id,
|
||||||
(Call_arg)pd, (Call_arg)utcb);
|
(Call_arg)&pd, (Call_arg)&utcb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -155,9 +155,9 @@ namespace Kernel
|
||||||
* limit the time a parent waits for a server when closing a session
|
* limit the time a parent waits for a server when closing a session
|
||||||
* of one of its children.
|
* of one of its children.
|
||||||
*/
|
*/
|
||||||
inline void cancel_thread_blocking(Thread * const thread)
|
inline void cancel_thread_blocking(Thread & thread)
|
||||||
{
|
{
|
||||||
call(call_id_cancel_thread_blocking(), (Call_arg)thread);
|
call(call_id_cancel_thread_blocking(), (Call_arg)&thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -167,10 +167,10 @@ namespace Kernel
|
||||||
* \param thread pointer to thread kernel object
|
* \param thread pointer to thread kernel object
|
||||||
* \param signal_context_id capability id of the page-fault handler
|
* \param signal_context_id capability id of the page-fault handler
|
||||||
*/
|
*/
|
||||||
inline void thread_pager(Thread * const thread,
|
inline void thread_pager(Thread & thread,
|
||||||
capid_t const signal_context_id)
|
capid_t const signal_context_id)
|
||||||
{
|
{
|
||||||
call(call_id_thread_pager(), (Call_arg)thread, signal_context_id);
|
call(call_id_thread_pager(), (Call_arg)&thread, signal_context_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -179,9 +179,9 @@ namespace Kernel
|
||||||
*
|
*
|
||||||
* \param vm pointer to vm kernel object
|
* \param vm pointer to vm kernel object
|
||||||
*/
|
*/
|
||||||
inline void run_vm(Vm * const vm)
|
inline void run_vm(Vm & vm)
|
||||||
{
|
{
|
||||||
call(call_id_run_vm(), (Call_arg) vm);
|
call(call_id_run_vm(), (Call_arg) &vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -190,33 +190,9 @@ namespace Kernel
|
||||||
*
|
*
|
||||||
* \param vm pointer to vm kernel object
|
* \param vm pointer to vm kernel object
|
||||||
*/
|
*/
|
||||||
inline void pause_vm(Vm * const vm)
|
inline void pause_vm(Vm & vm)
|
||||||
{
|
{
|
||||||
call(call_id_pause_vm(), (Call_arg) vm);
|
call(call_id_pause_vm(), (Call_arg) &vm);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an interrupt object
|
|
||||||
*
|
|
||||||
* \param p memory donation for the irq object
|
|
||||||
* \param irq_nr interrupt number
|
|
||||||
* \param signal_context_id capability id of the signal context
|
|
||||||
*/
|
|
||||||
inline int new_irq(addr_t const p, unsigned irq_nr,
|
|
||||||
capid_t signal_context_id)
|
|
||||||
{
|
|
||||||
return call(call_id_new_irq(), (Call_arg) p, irq_nr, signal_context_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set trigger/polaruty of IRQ
|
|
||||||
* \param irq_nr interrupt number
|
|
||||||
* \param trigger low or edge
|
|
||||||
* \param polarity low or high
|
|
||||||
*/
|
|
||||||
inline void irq_mode(unsigned irq_nr, unsigned trigger, unsigned polarity)
|
|
||||||
{
|
|
||||||
call(call_id_irq_mode(), irq_nr, trigger, polarity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -224,40 +200,9 @@ namespace Kernel
|
||||||
*
|
*
|
||||||
* \param irq pointer to interrupt kernel object
|
* \param irq pointer to interrupt kernel object
|
||||||
*/
|
*/
|
||||||
inline void ack_irq(User_irq * const irq)
|
inline void ack_irq(User_irq & irq)
|
||||||
{
|
{
|
||||||
call(call_id_ack_irq(), (Call_arg) irq);
|
call(call_id_ack_irq(), (Call_arg) &irq);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destruct an interrupt object
|
|
||||||
*
|
|
||||||
* \param irq pointer to interrupt kernel object
|
|
||||||
*/
|
|
||||||
inline void delete_irq(User_irq * const irq)
|
|
||||||
{
|
|
||||||
call(call_id_delete_irq(), (Call_arg) irq);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new object identity for a thread
|
|
||||||
*
|
|
||||||
* \param dst memory donation for the new object
|
|
||||||
* \param cap capability id of the targeted thread
|
|
||||||
*/
|
|
||||||
inline capid_t new_obj(void * const dst, capid_t const cap)
|
|
||||||
{
|
|
||||||
return call(call_id_new_obj(), (Call_arg)dst, (Call_arg)cap);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destroy an object identity
|
|
||||||
*
|
|
||||||
* \param dst pointer to the object identity object
|
|
||||||
*/
|
|
||||||
inline void delete_obj(void * const dst)
|
|
||||||
{
|
|
||||||
call(call_id_delete_obj(), (Call_arg)dst);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -157,10 +157,10 @@ addr_t Cpu::stack_start() {
|
||||||
return (addr_t)&kernel_stack + KERNEL_STACK_SIZE * (_id+1); }
|
return (addr_t)&kernel_stack + KERNEL_STACK_SIZE * (_id+1); }
|
||||||
|
|
||||||
|
|
||||||
Cpu::Cpu(unsigned const id, Board::Pic & pic,
|
Cpu::Cpu(unsigned const id,
|
||||||
Inter_processor_work_list & global_work_list)
|
Inter_processor_work_list & global_work_list)
|
||||||
:
|
:
|
||||||
_id(id), _pic(pic), _timer(*this),
|
_id(id), _timer(*this),
|
||||||
_scheduler(&_idle, _quota(), _fill()), _idle(*this),
|
_scheduler(&_idle, _quota(), _fill()), _idle(*this),
|
||||||
_ipi_irq(*this),
|
_ipi_irq(*this),
|
||||||
_global_work_list(global_work_list)
|
_global_work_list(global_work_list)
|
||||||
|
@ -174,7 +174,7 @@ Cpu::Cpu(unsigned const id, Board::Pic & pic,
|
||||||
bool Cpu_pool::initialize()
|
bool Cpu_pool::initialize()
|
||||||
{
|
{
|
||||||
unsigned id = Cpu::executing_id();
|
unsigned id = Cpu::executing_id();
|
||||||
_cpus[id].construct(id, _pic, _global_work_list);
|
_cpus[id].construct(id, _global_work_list);
|
||||||
return --_initialized == 0;
|
return --_initialized == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -113,7 +113,7 @@ class Kernel::Cpu : public Genode::Cpu, private Irq::Pool, private Timeout
|
||||||
|
|
||||||
|
|
||||||
unsigned const _id;
|
unsigned const _id;
|
||||||
Board::Pic &_pic;
|
Board::Pic _pic {};
|
||||||
Timer _timer;
|
Timer _timer;
|
||||||
Cpu_scheduler _scheduler;
|
Cpu_scheduler _scheduler;
|
||||||
Idle_thread _idle;
|
Idle_thread _idle;
|
||||||
|
@ -133,7 +133,7 @@ class Kernel::Cpu : public Genode::Cpu, private Irq::Pool, private Timeout
|
||||||
/**
|
/**
|
||||||
* Construct object for CPU 'id'
|
* Construct object for CPU 'id'
|
||||||
*/
|
*/
|
||||||
Cpu(unsigned const id, Board::Pic & pic,
|
Cpu(unsigned const id,
|
||||||
Inter_processor_work_list & global_work_list);
|
Inter_processor_work_list & global_work_list);
|
||||||
|
|
||||||
static inline unsigned primary_id() { return 0; }
|
static inline unsigned primary_id() { return 0; }
|
||||||
|
@ -192,7 +192,6 @@ class Kernel::Cpu_pool
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Board::Pic _pic {};
|
|
||||||
Inter_processor_work_list _global_work_list {};
|
Inter_processor_work_list _global_work_list {};
|
||||||
unsigned _count;
|
unsigned _count;
|
||||||
unsigned _initialized { _count };
|
unsigned _initialized { _count };
|
||||||
|
|
|
@ -46,4 +46,6 @@ void Cpu::trigger_ip_interrupt()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Cpu::Ipi::Ipi(Cpu & cpu) : Irq(Board::Pic::IPI, cpu), cpu(cpu) { }
|
Cpu::Ipi::Ipi(Cpu & cpu)
|
||||||
|
: Irq(Board::Pic::IPI, cpu), cpu(cpu) {
|
||||||
|
cpu.pic().unmask(Board::Pic::IPI, cpu.id()); }
|
||||||
|
|
|
@ -15,9 +15,6 @@
|
||||||
#ifndef _CORE__KERNEL__IPC_NODE_H_
|
#ifndef _CORE__KERNEL__IPC_NODE_H_
|
||||||
#define _CORE__KERNEL__IPC_NODE_H_
|
#define _CORE__KERNEL__IPC_NODE_H_
|
||||||
|
|
||||||
/* Genode includes */
|
|
||||||
#include <util/construct_at.h>
|
|
||||||
|
|
||||||
/* base-local includes */
|
/* base-local includes */
|
||||||
#include <base/internal/native_utcb.h>
|
#include <base/internal/native_utcb.h>
|
||||||
|
|
||||||
|
|
|
@ -30,3 +30,14 @@ Kernel::Irq::Pool &Kernel::User_irq::_pool()
|
||||||
static Irq::Pool p;
|
static Irq::Pool p;
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Kernel::User_irq::User_irq(unsigned const irq,
|
||||||
|
Genode::Irq_session::Trigger trigger,
|
||||||
|
Genode::Irq_session::Polarity polarity,
|
||||||
|
Signal_context & context)
|
||||||
|
: Irq(irq, _pool()), _context(context)
|
||||||
|
{
|
||||||
|
disable();
|
||||||
|
cpu_pool().executing_cpu().pic().irq_mode(_irq_nr, trigger, polarity);
|
||||||
|
}
|
||||||
|
|
|
@ -135,8 +135,10 @@ class Kernel::User_irq : public Kernel::Irq, public Kernel::Object
|
||||||
/**
|
/**
|
||||||
* Construct object that signals interrupt 'irq' via signal 'context'
|
* Construct object that signals interrupt 'irq' via signal 'context'
|
||||||
*/
|
*/
|
||||||
User_irq(unsigned const irq, Signal_context &context)
|
User_irq(unsigned const irq,
|
||||||
: Irq(irq, _pool()), _context(context) { disable(); }
|
Genode::Irq_session::Trigger trigger,
|
||||||
|
Genode::Irq_session::Polarity polarity,
|
||||||
|
Signal_context & context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destructor
|
* Destructor
|
||||||
|
@ -157,6 +159,33 @@ class Kernel::User_irq : public Kernel::Irq, public Kernel::Object
|
||||||
*/
|
*/
|
||||||
static User_irq * object(unsigned const irq) {
|
static User_irq * object(unsigned const irq) {
|
||||||
return dynamic_cast<User_irq*>(_pool().object(irq)); }
|
return dynamic_cast<User_irq*>(_pool().object(irq)); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Syscall to create user irq object
|
||||||
|
*
|
||||||
|
* \param irq reference to constructible object
|
||||||
|
* \param nr interrupt number
|
||||||
|
* \param trigger level or edge
|
||||||
|
* \param polarity low or high
|
||||||
|
* \param sig capability of signal context
|
||||||
|
*/
|
||||||
|
static capid_t syscall_create(Genode::Kernel_object<User_irq> & irq,
|
||||||
|
unsigned nr,
|
||||||
|
Genode::Irq_session::Trigger trigger,
|
||||||
|
Genode::Irq_session::Polarity polarity,
|
||||||
|
capid_t sig)
|
||||||
|
{
|
||||||
|
return call(call_id_new_irq(), (Call_arg)&irq, nr,
|
||||||
|
(trigger << 2) | polarity, sig);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Syscall to delete user irq object
|
||||||
|
*
|
||||||
|
* \param irq reference to constructible object
|
||||||
|
*/
|
||||||
|
static void syscall_destroy(Genode::Kernel_object<User_irq> &irq) {
|
||||||
|
call(call_id_delete_irq(), (Call_arg) &irq); }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _CORE__KERNEL__IRQ_H_ */
|
#endif /* _CORE__KERNEL__IRQ_H_ */
|
||||||
|
|
|
@ -31,7 +31,7 @@ class Kernel::Lock
|
||||||
|
|
||||||
enum State { UNLOCKED, LOCKED };
|
enum State { UNLOCKED, LOCKED };
|
||||||
|
|
||||||
State volatile _locked { UNLOCKED };
|
int volatile _locked { UNLOCKED };
|
||||||
unsigned volatile _current_cpu { INVALID };
|
unsigned volatile _current_cpu { INVALID };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -18,8 +18,10 @@
|
||||||
#include <util/avl_tree.h>
|
#include <util/avl_tree.h>
|
||||||
#include <util/bit_allocator.h>
|
#include <util/bit_allocator.h>
|
||||||
#include <util/list.h>
|
#include <util/list.h>
|
||||||
|
#include <util/reconstructible.h>
|
||||||
|
|
||||||
/* core includes */
|
/* core includes */
|
||||||
|
#include <kernel/core_interface.h>
|
||||||
#include <kernel/interface.h>
|
#include <kernel/interface.h>
|
||||||
#include "kernel.h"
|
#include "kernel.h"
|
||||||
|
|
||||||
|
@ -192,6 +194,13 @@ class Kernel::Core_object_identity : public Object_identity,
|
||||||
Object_identity_reference(this, core_pd()) { }
|
Object_identity_reference(this, core_pd()) { }
|
||||||
|
|
||||||
capid_t core_capid() { return capid(); }
|
capid_t core_capid() { return capid(); }
|
||||||
|
|
||||||
|
static capid_t syscall_create(Genode::Constructible<Core_object_identity<T>> & t,
|
||||||
|
capid_t const cap) {
|
||||||
|
return call(call_id_new_obj(), (Call_arg)&t, (Call_arg)cap); }
|
||||||
|
|
||||||
|
static void syscall_destroy(Genode::Constructible<Core_object_identity<T>> & t) {
|
||||||
|
call(call_id_delete_obj(), (Call_arg)&t); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,10 +18,12 @@
|
||||||
/* core includes */
|
/* core includes */
|
||||||
#include <hw/assert.h>
|
#include <hw/assert.h>
|
||||||
#include <cpu.h>
|
#include <cpu.h>
|
||||||
#include "core_interface.h"
|
#include <kernel/core_interface.h>
|
||||||
#include "object.h"
|
#include <object.h>
|
||||||
#include <translation_table.h>
|
#include <translation_table.h>
|
||||||
|
|
||||||
|
#include <util/reconstructible.h>
|
||||||
|
|
||||||
namespace Genode {
|
namespace Genode {
|
||||||
class Platform_pd;
|
class Platform_pd;
|
||||||
}
|
}
|
||||||
|
@ -51,6 +53,7 @@ class Kernel::Pd : public Kernel::Object
|
||||||
Genode::Platform_pd &_platform_pd;
|
Genode::Platform_pd &_platform_pd;
|
||||||
Capid_allocator _capid_alloc { };
|
Capid_allocator _capid_alloc { };
|
||||||
Object_identity_reference_tree _cap_tree { };
|
Object_identity_reference_tree _cap_tree { };
|
||||||
|
bool _core_pd { false };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -69,6 +72,12 @@ class Kernel::Pd : public Kernel::Object
|
||||||
{
|
{
|
||||||
capid_t invalid = _capid_alloc.alloc();
|
capid_t invalid = _capid_alloc.alloc();
|
||||||
assert(invalid == cap_id_invalid());
|
assert(invalid == cap_id_invalid());
|
||||||
|
|
||||||
|
static bool first_pd = true;
|
||||||
|
if (first_pd) {
|
||||||
|
_core_pd = true;
|
||||||
|
first_pd = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
~Pd()
|
~Pd()
|
||||||
|
@ -77,16 +86,16 @@ class Kernel::Pd : public Kernel::Object
|
||||||
oir->~Object_identity_reference();
|
oir->~Object_identity_reference();
|
||||||
}
|
}
|
||||||
|
|
||||||
static capid_t syscall_create(void * const dst,
|
static capid_t syscall_create(Genode::Kernel_object<Pd> & p,
|
||||||
Hw::Page_table &tt,
|
Hw::Page_table & tt,
|
||||||
Genode::Platform_pd &pd)
|
Genode::Platform_pd & pd)
|
||||||
{
|
{
|
||||||
return call(call_id_new_pd(), (Call_arg)dst,
|
return call(call_id_new_pd(), (Call_arg)&p,
|
||||||
(Call_arg)&tt, (Call_arg)&pd);
|
(Call_arg)&tt, (Call_arg)&pd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void syscall_destroy(Pd * const pd) {
|
static void syscall_destroy(Genode::Kernel_object<Pd> & p) {
|
||||||
call(call_id_delete_pd(), (Call_arg)pd); }
|
call(call_id_delete_pd(), (Call_arg)&p); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether the given 'cpu' needs to do some maintainance
|
* Check whether the given 'cpu' needs to do some maintainance
|
||||||
|
@ -103,6 +112,13 @@ class Kernel::Pd : public Kernel::Object
|
||||||
Hw::Page_table &translation_table() { return _table; }
|
Hw::Page_table &translation_table() { return _table; }
|
||||||
Capid_allocator &capid_alloc() { return _capid_alloc; }
|
Capid_allocator &capid_alloc() { return _capid_alloc; }
|
||||||
Object_identity_reference_tree &cap_tree() { return _cap_tree; }
|
Object_identity_reference_tree &cap_tree() { return _cap_tree; }
|
||||||
|
bool core_pd() const { return _core_pd; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline Kernel::Core_object_identity<Kernel::Pd>::Core_object_identity(Kernel::Pd & pd)
|
||||||
|
: Object_identity(pd),
|
||||||
|
Object_identity_reference(this, pd.core_pd() ? pd : core_pd()) { }
|
||||||
|
|
||||||
#endif /* _CORE__KERNEL__PD_H_ */
|
#endif /* _CORE__KERNEL__PD_H_ */
|
||||||
|
|
|
@ -55,7 +55,7 @@ Signal_context_killer::~Signal_context_killer() { cancel_waiting(); }
|
||||||
|
|
||||||
void Signal_context::_deliverable()
|
void Signal_context::_deliverable()
|
||||||
{
|
{
|
||||||
if (_submits) { _receiver->_add_deliverable(this); }
|
if (_submits) { _receiver._add_deliverable(this); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -118,16 +118,15 @@ int Signal_context::kill(Signal_context_killer * const k)
|
||||||
Signal_context::~Signal_context()
|
Signal_context::~Signal_context()
|
||||||
{
|
{
|
||||||
if (_killer) { _killer->_signal_context_kill_failed(); }
|
if (_killer) { _killer->_signal_context_kill_failed(); }
|
||||||
_receiver->_context_destructed(this);
|
_receiver._context_destructed(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Signal_context::Signal_context(Signal_receiver * const r, addr_t const imprint)
|
Signal_context::Signal_context(Signal_receiver & r, addr_t const imprint)
|
||||||
:
|
: _receiver(r),
|
||||||
_receiver(r),
|
_imprint(imprint)
|
||||||
_imprint(imprint)
|
|
||||||
{
|
{
|
||||||
r->_add_context(this);
|
r._add_context(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -164,7 +163,7 @@ void Signal_receiver::_listen()
|
||||||
/* communicate signal data to handler */
|
/* communicate signal data to handler */
|
||||||
_handlers.dequeue([&] (Signal_handler::Fifo_element &elem) {
|
_handlers.dequeue([&] (Signal_handler::Fifo_element &elem) {
|
||||||
auto const handler = &elem.object();
|
auto const handler = &elem.object();
|
||||||
handler->_receiver = 0;
|
handler->_receiver = nullptr;
|
||||||
handler->_receive_signal(&data, sizeof(data));
|
handler->_receive_signal(&data, sizeof(data));
|
||||||
});
|
});
|
||||||
context->_delivered();
|
context->_delivered();
|
||||||
|
|
|
@ -16,9 +16,10 @@
|
||||||
|
|
||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
#include <base/signal.h>
|
#include <base/signal.h>
|
||||||
|
#include <util/reconstructible.h>
|
||||||
|
|
||||||
#include "core_interface.h"
|
#include <kernel/core_interface.h>
|
||||||
#include "object.h"
|
#include <object.h>
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
@ -160,7 +161,7 @@ class Kernel::Signal_context : public Kernel::Object
|
||||||
|
|
||||||
Fifo_element _deliver_fe { *this };
|
Fifo_element _deliver_fe { *this };
|
||||||
Fifo_element _contexts_fe { *this };
|
Fifo_element _contexts_fe { *this };
|
||||||
Signal_receiver * const _receiver;
|
Signal_receiver & _receiver;
|
||||||
addr_t const _imprint;
|
addr_t const _imprint;
|
||||||
Signal_context_killer * _killer { nullptr };
|
Signal_context_killer * _killer { nullptr };
|
||||||
unsigned _submits { 0 };
|
unsigned _submits { 0 };
|
||||||
|
@ -197,7 +198,7 @@ class Kernel::Signal_context : public Kernel::Object
|
||||||
*
|
*
|
||||||
* \throw Assign_to_receiver_failed
|
* \throw Assign_to_receiver_failed
|
||||||
*/
|
*/
|
||||||
Signal_context(Signal_receiver * const r, addr_t const imprint);
|
Signal_context(Signal_receiver & r, addr_t const imprint);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Submit the signal
|
* Submit the signal
|
||||||
|
@ -233,12 +234,12 @@ class Kernel::Signal_context : public Kernel::Object
|
||||||
*
|
*
|
||||||
* \retval capability id of the new kernel object
|
* \retval capability id of the new kernel object
|
||||||
*/
|
*/
|
||||||
static capid_t syscall_create(void * p,
|
static capid_t syscall_create(Genode::Kernel_object<Signal_context> &c,
|
||||||
Signal_receiver * const receiver,
|
Signal_receiver & receiver,
|
||||||
addr_t const imprint)
|
addr_t const imprint)
|
||||||
{
|
{
|
||||||
return call(call_id_new_signal_context(), (Call_arg)p,
|
return call(call_id_new_signal_context(), (Call_arg)&c,
|
||||||
(Call_arg)receiver, (Call_arg)imprint);
|
(Call_arg)&receiver, (Call_arg)imprint);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -246,8 +247,8 @@ class Kernel::Signal_context : public Kernel::Object
|
||||||
*
|
*
|
||||||
* \param context pointer to signal context kernel object
|
* \param context pointer to signal context kernel object
|
||||||
*/
|
*/
|
||||||
static void syscall_destroy(Signal_context * const context) {
|
static void syscall_destroy(Genode::Kernel_object<Signal_context> &c) {
|
||||||
call(call_id_delete_signal_context(), (Call_arg)context); }
|
call(call_id_delete_signal_context(), (Call_arg)&c); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class Kernel::Signal_receiver : public Kernel::Object
|
class Kernel::Signal_receiver : public Kernel::Object
|
||||||
|
@ -311,16 +312,16 @@ class Kernel::Signal_receiver : public Kernel::Object
|
||||||
*
|
*
|
||||||
* \retval capability id of the new kernel object
|
* \retval capability id of the new kernel object
|
||||||
*/
|
*/
|
||||||
static capid_t syscall_create(void * p) {
|
static capid_t syscall_create(Genode::Kernel_object<Signal_receiver> &r) {
|
||||||
return call(call_id_new_signal_receiver(), (Call_arg)p); }
|
return call(call_id_new_signal_receiver(), (Call_arg)&r); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Syscall to destruct a signal receiver
|
* Syscall to destruct a signal receiver
|
||||||
*
|
*
|
||||||
* \param receiver pointer to signal receiver kernel object
|
* \param receiver pointer to signal receiver kernel object
|
||||||
*/
|
*/
|
||||||
static void syscall_destroy(Signal_receiver * const receiver) {
|
static void syscall_destroy(Genode::Kernel_object<Signal_receiver> &r) {
|
||||||
call(call_id_delete_signal_receiver(), (Call_arg)receiver); }
|
call(call_id_delete_signal_receiver(), (Call_arg)&r); }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _CORE__KERNEL__SIGNAL_RECEIVER_H_ */
|
#endif /* _CORE__KERNEL__SIGNAL_RECEIVER_H_ */
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
#include <base/thread_state.h>
|
#include <base/thread_state.h>
|
||||||
#include <cpu_session/cpu_session.h>
|
#include <cpu_session/cpu_session.h>
|
||||||
#include <util/construct_at.h>
|
|
||||||
|
|
||||||
/* base-internal includes */
|
/* base-internal includes */
|
||||||
#include <base/internal/unmanaged_singleton.h>
|
#include <base/internal/unmanaged_singleton.h>
|
||||||
|
@ -47,17 +46,17 @@ Thread::Tlb_invalidation::Tlb_invalidation(Thread & caller, Pd & pd,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Thread::Destroy::Destroy(Thread & caller, Thread & to_delete)
|
Thread::Destroy::Destroy(Thread & caller, Genode::Kernel_object<Thread> & to_delete)
|
||||||
: caller(caller), thread_to_destroy(to_delete)
|
: caller(caller), thread_to_destroy(to_delete)
|
||||||
{
|
{
|
||||||
thread_to_destroy._cpu->work_list().insert(&_le);
|
thread_to_destroy->_cpu->work_list().insert(&_le);
|
||||||
caller._become_inactive(AWAITS_RESTART);
|
caller._become_inactive(AWAITS_RESTART);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread::Destroy::execute()
|
void Thread::Destroy::execute()
|
||||||
{
|
{
|
||||||
thread_to_destroy.~Thread();
|
thread_to_destroy.destruct();
|
||||||
cpu_pool().executing_cpu().work_list().remove(&_le);
|
cpu_pool().executing_cpu().work_list().remove(&_le);
|
||||||
caller._restart();
|
caller._restart();
|
||||||
}
|
}
|
||||||
|
@ -193,28 +192,6 @@ size_t Thread::_core_to_kernel_quota(size_t const quota) const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread::_call_new_thread()
|
|
||||||
{
|
|
||||||
void * const p = (void *)user_arg_1();
|
|
||||||
unsigned const priority = user_arg_2();
|
|
||||||
unsigned const quota = _core_to_kernel_quota(user_arg_3());
|
|
||||||
char const * const label = (char *)user_arg_4();
|
|
||||||
Core_object<Thread> * co =
|
|
||||||
Genode::construct_at<Core_object<Thread> >(p, priority, quota, label);
|
|
||||||
user_arg_0(co->core_capid());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Thread::_call_new_core_thread()
|
|
||||||
{
|
|
||||||
void * const p = (void *)user_arg_1();
|
|
||||||
char const * const label = (char *)user_arg_2();
|
|
||||||
Core_object<Thread> * co =
|
|
||||||
Genode::construct_at<Core_object<Thread> >(p, label);
|
|
||||||
user_arg_0(co->core_capid());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Thread::_call_thread_quota()
|
void Thread::_call_thread_quota()
|
||||||
{
|
{
|
||||||
Thread * const thread = (Thread *)user_arg_1();
|
Thread * const thread = (Thread *)user_arg_1();
|
||||||
|
@ -227,7 +204,7 @@ void Thread::_call_start_thread()
|
||||||
/* lookup CPU */
|
/* lookup CPU */
|
||||||
Cpu & cpu = cpu_pool().cpu(user_arg_2());
|
Cpu & cpu = cpu_pool().cpu(user_arg_2());
|
||||||
user_arg_0(0);
|
user_arg_0(0);
|
||||||
Thread &thread = *(Thread *)user_arg_1();
|
Thread &thread = *(Thread*)user_arg_1();
|
||||||
|
|
||||||
assert(thread._state == AWAITS_START);
|
assert(thread._state == AWAITS_START);
|
||||||
|
|
||||||
|
@ -338,7 +315,8 @@ void Thread::_call_yield_thread()
|
||||||
|
|
||||||
void Thread::_call_delete_thread()
|
void Thread::_call_delete_thread()
|
||||||
{
|
{
|
||||||
Thread * to_delete = reinterpret_cast<Thread*>(user_arg_1());
|
Genode::Kernel_object<Thread> & to_delete =
|
||||||
|
*(Genode::Kernel_object<Thread>*)user_arg_1();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a thread immediately if it has no cpu assigned yet,
|
* Delete a thread immediately if it has no cpu assigned yet,
|
||||||
|
@ -346,7 +324,7 @@ void Thread::_call_delete_thread()
|
||||||
*/
|
*/
|
||||||
if (!to_delete->_cpu ||
|
if (!to_delete->_cpu ||
|
||||||
(to_delete->_cpu->id() == Cpu::executing_id() ||
|
(to_delete->_cpu->id() == Cpu::executing_id() ||
|
||||||
&to_delete->_cpu->scheduled_job() != to_delete)) {
|
&to_delete->_cpu->scheduled_job() != &*to_delete)) {
|
||||||
_call_delete<Thread>();
|
_call_delete<Thread>();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -354,7 +332,7 @@ void Thread::_call_delete_thread()
|
||||||
/**
|
/**
|
||||||
* Construct a cross-cpu work item and send an IPI
|
* Construct a cross-cpu work item and send an IPI
|
||||||
*/
|
*/
|
||||||
_destroy.construct(*this, *to_delete);
|
_destroy.construct(*this, to_delete);
|
||||||
to_delete->_cpu->trigger_ip_interrupt();
|
to_delete->_cpu->trigger_ip_interrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -566,21 +544,19 @@ void Thread::_call_kill_signal_context()
|
||||||
|
|
||||||
void Thread::_call_new_irq()
|
void Thread::_call_new_irq()
|
||||||
{
|
{
|
||||||
Signal_context * const c = pd().cap_tree().find<Signal_context>(user_arg_3());
|
Signal_context * const c = pd().cap_tree().find<Signal_context>(user_arg_4());
|
||||||
if (!c) {
|
if (!c) {
|
||||||
Genode::raw(*this, ": invalid signal context for interrupt");
|
Genode::raw(*this, ": invalid signal context for interrupt");
|
||||||
user_arg_0(-1);
|
user_arg_0(-1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
new ((void *)user_arg_1()) User_irq(user_arg_2(), *c);
|
Genode::Irq_session::Trigger trigger =
|
||||||
user_arg_0(0);
|
(Genode::Irq_session::Trigger) (user_arg_3() & 0b1100);
|
||||||
}
|
Genode::Irq_session::Polarity polarity =
|
||||||
|
(Genode::Irq_session::Polarity) (user_arg_3() & 0b11);
|
||||||
|
|
||||||
void Thread::_call_irq_mode()
|
_call_new<User_irq>((unsigned)user_arg_2(), trigger, polarity, *c);
|
||||||
{
|
|
||||||
cpu_pool().executing_cpu().pic().irq_mode(user_arg_1(), user_arg_2(),
|
|
||||||
user_arg_3());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -601,17 +577,18 @@ void Thread::_call_new_obj()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
using Thread_identity = Core_object_identity<Thread>;
|
using Thread_identity = Genode::Constructible<Core_object_identity<Thread>>;
|
||||||
Thread_identity * coi =
|
Thread_identity & coi = *(Thread_identity*)user_arg_1();
|
||||||
Genode::construct_at<Thread_identity>((void *)user_arg_1(), *thread);
|
coi.construct(*thread);
|
||||||
user_arg_0(coi->core_capid());
|
user_arg_0(coi->core_capid());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread::_call_delete_obj()
|
void Thread::_call_delete_obj()
|
||||||
{
|
{
|
||||||
using Object = Core_object_identity<Thread>;
|
using Thread_identity = Genode::Constructible<Core_object_identity<Thread>>;
|
||||||
reinterpret_cast<Object*>(user_arg_1())->~Object();
|
Thread_identity & coi = *(Thread_identity*)user_arg_1();
|
||||||
|
coi.destruct();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -686,8 +663,14 @@ void Thread::_call()
|
||||||
}
|
}
|
||||||
/* switch over kernel calls that are restricted to core */
|
/* switch over kernel calls that are restricted to core */
|
||||||
switch (call_id) {
|
switch (call_id) {
|
||||||
case call_id_new_thread(): _call_new_thread(); return;
|
case call_id_new_thread():
|
||||||
case call_id_new_core_thread(): _call_new_core_thread(); return;
|
_call_new<Thread>((unsigned) user_arg_2(),
|
||||||
|
(unsigned) _core_to_kernel_quota(user_arg_3()),
|
||||||
|
(char const *) user_arg_4());
|
||||||
|
return;
|
||||||
|
case call_id_new_core_thread():
|
||||||
|
_call_new<Thread>((char const *) user_arg_2());
|
||||||
|
return;
|
||||||
case call_id_thread_quota(): _call_thread_quota(); return;
|
case call_id_thread_quota(): _call_thread_quota(); return;
|
||||||
case call_id_delete_thread(): _call_delete_thread(); return;
|
case call_id_delete_thread(): _call_delete_thread(); return;
|
||||||
case call_id_start_thread(): _call_start_thread(); return;
|
case call_id_start_thread(): _call_start_thread(); return;
|
||||||
|
@ -702,7 +685,7 @@ void Thread::_call()
|
||||||
case call_id_delete_pd(): _call_delete<Pd>(); return;
|
case call_id_delete_pd(): _call_delete<Pd>(); return;
|
||||||
case call_id_new_signal_receiver(): _call_new<Signal_receiver>(); return;
|
case call_id_new_signal_receiver(): _call_new<Signal_receiver>(); return;
|
||||||
case call_id_new_signal_context():
|
case call_id_new_signal_context():
|
||||||
_call_new<Signal_context>((Signal_receiver*) user_arg_2(), user_arg_3());
|
_call_new<Signal_context>(*(Signal_receiver*) user_arg_2(), user_arg_3());
|
||||||
return;
|
return;
|
||||||
case call_id_delete_signal_context(): _call_delete<Signal_context>(); return;
|
case call_id_delete_signal_context(): _call_delete<Signal_context>(); return;
|
||||||
case call_id_delete_signal_receiver(): _call_delete<Signal_receiver>(); return;
|
case call_id_delete_signal_receiver(): _call_delete<Signal_receiver>(); return;
|
||||||
|
@ -712,8 +695,7 @@ void Thread::_call()
|
||||||
case call_id_pause_vm(): _call_pause_vm(); return;
|
case call_id_pause_vm(): _call_pause_vm(); return;
|
||||||
case call_id_pause_thread(): _call_pause_thread(); return;
|
case call_id_pause_thread(): _call_pause_thread(); return;
|
||||||
case call_id_new_irq(): _call_new_irq(); return;
|
case call_id_new_irq(): _call_new_irq(); return;
|
||||||
case call_id_irq_mode(): _call_irq_mode(); return;
|
case call_id_delete_irq(): _call_delete<User_irq>(); return;
|
||||||
case call_id_delete_irq(): _call_delete<Irq>(); return;
|
|
||||||
case call_id_ack_irq(): _call_ack_irq(); return;
|
case call_id_ack_irq(): _call_ack_irq(); return;
|
||||||
case call_id_new_obj(): _call_new_obj(); return;
|
case call_id_new_obj(): _call_new_obj(); return;
|
||||||
case call_id_delete_obj(): _call_delete_obj(); return;
|
case call_id_delete_obj(): _call_delete_obj(); return;
|
||||||
|
|
|
@ -19,11 +19,11 @@
|
||||||
|
|
||||||
/* core includes */
|
/* core includes */
|
||||||
#include <cpu.h>
|
#include <cpu.h>
|
||||||
#include "cpu_context.h"
|
#include <kernel/cpu_context.h>
|
||||||
#include "inter_processor_work.h"
|
#include <kernel/inter_processor_work.h>
|
||||||
#include "signal_receiver.h"
|
#include <kernel/signal_receiver.h>
|
||||||
#include "ipc_node.h"
|
#include <kernel/ipc_node.h>
|
||||||
#include "object.h"
|
#include <object.h>
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
@ -89,10 +89,12 @@ class Kernel::Thread
|
||||||
*/
|
*/
|
||||||
struct Destroy : Inter_processor_work
|
struct Destroy : Inter_processor_work
|
||||||
{
|
{
|
||||||
Thread & caller; /* the caller gets blocked till the end */
|
using Kthread = Genode::Kernel_object<Thread>;
|
||||||
Thread & thread_to_destroy; /* thread to be destroyed */
|
|
||||||
|
|
||||||
Destroy(Thread & caller, Thread & to_destroy);
|
Thread & caller; /* the caller gets blocked till the end */
|
||||||
|
Kthread & thread_to_destroy; /* thread to be destroyed */
|
||||||
|
|
||||||
|
Destroy(Thread & caller, Kthread & to_destroy);
|
||||||
|
|
||||||
/************************************
|
/************************************
|
||||||
** Inter_processor_work interface **
|
** Inter_processor_work interface **
|
||||||
|
@ -241,18 +243,19 @@ class Kernel::Thread
|
||||||
template <typename T, typename... ARGS>
|
template <typename T, typename... ARGS>
|
||||||
void _call_new(ARGS &&... args)
|
void _call_new(ARGS &&... args)
|
||||||
{
|
{
|
||||||
using Object = Core_object<T>;
|
Genode::Kernel_object<T> & kobj =
|
||||||
void * dst = (void *)user_arg_1();
|
*(Genode::Kernel_object<T>*)user_arg_1();
|
||||||
Object * o = Genode::construct_at<Object>(dst, args...);
|
kobj.construct(args...);
|
||||||
user_arg_0(o->core_capid());
|
user_arg_0(kobj->core_capid());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void _call_delete()
|
void _call_delete()
|
||||||
{
|
{
|
||||||
using Object = Core_object<T>;
|
Genode::Kernel_object<T> & kobj =
|
||||||
reinterpret_cast<Object*>(user_arg_1())->~Object();
|
*(Genode::Kernel_object<T>*)user_arg_1();
|
||||||
|
kobj.destruct();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -317,12 +320,14 @@ class Kernel::Thread
|
||||||
void user_arg_2(Kernel::Call_arg const arg);
|
void user_arg_2(Kernel::Call_arg const arg);
|
||||||
void user_arg_3(Kernel::Call_arg const arg);
|
void user_arg_3(Kernel::Call_arg const arg);
|
||||||
void user_arg_4(Kernel::Call_arg const arg);
|
void user_arg_4(Kernel::Call_arg const arg);
|
||||||
|
void user_arg_5(Kernel::Call_arg const arg);
|
||||||
|
|
||||||
Kernel::Call_arg user_arg_0() const;
|
Kernel::Call_arg user_arg_0() const;
|
||||||
Kernel::Call_arg user_arg_1() const;
|
Kernel::Call_arg user_arg_1() const;
|
||||||
Kernel::Call_arg user_arg_2() const;
|
Kernel::Call_arg user_arg_2() const;
|
||||||
Kernel::Call_arg user_arg_3() const;
|
Kernel::Call_arg user_arg_3() const;
|
||||||
Kernel::Call_arg user_arg_4() const;
|
Kernel::Call_arg user_arg_4() const;
|
||||||
|
Kernel::Call_arg user_arg_5() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Syscall to create a thread
|
* Syscall to create a thread
|
||||||
|
@ -334,11 +339,12 @@ class Kernel::Thread
|
||||||
*
|
*
|
||||||
* \retval capability id of the new kernel object
|
* \retval capability id of the new kernel object
|
||||||
*/
|
*/
|
||||||
static capid_t syscall_create(void * const p, unsigned const priority,
|
static capid_t syscall_create(Genode::Kernel_object<Thread> & t,
|
||||||
size_t const quota,
|
unsigned const priority,
|
||||||
char const * const label)
|
size_t const quota,
|
||||||
|
char const * const label)
|
||||||
{
|
{
|
||||||
return call(call_id_new_thread(), (Call_arg)p, (Call_arg)priority,
|
return call(call_id_new_thread(), (Call_arg)&t, (Call_arg)priority,
|
||||||
(Call_arg)quota, (Call_arg)label);
|
(Call_arg)quota, (Call_arg)label);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -350,9 +356,10 @@ class Kernel::Thread
|
||||||
*
|
*
|
||||||
* \retval capability id of the new kernel object
|
* \retval capability id of the new kernel object
|
||||||
*/
|
*/
|
||||||
static capid_t syscall_create(void * const p, char const * const label)
|
static capid_t syscall_create(Genode::Kernel_object<Thread> & t,
|
||||||
|
char const * const label)
|
||||||
{
|
{
|
||||||
return call(call_id_new_core_thread(), (Call_arg)p,
|
return call(call_id_new_core_thread(), (Call_arg)&t,
|
||||||
(Call_arg)label);
|
(Call_arg)label);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -361,8 +368,8 @@ class Kernel::Thread
|
||||||
*
|
*
|
||||||
* \param thread pointer to thread kernel object
|
* \param thread pointer to thread kernel object
|
||||||
*/
|
*/
|
||||||
static void syscall_destroy(Thread * thread) {
|
static void syscall_destroy(Genode::Kernel_object<Thread> & t) {
|
||||||
call(call_id_delete_thread(), (Call_arg)thread); }
|
call(call_id_delete_thread(), (Call_arg)&t); }
|
||||||
|
|
||||||
void print(Genode::Output &out) const;
|
void print(Genode::Output &out) const;
|
||||||
|
|
||||||
|
|
|
@ -105,8 +105,6 @@ class Kernel::Timer
|
||||||
|
|
||||||
unsigned interrupt_id() const;
|
unsigned interrupt_id() const;
|
||||||
|
|
||||||
static void init_cpu_local();
|
|
||||||
|
|
||||||
time_t time() const { return _time + _duration(); }
|
time_t time() const { return _time + _duration(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,8 @@ namespace Genode { class Vm_state; }
|
||||||
#include "pd.h"
|
#include "pd.h"
|
||||||
#include "signal_receiver.h"
|
#include "signal_receiver.h"
|
||||||
|
|
||||||
|
#include <board.h>
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -36,19 +38,22 @@ class Kernel::Vm : public Cpu_job,
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
using State = Board::Vm_state;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Noncopyable
|
* Noncopyable
|
||||||
*/
|
*/
|
||||||
Vm(Vm const &);
|
Vm(Vm const &);
|
||||||
Vm &operator = (Vm const &);
|
Vm &operator = (Vm const &);
|
||||||
|
|
||||||
enum State { ACTIVE, INACTIVE };
|
enum Scheduler_state { ACTIVE, INACTIVE };
|
||||||
|
|
||||||
unsigned _id = 0;
|
unsigned _id = 0;
|
||||||
Genode::Vm_state * const _state;
|
State & _state;
|
||||||
Signal_context * const _context;
|
Signal_context & _context;
|
||||||
void * const _table;
|
void * const _table;
|
||||||
State _scheduled = INACTIVE;
|
Scheduler_state _scheduled = INACTIVE;
|
||||||
|
Board::Vcpu_context _vcpu_context;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -59,9 +64,10 @@ class Kernel::Vm : public Cpu_job,
|
||||||
* \param context signal for VM exceptions other than interrupts
|
* \param context signal for VM exceptions other than interrupts
|
||||||
* \param table translation table for guest to host physical memory
|
* \param table translation table for guest to host physical memory
|
||||||
*/
|
*/
|
||||||
Vm(void * const state,
|
Vm(unsigned cpu,
|
||||||
Signal_context * const context,
|
State & state,
|
||||||
void * const table);
|
Signal_context & context,
|
||||||
|
void * const table);
|
||||||
|
|
||||||
~Vm();
|
~Vm();
|
||||||
|
|
||||||
|
@ -84,12 +90,14 @@ class Kernel::Vm : public Cpu_job,
|
||||||
*
|
*
|
||||||
* \retval cap id when successful, otherwise invalid cap id
|
* \retval cap id when successful, otherwise invalid cap id
|
||||||
*/
|
*/
|
||||||
static capid_t syscall_create(void * const dst, void * const state,
|
static capid_t syscall_create(Genode::Kernel_object<Vm> & vm,
|
||||||
capid_t const signal_context_id,
|
unsigned cpu,
|
||||||
void * const table)
|
void * const state,
|
||||||
|
capid_t const signal_context_id,
|
||||||
|
void * const table)
|
||||||
{
|
{
|
||||||
return call(call_id_new_vm(), (Call_arg)dst, (Call_arg)state,
|
return call(call_id_new_vm(), (Call_arg)&vm, (Call_arg)cpu,
|
||||||
(Call_arg)table, signal_context_id);
|
(Call_arg)state, (Call_arg)table, signal_context_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -99,8 +107,8 @@ class Kernel::Vm : public Cpu_job,
|
||||||
*
|
*
|
||||||
* \retval 0 when successful, otherwise !=0
|
* \retval 0 when successful, otherwise !=0
|
||||||
*/
|
*/
|
||||||
static void syscall_destroy(Vm * const vm) {
|
static void syscall_destroy(Genode::Kernel_object<Vm> & vm) {
|
||||||
call(call_id_delete_vm(), (Call_arg) vm); }
|
call(call_id_delete_vm(), (Call_arg) &vm); }
|
||||||
|
|
||||||
|
|
||||||
/****************
|
/****************
|
||||||
|
|
|
@ -18,13 +18,14 @@
|
||||||
void Kernel::Thread::_call_new_vm()
|
void Kernel::Thread::_call_new_vm()
|
||||||
{
|
{
|
||||||
Signal_context * context =
|
Signal_context * context =
|
||||||
pd().cap_tree().find<Signal_context>(user_arg_4());
|
pd().cap_tree().find<Signal_context>(user_arg_5());
|
||||||
if (!context) {
|
if (!context) {
|
||||||
user_arg_0(cap_id_invalid());
|
user_arg_0(cap_id_invalid());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_call_new<Vm>((void*)user_arg_2(), context, (void*)user_arg_3());
|
_call_new<Vm>((unsigned)user_arg_2(), *(Board::Vm_state*)user_arg_3(),
|
||||||
|
*context, (void*)user_arg_4());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
#define _CORE__OBJECT_H_
|
#define _CORE__OBJECT_H_
|
||||||
|
|
||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
#include <util/construct_at.h>
|
#include <util/reconstructible.h>
|
||||||
|
|
||||||
/* base-internal includes */
|
/* base-internal includes */
|
||||||
#include <base/internal/capability_space.h>
|
#include <base/internal/capability_space.h>
|
||||||
|
@ -35,13 +35,8 @@ namespace Genode {
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class Genode::Kernel_object
|
class Genode::Kernel_object : public Genode::Constructible<Kernel::Core_object<T>>
|
||||||
{
|
{
|
||||||
private:
|
|
||||||
|
|
||||||
uint8_t _data[sizeof(Kernel::Core_object<T>)]
|
|
||||||
__attribute__((aligned(sizeof(addr_t))));
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
Untyped_capability _cap { };
|
Untyped_capability _cap { };
|
||||||
|
@ -55,15 +50,17 @@ class Genode::Kernel_object
|
||||||
*/
|
*/
|
||||||
template <typename... ARGS>
|
template <typename... ARGS>
|
||||||
Kernel_object(bool syscall, ARGS &&... args)
|
Kernel_object(bool syscall, ARGS &&... args)
|
||||||
: _cap(Capability_space::import(syscall ? T::syscall_create(&_data, args...)
|
: _cap(Capability_space::import(syscall ? T::syscall_create(*this, args...)
|
||||||
: Kernel::cap_id_invalid()))
|
: Kernel::cap_id_invalid()))
|
||||||
{
|
{
|
||||||
if (!syscall) construct_at<T>(&_data, args...);
|
if (!syscall) Genode::Constructible<Kernel::Core_object<T>>::construct(args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
~Kernel_object() { T::syscall_destroy(kernel_object()); }
|
~Kernel_object()
|
||||||
|
{
|
||||||
T * kernel_object() { return reinterpret_cast<T*>(_data); }
|
if (Genode::Constructible<Kernel::Core_object<T>>::constructed())
|
||||||
|
T::syscall_destroy(*this);
|
||||||
|
}
|
||||||
|
|
||||||
Untyped_capability cap() { return _cap; }
|
Untyped_capability cap() { return _cap; }
|
||||||
|
|
||||||
|
@ -73,8 +70,10 @@ class Genode::Kernel_object
|
||||||
template <typename... ARGS>
|
template <typename... ARGS>
|
||||||
bool create(ARGS &&... args)
|
bool create(ARGS &&... args)
|
||||||
{
|
{
|
||||||
if (_cap.valid()) return false;
|
if (Genode::Constructible<Kernel::Core_object<T>>::constructed())
|
||||||
_cap = Capability_space::import(T::syscall_create(&_data, args...));
|
return false;
|
||||||
|
|
||||||
|
_cap = Capability_space::import(T::syscall_create(*this, args...));
|
||||||
return _cap.valid();
|
return _cap.valid();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -53,12 +53,12 @@ void Pager_object::wake_up()
|
||||||
if (pt) pt->restart();
|
if (pt) pt->restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Pager_object::start_paging(Kernel::Signal_receiver * receiver)
|
void Pager_object::start_paging(Kernel_object<Kernel::Signal_receiver> & receiver)
|
||||||
{
|
{
|
||||||
using Object = Kernel_object<Kernel::Signal_context>;
|
using Object = Kernel_object<Kernel::Signal_context>;
|
||||||
using Entry = Object_pool<Pager_object>::Entry;
|
using Entry = Object_pool<Pager_object>::Entry;
|
||||||
|
|
||||||
create(receiver, (unsigned long)this);
|
create(*receiver, (unsigned long)this);
|
||||||
Entry::cap(Object::_cap);
|
Entry::cap(Object::_cap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,13 +103,13 @@ void Pager_entrypoint::dissolve(Pager_object &o)
|
||||||
|
|
||||||
Pager_entrypoint::Pager_entrypoint(Rpc_cap_factory &)
|
Pager_entrypoint::Pager_entrypoint(Rpc_cap_factory &)
|
||||||
: Thread_deprecated<PAGER_EP_STACK_SIZE>("pager_ep"),
|
: Thread_deprecated<PAGER_EP_STACK_SIZE>("pager_ep"),
|
||||||
Kernel_object<Kernel::Signal_receiver>(true)
|
_kobj(true)
|
||||||
{ start(); }
|
{ start(); }
|
||||||
|
|
||||||
|
|
||||||
Pager_capability Pager_entrypoint::manage(Pager_object &o)
|
Pager_capability Pager_entrypoint::manage(Pager_object &o)
|
||||||
{
|
{
|
||||||
o.start_paging(kernel_object());
|
o.start_paging(_kobj);
|
||||||
insert(&o);
|
insert(&o);
|
||||||
return reinterpret_cap_cast<Pager_object>(o.cap());
|
return reinterpret_cap_cast<Pager_object>(o.cap());
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,26 +69,29 @@ void Hw::Address_space::flush(addr_t virt, size_t size, Core_local_addr)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
_tt.remove_translation(virt, size, _tt_alloc);
|
_tt.remove_translation(virt, size, _tt_alloc);
|
||||||
Kernel::invalidate_tlb(&_kernel_pd, virt, size);
|
Kernel::invalidate_tlb(*_kobj, virt, size);
|
||||||
} catch(...) {
|
} catch(...) {
|
||||||
error("tried to remove invalid region!");
|
error("tried to remove invalid region!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Hw::Address_space::Address_space(Kernel::Pd & pd, Page_table & tt,
|
Hw::Address_space::Address_space(Page_table & tt,
|
||||||
Page_table::Allocator & tt_alloc)
|
Page_table::Allocator & tt_alloc,
|
||||||
: _tt(tt), _tt_phys(Platform::core_page_table()),
|
Platform_pd & pd)
|
||||||
_tt_alloc(tt_alloc), _kernel_pd(pd) { }
|
: _tt(tt),
|
||||||
|
_tt_phys(Platform::core_page_table()),
|
||||||
|
_tt_alloc(tt_alloc),
|
||||||
|
_kobj(false, *(Page_table*)translation_table_phys(), pd) {}
|
||||||
|
|
||||||
|
|
||||||
Hw::Address_space::Address_space(Kernel::Pd & pd)
|
Hw::Address_space::Address_space(Platform_pd & pd)
|
||||||
: _tt(*construct_at<Page_table>(_table_alloc(), *((Page_table*)Hw::Mm::core_page_tables().base))),
|
: _tt(*construct_at<Page_table>(_table_alloc(), *((Page_table*)Hw::Mm::core_page_tables().base))),
|
||||||
_tt_phys((addr_t)_cma().phys_addr(&_tt)),
|
_tt_phys((addr_t)_cma().phys_addr(&_tt)),
|
||||||
_tt_array(new (_cma()) Array([] (void * virt) {
|
_tt_array(new (_cma()) Array([] (void * virt) {
|
||||||
return (addr_t)_cma().phys_addr(virt);})),
|
return (addr_t)_cma().phys_addr(virt);})),
|
||||||
_tt_alloc(_tt_array->alloc()),
|
_tt_alloc(_tt_array->alloc()),
|
||||||
_kernel_pd(pd) { }
|
_kobj(true, *(Page_table*)translation_table_phys(), pd) { }
|
||||||
|
|
||||||
|
|
||||||
Hw::Address_space::~Address_space()
|
Hw::Address_space::~Address_space()
|
||||||
|
@ -142,20 +145,13 @@ void Platform_pd::assign_parent(Native_capability parent)
|
||||||
|
|
||||||
Platform_pd::Platform_pd(Page_table & tt,
|
Platform_pd::Platform_pd(Page_table & tt,
|
||||||
Page_table::Allocator & alloc)
|
Page_table::Allocator & alloc)
|
||||||
:
|
: Hw::Address_space(tt, alloc, *this), _label("core") { }
|
||||||
Hw::Address_space(*kernel_object(), tt, alloc),
|
|
||||||
Kernel_object<Kernel::Pd>(false, *(Page_table*)translation_table_phys(), *this),
|
|
||||||
_label("core")
|
|
||||||
{ }
|
|
||||||
|
|
||||||
|
|
||||||
Platform_pd::Platform_pd(Allocator &, char const *label)
|
Platform_pd::Platform_pd(Allocator &, char const *label)
|
||||||
:
|
: Hw::Address_space(*this), _label(label)
|
||||||
Hw::Address_space(*kernel_object()),
|
|
||||||
Kernel_object<Kernel::Pd>(true, *(Page_table*)translation_table_phys(), *this),
|
|
||||||
_label(label)
|
|
||||||
{
|
{
|
||||||
if (!_cap.valid()) {
|
if (!_kobj.cap().valid()) {
|
||||||
error("failed to create kernel object");
|
error("failed to create kernel object");
|
||||||
throw Service_denied();
|
throw Service_denied();
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ Platform_thread::~Platform_thread()
|
||||||
void Platform_thread::quota(size_t const quota)
|
void Platform_thread::quota(size_t const quota)
|
||||||
{
|
{
|
||||||
_quota = quota;
|
_quota = quota;
|
||||||
Kernel::thread_quota(_kobj.kernel_object(), quota);
|
Kernel::thread_quota(*_kobj, quota);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -158,8 +158,8 @@ int Platform_thread::start(void * const ip, void * const sp)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* initialize thread registers */
|
/* initialize thread registers */
|
||||||
_kobj.kernel_object()->regs->ip = reinterpret_cast<addr_t>(ip);
|
_kobj->regs->ip = reinterpret_cast<addr_t>(ip);
|
||||||
_kobj.kernel_object()->regs->sp = reinterpret_cast<addr_t>(sp);
|
_kobj->regs->sp = reinterpret_cast<addr_t>(sp);
|
||||||
|
|
||||||
/* start executing new thread */
|
/* start executing new thread */
|
||||||
if (!_pd) {
|
if (!_pd) {
|
||||||
|
@ -179,8 +179,7 @@ int Platform_thread::start(void * const ip, void * const sp)
|
||||||
utcb.cap_add(Capability_space::capid(_pd->parent()));
|
utcb.cap_add(Capability_space::capid(_pd->parent()));
|
||||||
utcb.cap_add(Capability_space::capid(_utcb));
|
utcb.cap_add(Capability_space::capid(_utcb));
|
||||||
}
|
}
|
||||||
Kernel::start_thread(_kobj.kernel_object(), cpu, &_pd->kernel_pd(),
|
Kernel::start_thread(*_kobj, cpu, _pd->kernel_pd(), *_utcb_core_addr);
|
||||||
_utcb_core_addr);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,7 +188,7 @@ void Platform_thread::pager(Pager_object &pager)
|
||||||
{
|
{
|
||||||
using namespace Kernel;
|
using namespace Kernel;
|
||||||
|
|
||||||
thread_pager(_kobj.kernel_object(), Capability_space::capid(pager.cap()));
|
thread_pager(*_kobj, Capability_space::capid(pager.cap()));
|
||||||
_pager = &pager;
|
_pager = &pager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,14 +204,14 @@ Genode::Pager_object &Platform_thread::pager()
|
||||||
|
|
||||||
Thread_state Platform_thread::state()
|
Thread_state Platform_thread::state()
|
||||||
{
|
{
|
||||||
Thread_state bstate(*_kobj.kernel_object()->regs);
|
Thread_state bstate(*_kobj->regs);
|
||||||
return Thread_state(bstate);
|
return Thread_state(bstate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Platform_thread::state(Thread_state thread_state)
|
void Platform_thread::state(Thread_state thread_state)
|
||||||
{
|
{
|
||||||
Cpu_state * cstate = static_cast<Cpu_state *>(&*_kobj.kernel_object()->regs);
|
Cpu_state * cstate = static_cast<Cpu_state *>(&*_kobj->regs);
|
||||||
*cstate = static_cast<Cpu_state>(thread_state);
|
*cstate = static_cast<Cpu_state>(thread_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ void Pager_entrypoint::entry()
|
||||||
if (cap.valid()) Kernel::ack_signal(Capability_space::capid(cap));
|
if (cap.valid()) Kernel::ack_signal(Capability_space::capid(cap));
|
||||||
|
|
||||||
/* receive fault */
|
/* receive fault */
|
||||||
if (Kernel::await_signal(Capability_space::capid(_cap))) continue;
|
if (Kernel::await_signal(Capability_space::capid(_kobj.cap()))) continue;
|
||||||
|
|
||||||
Pager_object *po = *(Pager_object**)Thread::myself()->utcb()->data();
|
Pager_object *po = *(Pager_object**)Thread::myself()->utcb()->data();
|
||||||
cap = po->cap();
|
cap = po->cap();
|
||||||
|
|
|
@ -55,19 +55,21 @@ struct Genode::Signal_source_component : private Kernel_object<Kernel::Signal_re
|
||||||
using Signal_source_pool::Entry::cap;
|
using Signal_source_pool::Entry::cap;
|
||||||
|
|
||||||
Signal_source_component()
|
Signal_source_component()
|
||||||
:
|
: Kernel_object<Kernel::Signal_receiver>(true),
|
||||||
Kernel_object<Kernel::Signal_receiver>(true),
|
Signal_source_pool::Entry(Kernel_object<Kernel::Signal_receiver>::cap())
|
||||||
Signal_source_pool::Entry(Kernel_object<Kernel::Signal_receiver>::_cap)
|
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void submit(Signal_context_component *, unsigned long) { ASSERT_NEVER_CALLED; }
|
void submit(Signal_context_component *, unsigned long) { ASSERT_NEVER_CALLED; }
|
||||||
|
|
||||||
|
Kernel::Signal_receiver & signal_receiver() {
|
||||||
|
return **static_cast<Kernel_object<Kernel::Signal_receiver>*>(this); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Genode::Signal_context_component::Signal_context_component(Signal_source_component &s,
|
Genode::Signal_context_component::Signal_context_component(Signal_source_component &s,
|
||||||
addr_t const imprint)
|
addr_t const imprint)
|
||||||
:
|
:
|
||||||
Kernel_object<Kernel::Signal_context>(true, s.kernel_object(), imprint),
|
Kernel_object<Kernel::Signal_context>(true, s.signal_receiver(), imprint),
|
||||||
Signal_context_pool::Entry(Kernel_object<Kernel::Signal_context>::_cap)
|
Signal_context_pool::Entry(Kernel_object<Kernel::Signal_context>::_cap)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <board.h>
|
#include <board.h>
|
||||||
|
#include <cpu.h>
|
||||||
#include <platform.h>
|
#include <platform.h>
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,41 +22,109 @@ Board::Pic::Pic()
|
||||||
|
|
||||||
bool Board::Pic::take_request(unsigned & irq)
|
bool Board::Pic::take_request(unsigned & irq)
|
||||||
{
|
{
|
||||||
Core0_irq_source::access_t src = read<Core0_irq_source>();
|
unsigned cpu = Genode::Cpu::executing_id();
|
||||||
|
Core_irq_source<0>::access_t src = 0;
|
||||||
|
switch (cpu) {
|
||||||
|
case 0: src = read<Core_irq_source<0>>(); break;
|
||||||
|
case 1: src = read<Core_irq_source<1>>(); break;
|
||||||
|
case 2: src = read<Core_irq_source<2>>(); break;
|
||||||
|
case 3: src = read<Core_irq_source<3>>(); break;
|
||||||
|
}
|
||||||
|
|
||||||
if ((1 << TIMER_IRQ) & src) {
|
if ((1 << TIMER_IRQ) & src) {
|
||||||
irq = TIMER_IRQ;
|
irq = TIMER_IRQ;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (0xf0 & src) {
|
||||||
|
irq = IPI;
|
||||||
|
switch (cpu) {
|
||||||
|
case 0: write<Core_mailbox_clear<0>>(1); break;
|
||||||
|
case 1: write<Core_mailbox_clear<1>>(1); break;
|
||||||
|
case 2: write<Core_mailbox_clear<2>>(1); break;
|
||||||
|
case 3: write<Core_mailbox_clear<3>>(1); break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Board::Pic::mask() { }
|
void Board::Pic::_timer_irq(unsigned cpu, bool enable)
|
||||||
|
{
|
||||||
|
unsigned v = enable ? 1 : 0;
|
||||||
|
switch (cpu) {
|
||||||
|
case 0:
|
||||||
|
write<Core_timer_irq_control<0>::Cnt_p_ns_irq>(v);
|
||||||
|
return;
|
||||||
|
case 1:
|
||||||
|
write<Core_timer_irq_control<1>::Cnt_p_ns_irq>(v);
|
||||||
|
return;
|
||||||
|
case 2:
|
||||||
|
write<Core_timer_irq_control<2>::Cnt_p_ns_irq>(v);
|
||||||
|
return;
|
||||||
|
case 3:
|
||||||
|
write<Core_timer_irq_control<3>::Cnt_p_ns_irq>(v);
|
||||||
|
return;
|
||||||
|
default: ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Board::Pic::_ipi(unsigned cpu, bool enable)
|
||||||
|
{
|
||||||
|
unsigned v = enable ? 1 : 0;
|
||||||
|
switch (cpu) {
|
||||||
|
case 0:
|
||||||
|
write<Core_mailbox_irq_control<0>>(v);
|
||||||
|
return;
|
||||||
|
case 1:
|
||||||
|
write<Core_mailbox_irq_control<1>>(v);
|
||||||
|
return;
|
||||||
|
case 2:
|
||||||
|
write<Core_mailbox_irq_control<2>>(v);
|
||||||
|
return;
|
||||||
|
case 3:
|
||||||
|
write<Core_mailbox_irq_control<3>>(v);
|
||||||
|
return;
|
||||||
|
default: ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Board::Pic::unmask(unsigned const i, unsigned cpu)
|
void Board::Pic::unmask(unsigned const i, unsigned cpu)
|
||||||
{
|
{
|
||||||
if (cpu > 0)
|
switch (i) {
|
||||||
Genode::raw("multi-core irq controller not implemented yet");
|
case TIMER_IRQ: _timer_irq(cpu, true); return;
|
||||||
|
case IPI: _ipi(cpu, true); return;
|
||||||
if (i == TIMER_IRQ) {
|
|
||||||
write<Core0_timer_irq_control::Cnt_p_ns_irq>(1);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Genode::raw("irq of peripherals != timer not implemented yet!");
|
Genode::raw("irq of peripherals != timer not implemented yet! (irq=", i, ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Board::Pic::mask(unsigned const i)
|
void Board::Pic::mask(unsigned const i)
|
||||||
{
|
{
|
||||||
if (i == TIMER_IRQ) {
|
unsigned cpu = Genode::Cpu::executing_id();
|
||||||
write<Core0_timer_irq_control::Cnt_p_ns_irq>(0);
|
switch (i) {
|
||||||
return;
|
case TIMER_IRQ: _timer_irq(cpu, false); return;
|
||||||
|
case IPI: _ipi(cpu, false); return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Genode::raw("irq of peripherals != timer not implemented yet!");
|
Genode::raw("irq of peripherals != timer not implemented yet! (irq=", i, ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Board::Pic::irq_mode(unsigned, unsigned, unsigned) { }
|
void Board::Pic::irq_mode(unsigned, unsigned, unsigned) { }
|
||||||
|
|
||||||
|
|
||||||
|
void Board::Pic::send_ipi(unsigned cpu_target)
|
||||||
|
{
|
||||||
|
switch (cpu_target) {
|
||||||
|
case 0: write<Core_mailbox_set<0>>(1); return;
|
||||||
|
case 1: write<Core_mailbox_set<1>>(1); return;
|
||||||
|
case 2: write<Core_mailbox_set<2>>(1); return;
|
||||||
|
case 3: write<Core_mailbox_set<3>>(1); return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -23,43 +23,45 @@ class Board::Pic : Genode::Mmio
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
IPI = 0,
|
||||||
NR_OF_IRQ = 64,
|
NR_OF_IRQ = 64,
|
||||||
|
|
||||||
/*
|
|
||||||
* dummy IPI value on non-SMP platform,
|
|
||||||
* only used in interrupt reservation within generic code
|
|
||||||
*/
|
|
||||||
IPI,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
||||||
struct Core0_timer_irq_control : Register<0x40, 32>
|
template <unsigned CPU_NUM>
|
||||||
|
struct Core_timer_irq_control : Register<0x40+CPU_NUM*0x4, 32>
|
||||||
{
|
{
|
||||||
struct Cnt_p_ns_irq : Bitfield<1, 1> {};
|
struct Cnt_p_ns_irq
|
||||||
|
: Register<0x40+CPU_NUM*0x4, 32>::template Bitfield<1, 1> {};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Core1_timer_irq_control : Register<0x44, 32> {};
|
template <unsigned CPU_NUM>
|
||||||
struct Core2_timer_irq_control : Register<0x48, 32> {};
|
struct Core_mailbox_irq_control : Register<0x50+CPU_NUM*0x4, 32> {};
|
||||||
struct Core3_timer_irq_control : Register<0x4c, 32> {};
|
|
||||||
|
|
||||||
struct Core0_irq_source : Register<0x60, 32> {};
|
template <unsigned CPU_NUM>
|
||||||
struct Core1_irq_source : Register<0x64, 32> {};
|
struct Core_irq_source : Register<0x60+CPU_NUM*0x4, 32> {};
|
||||||
struct Core2_irq_source : Register<0x68, 32> {};
|
|
||||||
struct Core3_irq_source : Register<0x6c, 32> {};
|
template <unsigned CPU_NUM>
|
||||||
|
struct Core_mailbox_set : Register<0x80+CPU_NUM*0x10, 32> {};
|
||||||
|
|
||||||
|
template <unsigned CPU_NUM>
|
||||||
|
struct Core_mailbox_clear : Register<0xc0+CPU_NUM*0x10, 32> {};
|
||||||
|
|
||||||
|
void _ipi(unsigned cpu, bool enable);
|
||||||
|
void _timer_irq(unsigned cpu, bool enable);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Pic();
|
Pic();
|
||||||
|
|
||||||
void init_cpu_local();
|
|
||||||
bool take_request(unsigned &irq);
|
bool take_request(unsigned &irq);
|
||||||
void finish_request() { }
|
void finish_request() { }
|
||||||
void mask();
|
|
||||||
void unmask(unsigned const i, unsigned);
|
void unmask(unsigned const i, unsigned);
|
||||||
void mask(unsigned const i);
|
void mask(unsigned const i);
|
||||||
void irq_mode(unsigned, unsigned, unsigned);
|
void irq_mode(unsigned, unsigned, unsigned);
|
||||||
|
void send_ipi(unsigned);
|
||||||
|
|
||||||
static constexpr bool fast_interrupts() { return false; }
|
static constexpr bool fast_interrupts() { return false; }
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,11 +17,16 @@
|
||||||
|
|
||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
|
|
||||||
|
static inline Genode::addr_t redistributor_addr()
|
||||||
|
{
|
||||||
|
return Platform::mmio_to_virt(Board::Cpu_mmio::IRQ_CONTROLLER_REDIST_BASE
|
||||||
|
+ (Cpu::executing_id() * 0x20000));
|
||||||
|
};
|
||||||
|
|
||||||
Hw::Pic::Pic()
|
Hw::Pic::Pic()
|
||||||
: _distr(Platform::mmio_to_virt(Board::Cpu_mmio::IRQ_CONTROLLER_DISTR_BASE)),
|
: _distr(Platform::mmio_to_virt(Board::Cpu_mmio::IRQ_CONTROLLER_DISTR_BASE)),
|
||||||
_redistr(Platform::mmio_to_virt(Board::Cpu_mmio::IRQ_CONTROLLER_REDIST_BASE)),
|
_redistr(redistributor_addr()),
|
||||||
_redistr_sgi(Platform::mmio_to_virt(Board::Cpu_mmio::IRQ_CONTROLLER_REDIST_BASE)
|
_redistr_sgi(redistributor_addr() + 0x10000),
|
||||||
+ Board::Cpu_mmio::IRQ_CONTROLLER_REDIST_SIZE / 2),
|
|
||||||
_max_irq(_distr.max_irq())
|
_max_irq(_distr.max_irq())
|
||||||
{
|
{
|
||||||
_redistributor_init();
|
_redistributor_init();
|
||||||
|
|
|
@ -104,9 +104,11 @@ void Thread::user_arg_1(Kernel::Call_arg const arg) { regs->r1 = arg; }
|
||||||
void Thread::user_arg_2(Kernel::Call_arg const arg) { regs->r2 = arg; }
|
void Thread::user_arg_2(Kernel::Call_arg const arg) { regs->r2 = arg; }
|
||||||
void Thread::user_arg_3(Kernel::Call_arg const arg) { regs->r3 = arg; }
|
void Thread::user_arg_3(Kernel::Call_arg const arg) { regs->r3 = arg; }
|
||||||
void Thread::user_arg_4(Kernel::Call_arg const arg) { regs->r4 = arg; }
|
void Thread::user_arg_4(Kernel::Call_arg const arg) { regs->r4 = arg; }
|
||||||
|
void Thread::user_arg_5(Kernel::Call_arg const arg) { regs->r5 = arg; }
|
||||||
|
|
||||||
Kernel::Call_arg Thread::user_arg_0() const { return regs->r0; }
|
Kernel::Call_arg Thread::user_arg_0() const { return regs->r0; }
|
||||||
Kernel::Call_arg Thread::user_arg_1() const { return regs->r1; }
|
Kernel::Call_arg Thread::user_arg_1() const { return regs->r1; }
|
||||||
Kernel::Call_arg Thread::user_arg_2() const { return regs->r2; }
|
Kernel::Call_arg Thread::user_arg_2() const { return regs->r2; }
|
||||||
Kernel::Call_arg Thread::user_arg_3() const { return regs->r3; }
|
Kernel::Call_arg Thread::user_arg_3() const { return regs->r3; }
|
||||||
Kernel::Call_arg Thread::user_arg_4() const { return regs->r4; }
|
Kernel::Call_arg Thread::user_arg_4() const { return regs->r4; }
|
||||||
|
Kernel::Call_arg Thread::user_arg_5() const { return regs->r5; }
|
||||||
|
|
33
repos/base-hw/src/core/spec/arm/trustzone_board.h
Normal file
33
repos/base-hw/src/core/spec/arm/trustzone_board.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* \brief Board driver
|
||||||
|
* \author Stefan Kalkowski
|
||||||
|
* \date 2019-11-11
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2019 Genode Labs GmbH
|
||||||
|
*
|
||||||
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _CORE__SPEC__ARM_TRUSTZONE_BOARD_H_
|
||||||
|
#define _CORE__SPEC__ARM_TRUSTZONE_BOARD_H_
|
||||||
|
|
||||||
|
#include <spec/arm/cpu/vm_state_trustzone.h>
|
||||||
|
|
||||||
|
namespace Kernel { class Cpu; }
|
||||||
|
|
||||||
|
namespace Board {
|
||||||
|
using Genode::Vm_state;
|
||||||
|
|
||||||
|
enum { VCPU_MAX = 1 };
|
||||||
|
|
||||||
|
struct Vm_page_table {};
|
||||||
|
struct Vm_page_table_array {};
|
||||||
|
|
||||||
|
struct Pic : Hw::Pic { struct Virtual_context {}; };
|
||||||
|
struct Vcpu_context { Vcpu_context(Kernel::Cpu &) {} };
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _CORE__SPEC__ARM_TRUSTZONE_BOARD_H_ */
|
62
repos/base-hw/src/core/spec/arm/virtualization/gicv2.cc
Normal file
62
repos/base-hw/src/core/spec/arm/virtualization/gicv2.cc
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* \brief Gicv2 with virtualization extensions
|
||||||
|
* \author Stefan Kalkowski
|
||||||
|
* \date 2019-09-02
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2019 Genode Labs GmbH
|
||||||
|
*
|
||||||
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <util/mmio.h>
|
||||||
|
|
||||||
|
#include <platform.h>
|
||||||
|
#include <spec/arm/virtualization/gicv2.h>
|
||||||
|
|
||||||
|
using Board::Pic;
|
||||||
|
|
||||||
|
Pic::Gich::Gich()
|
||||||
|
: Genode::Mmio(Genode::Platform::mmio_to_virt(Board::Cpu_mmio::IRQ_CONTROLLER_VT_CTRL_BASE)) { }
|
||||||
|
|
||||||
|
|
||||||
|
bool Pic::ack_virtual_irq(Pic::Virtual_context & c)
|
||||||
|
{
|
||||||
|
c.misr = _gich.read<Gich::Gich_misr >();
|
||||||
|
c.vmcr = _gich.read<Gich::Gich_vmcr >();
|
||||||
|
c.apr = _gich.read<Gich::Gich_apr >();
|
||||||
|
c.eisr = _gich.read<Gich::Gich_eisr0 >();
|
||||||
|
c.elrsr = _gich.read<Gich::Gich_elrsr0>();
|
||||||
|
c.lr = _gich.read<Gich::Gich_lr0 >();
|
||||||
|
_gich.write<Gich::Gich_hcr>(0);
|
||||||
|
|
||||||
|
if (c.eisr & 1) {
|
||||||
|
c.lr = 0;
|
||||||
|
c.elrsr = 0xffffffff;
|
||||||
|
c.misr = 0;
|
||||||
|
c.eisr = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Pic::insert_virtual_irq(Pic::Virtual_context & c, unsigned irq)
|
||||||
|
{
|
||||||
|
enum { SPURIOUS = 1023 };
|
||||||
|
|
||||||
|
if (irq != SPURIOUS && !c.lr) {
|
||||||
|
c.elrsr &= 0x7ffffffe;
|
||||||
|
c.lr = irq | 1 << 28 | 1 << 19;
|
||||||
|
}
|
||||||
|
|
||||||
|
_gich.write<Gich::Gich_misr >(c.misr);
|
||||||
|
_gich.write<Gich::Gich_vmcr >(c.vmcr);
|
||||||
|
_gich.write<Gich::Gich_apr >(c.apr);
|
||||||
|
_gich.write<Gich::Gich_elrsr0>(c.elrsr);
|
||||||
|
_gich.write<Gich::Gich_lr0 >(c.lr);
|
||||||
|
_gich.write<Gich::Gich_hcr>(0b1);
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user