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:
Ehmry - 2019-11-28 13:21:13 +01:00
commit 3d68a520cb
1061 changed files with 21944 additions and 18227 deletions

View File

@ -1 +1 @@
19.08
19.11

View File

@ -391,6 +391,22 @@ Platforms
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
#############

View File

@ -3,6 +3,54 @@
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
##############################################

View File

@ -143,8 +143,8 @@ corresponds to Shift, '<mod2>' to Control, '<mod3>' to AltGr, and '<mod4>' to
Caps Lock.
! <mod1> <key name="KEY_LEFTSHIFT"/> <key name="KEY_RIGHTSHIFT"/> </mod1>
! <mod2> <key name="KEY_LEFTCTRL"/> <key name="KEY_RIGHTCTRL"/> </mod4>
! <mod3> <key name="KEY_RIGHTALT"/> </mod4> <!-- AltGr -->
! <mod2> <key name="KEY_LEFTCTRL"/> <key name="KEY_RIGHTCTRL"/> </mod2>
! <mod3> <key name="KEY_RIGHTALT"/> </mod3> <!-- AltGr -->
! <mod4> <rom name="capslock"/> </mod4>
As outlined above, the '<key>' nodes generated by xkb2ifcfg always use the

815
doc/release_notes-19-11.txt Normal file
View 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.

View File

@ -1 +1 @@
2019-09-19 b0d371ca01b27c5b09fd55732681ab9e2cede5d5
2019-11-25 c7e2a3eca5820b2304b4520d0fc831ede73691f2

View File

@ -1 +1 @@
2019-09-19 59410c274229c50f68d0fd65d52cc730a4b0f55b
2019-11-25 9a459c4fd8a907810d91041751affcf3e119fcb1

View File

@ -1 +1 @@
2019-09-19 30eff00614afebb83d4be10a61d8d0f3b3fa8c33
2019-11-25 d8ff4913b8aa117aef77a7918bc82808e38a4ee7

View File

@ -1 +1 @@
2019-09-19 e2ce197e4ed2239ed2688c8bab5ea98f5e87d439
2019-11-25 a750c8988106d5c26e46dcceb1f76bfd7bfa1457

View File

@ -1 +1 @@
2019-09-19 d3481851efe9091caf413496883a03875a298b90
2019-11-25 0c0a26b6ddb0ee5261f0be30f229e9ce04b61eda

View File

@ -1 +1 @@
2019-09-19 c842719c606b0ec3eed05255761665737cecf208
2019-11-25 bce6f0a8f1f46f8edf62ef2180dbfc949123432d

View File

@ -1 +1 @@
2019-09-19 d3bf4e77c5f352efcf384b57be11668d6047ecf3
2019-11-25 307d01e531dbbcd672463a4ea090f40bb399cae8

View File

@ -108,7 +108,7 @@ class Genode::Vm_session_component
void attach(Dataspace_capability, addr_t, Attach_attr) override;
void attach_pic(addr_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_ */

View File

@ -107,10 +107,12 @@ Vcpu::~Vcpu()
_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())
return;
return ret;
auto lambda = [&] (Cpu_thread_component *thread) {
if (!thread)
@ -146,10 +148,11 @@ void Vm_session_component::_create_vcpu(Thread_capability cap)
}
_vcpus.insert(vcpu);
_id_alloc++;
ret.id = _id_alloc++;
};
_ep.apply(cap, lambda);
return ret;
}
Dataspace_capability Vm_session_component::_cpu_state(Vcpu_id const vcpu_id)

View File

@ -50,7 +50,6 @@ static bool svm_np() { return svm_features() & (1U << 0); }
struct Vcpu;
static Genode::Registry<Genode::Registered<Vcpu> > vcpus;
static unsigned vcpu_id = 0;
struct Vcpu : Genode::Thread
{
@ -202,7 +201,7 @@ struct Vcpu : Genode::Thread
Semaphore _wake_up { 0 };
Semaphore &_handler_ready;
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 _task { 0 };
enum Virt const _vm_type;
@ -1184,20 +1183,20 @@ struct Vcpu : Genode::Thread
public:
Vcpu(Env &env, Signal_context_capability &cap,
Semaphore &handler_ready,
Vm_session_client::Vcpu_id &id, enum Virt type,
Semaphore &handler_ready, enum Virt type,
Allocator &alloc, Affinity::Location location)
:
Thread(env, "vcpu_thread", STACK_SIZE, location, Weight(), env.cpu()),
_signal(cap), _handler_ready(handler_ready), _alloc(alloc),
_id(id), _vm_type(type)
_vm_type(type)
{ }
Allocator &allocator() const { return _alloc; }
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)
{
@ -1266,12 +1265,10 @@ Vm_session_client::Vcpu_id
Vm_session_client::create_vcpu(Allocator &alloc, Env &env,
Vm_handler_base &handler)
{
Vm_session_client::Vcpu_id id = { vcpu_id };
enum Virt vm_type = virt_type(env);
if (vm_type == Virt::UNKNOWN) {
Genode::error("unsupported hardware virtualisation");
return id;
return Vm_session::Vcpu_id();
}
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 */
Vcpu * vcpu = new (alloc) Registered<Vcpu>(vcpus, env, handler._cap,
handler._done, id, vm_type,
handler._done, vm_type,
alloc, location);
try {
/* now it gets actually valid - vcpu->cap() becomes valid */
vcpu->start();
call<Rpc_exception_handler>(handler._cap, vcpu->id());
/* 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()));
} catch (...) {
@ -1299,9 +1296,7 @@ Vm_session_client::create_vcpu(Allocator &alloc, Env &env,
destroy(alloc, vcpu);
throw;
}
vcpu_id ++;
return id;
return vcpu->id();
}
void Vm_session_client::run(Vcpu_id vcpu_id)

View 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_ */

View File

@ -17,6 +17,7 @@ SRC_CC += lib/base/heap.cc
SRC_CC += lib/base/registry.cc
SRC_CC += lib/base/log.cc
SRC_CC += lib/base/output.cc
SRC_CC += lib/base/raw_output.cc
SRC_CC += lib/base/slab.cc
SRC_CC += lib/base/sleep.cc
SRC_CC += lib/base/sliced_heap.cc

View File

@ -6,16 +6,16 @@
# add include paths
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
SRC_CC += kernel/vm_thread_on.cc
SRC_CC += spec/arm/gicv2.cc
SRC_CC += spec/arm_v7/virtualization/kernel/vm.cc
SRC_CC += spec/arm_v7/virtualization/platform_services.cc
SRC_CC += spec/arm_v7/virtualization/vm_session_component.cc
SRC_CC += spec/arm_v7/vm_session_component.cc
SRC_CC += spec/arm/virtualization/platform_services.cc
SRC_CC += spec/arm/virtualization/vm_session_component.cc
SRC_CC += vm_session_common.cc
SRC_CC += vm_session_component.cc
# add assembly sources
SRC_S += spec/arm_v7/virtualization/exception_vector.s

View File

@ -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/platform_services.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

View File

@ -6,17 +6,18 @@
# add include paths
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
SRC_CC += kernel/vm_thread_on.cc
SRC_CC += spec/arm/generic_timer.cc
SRC_CC += spec/arm/gicv2.cc
SRC_CC += spec/arm_v7/virtualization/kernel/vm.cc
SRC_CC += spec/arm_v7/virtualization/platform_services.cc
SRC_CC += spec/arm_v7/virtualization/vm_session_component.cc
SRC_CC += spec/arm_v7/vm_session_component.cc
SRC_CC += spec/arm/virtualization/gicv2.cc
SRC_CC += spec/arm/virtualization/platform_services.cc
SRC_CC += spec/arm/virtualization/vm_session_component.cc
SRC_CC += vm_session_common.cc
SRC_CC += vm_session_component.cc
# add assembly sources
SRC_S += spec/arm_v7/virtualization/exception_vector.s

View File

@ -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/platform_services.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
SRC_S += spec/arm_v7/trustzone/exception_vector.s

View File

@ -7,6 +7,8 @@ SRC_CC += lib/base/arm_64/kernel/interface.cc
SRC_CC += spec/64bit/memory_map.cc
SRC_S += bootstrap/spec/arm_64/crt0.s
NR_OF_CPUS = 4
vpath spec/64bit/memory_map.cc $(BASE_DIR)/../base-hw/src/lib/hw
include $(BASE_DIR)/../base-hw/lib/mk/bootstrap-hw.inc

View File

@ -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
NR_OF_CPUS = 4
include $(BASE_DIR)/../base-hw/lib/mk/bootstrap-hw.inc

View File

@ -1,24 +1,32 @@
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/virtualization
# add C++ sources
SRC_CC += kernel/cpu_up.cc
SRC_CC += kernel/lock.cc
SRC_CC += kernel/vm_thread_off.cc
SRC_CC += platform_services.cc
SRC_CC += kernel/cpu_mp.cc
SRC_CC += kernel/vm_thread_on.cc
SRC_CC += spec/64bit/memory_map.cc
SRC_CC += spec/arm/generic_timer.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_v8/cpu.cc
SRC_CC += spec/arm_v8/kernel/cpu.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
SRC_S += spec/arm_v8/exception_vector.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
NR_OF_CPUS = 4
# include less specific configuration
include $(REP_DIR)/lib/mk/core-hw.inc

View File

@ -2,17 +2,17 @@ INC_DIR += $(REP_DIR)/src/core/spec/rpi3
INC_DIR += $(REP_DIR)/src/core/spec/arm_v8
# add C++ sources
SRC_CC += platform_services.cc
SRC_CC += kernel/cpu_mp.cc
SRC_CC += kernel/vm_thread_off.cc
SRC_CC += kernel/cpu_up.cc
SRC_CC += kernel/lock.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 += platform_services.cc
SRC_CC += spec/64bit/memory_map.cc
SRC_CC += spec/arm/bcm2837_pic.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
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
NR_OF_CPUS = 4
# include less specific configuration
include $(REP_DIR)/lib/mk/core-hw.inc

View File

@ -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/sinfo_instance.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 += vm_session_common.cc
SRC_CC += vm_session_component.cc
SRC_CC += spec/64bit/memory_map.cc

View File

@ -1 +1 @@
2019-07-08 abc6d82ca4a240319850c788f29cde2655eab1d1
2019-11-25 6593319a4dec74af9dc15554139e4343ef4312a9

View File

@ -1 +1 @@
2019-09-19 1c57558662fd8474e71ac732af797c3585322017
2019-11-25 c60d834ce54a46a946c36249784e734e06274d97

View File

@ -1 +1 @@
2019-09-19 47d633f15a78dba4ce4a0ece9fd301ec59476d18
2019-11-25 e9232754efd81c14aa65d4852d276852f591f3e5

View File

@ -1 +1 @@
2019-09-19 a922228b96330109da7ddb61450a385ef485a93b
2019-11-25 2ab0250606cee0da4f08ac08f7f33c743f32c88c

View File

@ -1 +1 @@
2019-09-19 d4514d968b7e55b42247e0231ad95bd77e92d253
2019-11-25 7780e0570ac0277d678dee76a579a9d9f9a1a776

View File

@ -1 +1 @@
2019-09-19 742a48fd23606d2b6763b2f4f2ae4a199e3d6e56
2019-11-25 2dee497b7892f706236fdbfabae53bbd4e62463b

View File

@ -1 +1 @@
2019-09-19 16b8071d8d3eee712181720ddf018c26e72f0f56
2019-11-25 efd164d66086a998484d7413c5416e3aa128e560

View File

@ -1 +1 @@
2019-09-19 b1342fe0f4a662c502b296b11d2524d64d2a482e
2019-11-25 25f54b8744778f0860ac2a93c11ee6b1cd16d0c9

View File

@ -1 +1 @@
2019-09-19 f5acd9b2761cb465a885ecff6ddb436bacff0788
2019-11-25 ceeaef3ad58fc5b88cf4686aa42f50fd254063e3

View File

@ -1 +1 @@
2019-09-19 b078e13e4c53a1b0db0bd0336d64b3abf50e88e3
2019-11-25 aee36abdef456d2d1c6bba023f16cbca08eceabe

View File

@ -1 +1 @@
2019-09-19 cdaaf832a7be3789c06a88888b11fafe6044b6ac
2019-11-25 ede7ce464c3f4b8486fd93413088a1b83fbf796a

View File

@ -1 +1 @@
2019-09-19 2f375cd8feabedf1fcee6228faef30a8165e9f5b
2019-11-25 2bea4132b9ab877e802cfb81ad3c62bda0c2bc50

View File

@ -1 +1 @@
2019-09-19 e66163f4025a92d475058a1ab1aeb911dd0c7540
2019-11-25 807893480c51457cad7e00e1275eff9749c91c68

View File

@ -1 +1 @@
2019-09-19 fdbdc1b821fdf215203eae20dd1d5482f60f2685
2019-11-25 6a3f12cd6429f5d5bcf617cdd3ea9d345e8614ad

View File

@ -1 +1 @@
2019-09-19 f2def44f31f4491e5ad1e13e3d980608e647fb91
2019-11-25 a318db7d985930e3f58ce3bccce290bc13aaedab

View File

@ -1 +1 @@
2019-09-19 30958dd0b796aed5ea5a80d43fc660fa230eed34
2019-11-25 75f1b89ea50fdfd0a69c33dee4ba1e120d49fad5

View File

@ -19,6 +19,7 @@
/* base-internal includes */
#include <base/internal/globals.h>
#include <base/internal/output.h>
#include <base/internal/raw_write_string.h>
#include <base/internal/unmanaged_singleton.h>
#include <board.h>
@ -57,3 +58,5 @@ struct Buffer
Genode::Log &Genode::Log::log() {
return unmanaged_singleton<Buffer>()->log; }
void Genode::raw_write_string(char const *str) { log(str); }

View File

@ -47,7 +47,6 @@ class Bootstrap::Platform
Mmio_space const core_mmio;
unsigned cpus { NR_OF_CPUS };
::Board::Boot_info info { };
::Board::Pic pic { };
Board();
};

View File

@ -15,6 +15,7 @@
unsigned Bootstrap::Platform::enable_mmu()
{
::Board::Pic pic { };
::Board::Cpu::Sctlr::init();
::Board::Cpu::enable_mmu_and_caches((addr_t)core_pd->table_base);

View File

@ -118,7 +118,7 @@ unsigned Bootstrap::Platform::enable_mmu()
Actlr::disable_smp();
/* locally initialize interrupt controller */
board.pic.init_cpu_local();
::Board::Pic pic { };
Cpu::invalidate_data_cache();
data_cache_invalidated.inc();

View File

@ -13,8 +13,41 @@
#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) {
_cpui.write<Cpu_interface::Ctlr>(0);
@ -40,34 +73,3 @@ void Board::Pic::init_cpu_local()
}
_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);
}

View File

@ -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_ */

View File

@ -11,10 +11,12 @@
* under the terms of the GNU Affero General Public License version 3.
*/
#include <hw/spec/arm_64/memory_map.h>
#include <platform.h>
using Board::Cpu;
extern "C" void * _crt0_enable_fpu;
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();
Cpu::Hcr::Rw::set(scr, 1); /* exec in aarch64 */
Cpu::Hcr::write(scr);
using namespace Hw::Mm;
/* 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::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_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"
"msr sp_el1, x0 \n"
"adr x0, 1f \n"
"msr elr_el2, x0 \n"
"mov sp, %0 \n"
"eret \n"
"1:");
"1:": : "r"(stack_el2): "x0");
}
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) {
if (Cpu::current_privilege_level() == Cpu::Current_el::EL3)
if (Cpu::current_privilege_level() == Cpu::Current_el::EL3) {
prepare_non_secure_world();
else
prepare_hypervisor();
} else {
::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 */
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);
/* 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::Attr2::set(mair, Cpu::Mair::NORMAL_MEMORY_CACHED);
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::Ttbr1_el1::write(ttbr);
@ -119,13 +188,14 @@ unsigned Bootstrap::Platform::enable_mmu()
Cpu::Tcr_el1::As::set(tcr, 1);
Cpu::Tcr_el1::write(tcr);
Cpu::Sctlr_el1::access_t sctlr = Cpu::Sctlr_el1::read();
Cpu::Sctlr_el1::C::set(sctlr, 1);
Cpu::Sctlr_el1::I::set(sctlr, 1);
Cpu::Sctlr_el1::A::set(sctlr, 0);
Cpu::Sctlr_el1::M::set(sctlr, 1);
Cpu::Sctlr_el1::Sa0::set(sctlr, 1);
Cpu::Sctlr_el1::Sa::set(sctlr, 0);
Cpu::Sctlr::access_t sctlr = Cpu::Sctlr_el1::read();
Cpu::Sctlr::C::set(sctlr, 1);
Cpu::Sctlr::I::set(sctlr, 1);
Cpu::Sctlr::A::set(sctlr, 0);
Cpu::Sctlr::M::set(sctlr, 1);
Cpu::Sctlr::Sa0::set(sctlr, 1);
Cpu::Sctlr::Sa::set(sctlr, 0);
Cpu::Sctlr::Uct::set(sctlr, 1);
Cpu::Sctlr_el1::write(sctlr);
return 0;

View File

@ -23,8 +23,19 @@
mrs x0, mpidr_el1
and x0, x0, #0b11111111
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
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:
ldr x0, =_bss_start
ldr x1, =_bss_end
ldr x1, =_bss_start
ldr x2, =_bss_end
1:
cmp x1, x0
cmp x2, x1
b.eq _crt0_enable_fpu
str xzr, [x0], #8
str xzr, [x1], #8
b 1b
@ -45,20 +56,30 @@
** Enable FPU **
****************/
.global _crt0_enable_fpu
_crt0_enable_fpu:
mov x0, #0b11
lsl x0, x0, #20
msr cpacr_el1, x0
mov x1, #0b11
lsl x1, x1, #20
msr cpacr_el1, x1
/**********************
** Initialize stack **
**********************/
ldr x0, =_crt0_start_stack
mov sp, x0
.set STACK_SIZE, 0x2000
ldr x1, =_crt0_start_stack
ldr x2, [x1]
mul x0, x0, x2
add x1, x1, x0
mov sp, x1
bl init
.p2align 4
.space 0x4000
.rept NR_OF_CPUS
.space STACK_SIZE
.endr
_crt0_start_stack:
.long STACK_SIZE

View File

@ -17,11 +17,11 @@
#include <hw/spec/arm/arndale_board.h>
#include <hw/spec/arm/lpae.h>
#include <spec/arm/cpu.h>
#include <spec/arm/gicv2.h>
#include <hw/spec/arm/gicv2.h>
namespace Board {
using namespace Hw::Arndale_board;
using Pic = Hw::Gicv2;
static constexpr bool NON_SECURE = true;
}

View File

@ -155,7 +155,9 @@ unsigned Bootstrap::Platform::enable_mmu()
using namespace ::Board;
static volatile bool primary_cpu = true;
board.pic.init_cpu_local();
/* locally initialize interrupt controller */
::Board::Pic pic { };
prepare_nonsecure_world();
prepare_hypervisor((addr_t)core_pd->table_base);

View File

@ -18,11 +18,11 @@
#include <spec/arm/cortex_a9_actlr.h>
#include <spec/arm/cortex_a9_page_table.h>
#include <spec/arm/cpu.h>
#include <spec/arm/gicv2.h>
#include <hw/spec/arm/gicv2.h>
namespace Board {
using namespace Hw::Imx6q_sabrelite_board;
using Pic = Hw::Gicv2;
struct L2_cache;
static constexpr bool NON_SECURE = false;

View File

@ -17,11 +17,11 @@
#include <hw/spec/arm/imx7d_sabre_board.h>
#include <hw/spec/arm/lpae.h>
#include <spec/arm/cpu.h>
#include <spec/arm/gicv2.h>
#include <hw/spec/arm/gicv2.h>
namespace Board {
using namespace Hw::Imx7d_sabre_board;
using Pic = Hw::Gicv2;
static constexpr bool NON_SECURE = true;
}

View File

@ -287,7 +287,9 @@ unsigned Bootstrap::Platform::enable_mmu()
{
static volatile bool primary_cpu = true;
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_hypervisor((addr_t)core_pd->table_base);

View File

@ -21,7 +21,12 @@
namespace 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;
};

View File

@ -24,4 +24,269 @@ Bootstrap::Platform::Board::Board()
Memory_region { ::Board::Cpu_mmio::IRQ_CONTROLLER_DISTR_BASE,
::Board::Cpu_mmio::IRQ_CONTROLLER_DISTR_SIZE },
Memory_region { ::Board::Cpu_mmio::IRQ_CONTROLLER_REDIST_BASE,
::Board::Cpu_mmio::IRQ_CONTROLLER_REDIST_SIZE }) {}
::Board::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");
}
}

View File

@ -18,11 +18,11 @@
#include <spec/arm/cortex_a9_actlr.h>
#include <spec/arm/cortex_a9_page_table.h>
#include <spec/arm/cpu.h>
#include <spec/arm/gicv2.h>
#include <hw/spec/arm/gicv2.h>
namespace Board {
using namespace Hw::Nit6_solox_board;
using Pic = Hw::Gicv2;
struct L2_cache;
static constexpr bool NON_SECURE = false;

View File

@ -17,10 +17,11 @@
#include <hw/spec/arm/odroid_xu_board.h>
#include <hw/spec/arm/lpae.h>
#include <spec/arm/cpu.h>
#include <spec/arm/gicv2.h>
#include <hw/spec/arm/gicv2.h>
namespace Board {
using namespace Hw::Odroid_xu_board;
using Pic = Hw::Gicv2;
static constexpr bool NON_SECURE = false;
}

View File

@ -25,7 +25,9 @@ Bootstrap::Platform::Board::Board()
unsigned Bootstrap::Platform::enable_mmu()
{
board.pic.init_cpu_local();
/* locally initialize interrupt controller */
::Board::Pic pic { };
Cpu::Sctlr::init();
Cpu::Cpsr::init();
Cpu::invalidate_data_cache();

View File

@ -17,11 +17,11 @@
#include <hw/spec/arm/panda_board.h>
#include <spec/arm/cortex_a9_page_table.h>
#include <spec/arm/cpu.h>
#include <spec/arm/gicv2.h>
#include <hw/spec/arm/gicv2.h>
namespace Board {
using namespace Hw::Panda_board;
using Pic = Hw::Gicv2;
static constexpr bool NON_SECURE = false;
class L2_cache;

View File

@ -19,11 +19,13 @@
#include <spec/arm/cortex_a9_actlr.h>
#include <spec/arm/cortex_a9_page_table.h>
#include <spec/arm/cpu.h>
#include <spec/arm/gicv2.h>
#include <hw/spec/arm/gicv2.h>
namespace Board {
using namespace Hw::Pbxa9_board;
using Pic = Hw::Gicv2;
static constexpr bool NON_SECURE = false;
}

View File

@ -16,10 +16,7 @@
#include <hw/spec/riscv/board.h>
namespace Board {
using namespace Hw::Riscv_board;
struct Pic {};
}
namespace Board { using namespace Hw::Riscv_board; }
template <typename E, unsigned B, unsigned S>
void Sv39::Level_x_translation_table<E, B, S>::_translation_added(addr_t, size_t)

View File

@ -18,11 +18,7 @@
#include <hw/spec/arm/page_table.h>
#include <spec/arm/cpu.h>
namespace Board {
using namespace Hw::Rpi_board;
struct Pic {};
}
namespace Board { using namespace Hw::Rpi_board; }
constexpr unsigned Hw::Page_table::Descriptor_base::_device_tex() {

View File

@ -20,8 +20,13 @@
namespace 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_ */

View File

@ -26,3 +26,12 @@ Bootstrap::Platform::Board::Board()
::Board::LOCAL_IRQ_CONTROLLER_SIZE },
Memory_region { ::Board::IRQ_CONTROLLER_BASE,
::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");
}

View File

@ -38,6 +38,8 @@ Bootstrap::Platform::Board::Board()
Aipstz aipstz_1(AIPS_1_MMIO_BASE);
Aipstz aipstz_2(AIPS_2_MMIO_BASE);
Pic pic {};
/* set monitor mode exception vector entry */
Cpu::Mvbar::write(Hw::Mm::system_exception_vector().base);

View File

@ -18,11 +18,13 @@
#include <spec/arm/cortex_a9_actlr.h>
#include <spec/arm/cortex_a9_page_table.h>
#include <spec/arm/cpu.h>
#include <spec/arm/gicv2.h>
#include <hw/spec/arm/gicv2.h>
namespace Board {
using namespace Hw::Wand_quad_board;
using Pic = Hw::Gicv2;
struct L2_cache;
static constexpr bool NON_SECURE = false;

View File

@ -22,7 +22,6 @@
namespace Board {
using namespace Hw::Pc_board;
using Cpu = Hw::X86_64_cpu;
struct Pic {};
}
#endif /* _SRC__BOOTSTRAP__SPEC__X86_64__BOARD_H_ */

View File

@ -18,10 +18,11 @@
#include <spec/arm/cortex_a9_actlr.h>
#include <spec/arm/cortex_a9_page_table.h>
#include <spec/arm/cpu.h>
#include <spec/arm/gicv2.h>
#include <hw/spec/arm/gicv2.h>
namespace Board {
using namespace Hw::Zynq_qemu_board;
using Pic = Hw::Gicv2;
static constexpr bool NON_SECURE = false;
}

View File

@ -18,7 +18,6 @@
/* core includes */
#include "kernel/irq.h"
#include <irq_root.h>
#include <irq_args.h>
#include <core_env.h>
/* base-internal includes */
@ -35,10 +34,7 @@ unsigned Irq_session_component::_find_irq_number(const char * const args)
void Irq_session_component::ack_irq()
{
using Kernel::User_irq;
if (!_sig_cap.valid()) { return; }
User_irq * const kirq = reinterpret_cast<User_irq*>(&_kernel_object);
Kernel::ack_irq(kirq);
if (_kobj.constructed()) Kernel::ack_irq(*_kobj);
}
@ -51,8 +47,8 @@ void Irq_session_component::sigh(Signal_context_capability cap)
_sig_cap = cap;
if (Kernel::new_irq((addr_t)&_kernel_object, _irq_number,
Capability_space::capid(_sig_cap)))
if (!_kobj.create(_irq_number, _irq_args.trigger(), _irq_args.polarity(),
Capability_space::capid(_sig_cap)))
warning("invalid signal handler for IRQ ", _irq_number);
}
@ -61,18 +57,16 @@ Irq_session_component::~Irq_session_component()
{
using namespace Kernel;
User_irq * kirq = reinterpret_cast<User_irq*>(&_kernel_object);
_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,
const char * const args)
:
_irq_number(Platform::irq(_find_irq_number(args))), _irq_alloc(irq_alloc),
_is_msi(false), _address(0), _value(0)
: _irq_args(args),
_irq_number(Platform::irq(_irq_args.irq_number())),
_irq_alloc(irq_alloc),
_kobj(), _is_msi(false), _address(0), _value(0)
{
const long mmconf =
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");
throw Service_denied();
}
Irq_args const irq_args(args);
Kernel::irq_mode(_irq_number, irq_args.trigger(), irq_args.polarity());
}

View File

@ -31,6 +31,7 @@ namespace Kernel
class Vm;
class User_irq;
using Native_utcb = Genode::Native_utcb;
template <typename T> class Core_object_identity;
/**
* 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_cancel_thread_blocking() { return 123; }
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`
*/
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)
{
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);
}
@ -79,9 +79,9 @@ namespace Kernel
* \param thread kernel object of the targeted thread
* \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
* 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
*/
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 failed
*/
inline int start_thread(Thread * const thread, unsigned const cpu_id,
Pd * const pd, Native_utcb * const utcb)
inline int start_thread(Thread & thread, unsigned const cpu_id,
Pd & pd, Native_utcb & utcb)
{
return call(call_id_start_thread(), (Call_arg)thread, cpu_id,
(Call_arg)pd, (Call_arg)utcb);
return call(call_id_start_thread(), (Call_arg)&thread, cpu_id,
(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
* 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 signal_context_id capability id of the page-fault handler
*/
inline void thread_pager(Thread * const thread,
capid_t const signal_context_id)
inline void thread_pager(Thread & thread,
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
*/
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
*/
inline void pause_vm(Vm * const vm)
inline void pause_vm(Vm & 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);
call(call_id_pause_vm(), (Call_arg) &vm);
}
/**
@ -224,40 +200,9 @@ namespace Kernel
*
* \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);
}
/**
* 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);
call(call_id_ack_irq(), (Call_arg) &irq);
}
}

View File

@ -157,10 +157,10 @@ addr_t Cpu::stack_start() {
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)
:
_id(id), _pic(pic), _timer(*this),
_id(id), _timer(*this),
_scheduler(&_idle, _quota(), _fill()), _idle(*this),
_ipi_irq(*this),
_global_work_list(global_work_list)
@ -174,7 +174,7 @@ Cpu::Cpu(unsigned const id, Board::Pic & pic,
bool Cpu_pool::initialize()
{
unsigned id = Cpu::executing_id();
_cpus[id].construct(id, _pic, _global_work_list);
_cpus[id].construct(id, _global_work_list);
return --_initialized == 0;
}

View File

@ -113,7 +113,7 @@ class Kernel::Cpu : public Genode::Cpu, private Irq::Pool, private Timeout
unsigned const _id;
Board::Pic &_pic;
Board::Pic _pic {};
Timer _timer;
Cpu_scheduler _scheduler;
Idle_thread _idle;
@ -133,7 +133,7 @@ class Kernel::Cpu : public Genode::Cpu, private Irq::Pool, private Timeout
/**
* Construct object for CPU 'id'
*/
Cpu(unsigned const id, Board::Pic & pic,
Cpu(unsigned const id,
Inter_processor_work_list & global_work_list);
static inline unsigned primary_id() { return 0; }
@ -192,7 +192,6 @@ class Kernel::Cpu_pool
{
private:
Board::Pic _pic {};
Inter_processor_work_list _global_work_list {};
unsigned _count;
unsigned _initialized { _count };

View File

@ -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()); }

View File

@ -15,9 +15,6 @@
#ifndef _CORE__KERNEL__IPC_NODE_H_
#define _CORE__KERNEL__IPC_NODE_H_
/* Genode includes */
#include <util/construct_at.h>
/* base-local includes */
#include <base/internal/native_utcb.h>

View File

@ -30,3 +30,14 @@ Kernel::Irq::Pool &Kernel::User_irq::_pool()
static Irq::Pool 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);
}

View File

@ -135,8 +135,10 @@ class Kernel::User_irq : public Kernel::Irq, public Kernel::Object
/**
* Construct object that signals interrupt 'irq' via signal 'context'
*/
User_irq(unsigned const irq, Signal_context &context)
: Irq(irq, _pool()), _context(context) { disable(); }
User_irq(unsigned const irq,
Genode::Irq_session::Trigger trigger,
Genode::Irq_session::Polarity polarity,
Signal_context & context);
/**
* Destructor
@ -157,6 +159,33 @@ class Kernel::User_irq : public Kernel::Irq, public Kernel::Object
*/
static User_irq * object(unsigned const 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_ */

View File

@ -31,7 +31,7 @@ class Kernel::Lock
enum State { UNLOCKED, LOCKED };
State volatile _locked { UNLOCKED };
int volatile _locked { UNLOCKED };
unsigned volatile _current_cpu { INVALID };
public:

View File

@ -18,8 +18,10 @@
#include <util/avl_tree.h>
#include <util/bit_allocator.h>
#include <util/list.h>
#include <util/reconstructible.h>
/* core includes */
#include <kernel/core_interface.h>
#include <kernel/interface.h>
#include "kernel.h"
@ -192,6 +194,13 @@ class Kernel::Core_object_identity : public Object_identity,
Object_identity_reference(this, core_pd()) { }
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); }
};

View File

@ -18,10 +18,12 @@
/* core includes */
#include <hw/assert.h>
#include <cpu.h>
#include "core_interface.h"
#include "object.h"
#include <kernel/core_interface.h>
#include <object.h>
#include <translation_table.h>
#include <util/reconstructible.h>
namespace Genode {
class Platform_pd;
}
@ -51,6 +53,7 @@ class Kernel::Pd : public Kernel::Object
Genode::Platform_pd &_platform_pd;
Capid_allocator _capid_alloc { };
Object_identity_reference_tree _cap_tree { };
bool _core_pd { false };
public:
@ -69,6 +72,12 @@ class Kernel::Pd : public Kernel::Object
{
capid_t invalid = _capid_alloc.alloc();
assert(invalid == cap_id_invalid());
static bool first_pd = true;
if (first_pd) {
_core_pd = true;
first_pd = false;
}
}
~Pd()
@ -77,16 +86,16 @@ class Kernel::Pd : public Kernel::Object
oir->~Object_identity_reference();
}
static capid_t syscall_create(void * const dst,
Hw::Page_table &tt,
Genode::Platform_pd &pd)
static capid_t syscall_create(Genode::Kernel_object<Pd> & p,
Hw::Page_table & tt,
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);
}
static void syscall_destroy(Pd * const pd) {
call(call_id_delete_pd(), (Call_arg)pd); }
static void syscall_destroy(Genode::Kernel_object<Pd> & p) {
call(call_id_delete_pd(), (Call_arg)&p); }
/**
* 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; }
Capid_allocator &capid_alloc() { return _capid_alloc; }
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_ */

View File

@ -55,7 +55,7 @@ Signal_context_killer::~Signal_context_killer() { cancel_waiting(); }
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()
{
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)
:
_receiver(r),
_imprint(imprint)
Signal_context::Signal_context(Signal_receiver & r, addr_t const imprint)
: _receiver(r),
_imprint(imprint)
{
r->_add_context(this);
r._add_context(this);
}
@ -164,7 +163,7 @@ void Signal_receiver::_listen()
/* communicate signal data to handler */
_handlers.dequeue([&] (Signal_handler::Fifo_element &elem) {
auto const handler = &elem.object();
handler->_receiver = 0;
handler->_receiver = nullptr;
handler->_receive_signal(&data, sizeof(data));
});
context->_delivered();

View File

@ -16,9 +16,10 @@
/* Genode includes */
#include <base/signal.h>
#include <util/reconstructible.h>
#include "core_interface.h"
#include "object.h"
#include <kernel/core_interface.h>
#include <object.h>
namespace Kernel
{
@ -160,7 +161,7 @@ class Kernel::Signal_context : public Kernel::Object
Fifo_element _deliver_fe { *this };
Fifo_element _contexts_fe { *this };
Signal_receiver * const _receiver;
Signal_receiver & _receiver;
addr_t const _imprint;
Signal_context_killer * _killer { nullptr };
unsigned _submits { 0 };
@ -197,7 +198,7 @@ class Kernel::Signal_context : public Kernel::Object
*
* \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
@ -233,12 +234,12 @@ class Kernel::Signal_context : public Kernel::Object
*
* \retval capability id of the new kernel object
*/
static capid_t syscall_create(void * p,
Signal_receiver * const receiver,
static capid_t syscall_create(Genode::Kernel_object<Signal_context> &c,
Signal_receiver & receiver,
addr_t const imprint)
{
return call(call_id_new_signal_context(), (Call_arg)p,
(Call_arg)receiver, (Call_arg)imprint);
return call(call_id_new_signal_context(), (Call_arg)&c,
(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
*/
static void syscall_destroy(Signal_context * const context) {
call(call_id_delete_signal_context(), (Call_arg)context); }
static void syscall_destroy(Genode::Kernel_object<Signal_context> &c) {
call(call_id_delete_signal_context(), (Call_arg)&c); }
};
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
*/
static capid_t syscall_create(void * p) {
return call(call_id_new_signal_receiver(), (Call_arg)p); }
static capid_t syscall_create(Genode::Kernel_object<Signal_receiver> &r) {
return call(call_id_new_signal_receiver(), (Call_arg)&r); }
/**
* Syscall to destruct a signal receiver
*
* \param receiver pointer to signal receiver kernel object
*/
static void syscall_destroy(Signal_receiver * const receiver) {
call(call_id_delete_signal_receiver(), (Call_arg)receiver); }
static void syscall_destroy(Genode::Kernel_object<Signal_receiver> &r) {
call(call_id_delete_signal_receiver(), (Call_arg)&r); }
};
#endif /* _CORE__KERNEL__SIGNAL_RECEIVER_H_ */

View File

@ -15,7 +15,6 @@
/* Genode includes */
#include <base/thread_state.h>
#include <cpu_session/cpu_session.h>
#include <util/construct_at.h>
/* base-internal includes */
#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)
{
thread_to_destroy._cpu->work_list().insert(&_le);
thread_to_destroy->_cpu->work_list().insert(&_le);
caller._become_inactive(AWAITS_RESTART);
}
void Thread::Destroy::execute()
{
thread_to_destroy.~Thread();
thread_to_destroy.destruct();
cpu_pool().executing_cpu().work_list().remove(&_le);
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()
{
Thread * const thread = (Thread *)user_arg_1();
@ -227,7 +204,7 @@ void Thread::_call_start_thread()
/* lookup CPU */
Cpu & cpu = cpu_pool().cpu(user_arg_2());
user_arg_0(0);
Thread &thread = *(Thread *)user_arg_1();
Thread &thread = *(Thread*)user_arg_1();
assert(thread._state == AWAITS_START);
@ -338,7 +315,8 @@ void Thread::_call_yield_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,
@ -346,7 +324,7 @@ void Thread::_call_delete_thread()
*/
if (!to_delete->_cpu ||
(to_delete->_cpu->id() == Cpu::executing_id() ||
&to_delete->_cpu->scheduled_job() != to_delete)) {
&to_delete->_cpu->scheduled_job() != &*to_delete)) {
_call_delete<Thread>();
return;
}
@ -354,7 +332,7 @@ void Thread::_call_delete_thread()
/**
* 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();
}
@ -566,21 +544,19 @@ void Thread::_call_kill_signal_context()
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) {
Genode::raw(*this, ": invalid signal context for interrupt");
user_arg_0(-1);
return;
}
new ((void *)user_arg_1()) User_irq(user_arg_2(), *c);
user_arg_0(0);
}
Genode::Irq_session::Trigger trigger =
(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()
{
cpu_pool().executing_cpu().pic().irq_mode(user_arg_1(), user_arg_2(),
user_arg_3());
_call_new<User_irq>((unsigned)user_arg_2(), trigger, polarity, *c);
}
@ -601,17 +577,18 @@ void Thread::_call_new_obj()
return;
}
using Thread_identity = Core_object_identity<Thread>;
Thread_identity * coi =
Genode::construct_at<Thread_identity>((void *)user_arg_1(), *thread);
using Thread_identity = Genode::Constructible<Core_object_identity<Thread>>;
Thread_identity & coi = *(Thread_identity*)user_arg_1();
coi.construct(*thread);
user_arg_0(coi->core_capid());
}
void Thread::_call_delete_obj()
{
using Object = Core_object_identity<Thread>;
reinterpret_cast<Object*>(user_arg_1())->~Object();
using Thread_identity = Genode::Constructible<Core_object_identity<Thread>>;
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 (call_id) {
case call_id_new_thread(): _call_new_thread(); return;
case call_id_new_core_thread(): _call_new_core_thread(); return;
case call_id_new_thread():
_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_delete_thread(): _call_delete_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_new_signal_receiver(): _call_new<Signal_receiver>(); return;
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;
case call_id_delete_signal_context(): _call_delete<Signal_context>(); 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_thread(): _call_pause_thread(); 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<Irq>(); return;
case call_id_delete_irq(): _call_delete<User_irq>(); return;
case call_id_ack_irq(): _call_ack_irq(); return;
case call_id_new_obj(): _call_new_obj(); return;
case call_id_delete_obj(): _call_delete_obj(); return;

View File

@ -19,11 +19,11 @@
/* core includes */
#include <cpu.h>
#include "cpu_context.h"
#include "inter_processor_work.h"
#include "signal_receiver.h"
#include "ipc_node.h"
#include "object.h"
#include <kernel/cpu_context.h>
#include <kernel/inter_processor_work.h>
#include <kernel/signal_receiver.h>
#include <kernel/ipc_node.h>
#include <object.h>
namespace Kernel
{
@ -89,10 +89,12 @@ class Kernel::Thread
*/
struct Destroy : Inter_processor_work
{
Thread & caller; /* the caller gets blocked till the end */
Thread & thread_to_destroy; /* thread to be destroyed */
using Kthread = Genode::Kernel_object<Thread>;
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 **
@ -241,18 +243,19 @@ class Kernel::Thread
template <typename T, typename... ARGS>
void _call_new(ARGS &&... args)
{
using Object = Core_object<T>;
void * dst = (void *)user_arg_1();
Object * o = Genode::construct_at<Object>(dst, args...);
user_arg_0(o->core_capid());
Genode::Kernel_object<T> & kobj =
*(Genode::Kernel_object<T>*)user_arg_1();
kobj.construct(args...);
user_arg_0(kobj->core_capid());
}
template <typename T>
void _call_delete()
{
using Object = Core_object<T>;
reinterpret_cast<Object*>(user_arg_1())->~Object();
Genode::Kernel_object<T> & kobj =
*(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_3(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_1() const;
Kernel::Call_arg user_arg_2() const;
Kernel::Call_arg user_arg_3() const;
Kernel::Call_arg user_arg_4() const;
Kernel::Call_arg user_arg_5() const;
/**
* Syscall to create a thread
@ -334,11 +339,12 @@ class Kernel::Thread
*
* \retval capability id of the new kernel object
*/
static capid_t syscall_create(void * const p, unsigned const priority,
size_t const quota,
char const * const label)
static capid_t syscall_create(Genode::Kernel_object<Thread> & t,
unsigned const priority,
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);
}
@ -350,9 +356,10 @@ class Kernel::Thread
*
* \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);
}
@ -361,8 +368,8 @@ class Kernel::Thread
*
* \param thread pointer to thread kernel object
*/
static void syscall_destroy(Thread * thread) {
call(call_id_delete_thread(), (Call_arg)thread); }
static void syscall_destroy(Genode::Kernel_object<Thread> & t) {
call(call_id_delete_thread(), (Call_arg)&t); }
void print(Genode::Output &out) const;

View File

@ -105,8 +105,6 @@ class Kernel::Timer
unsigned interrupt_id() const;
static void init_cpu_local();
time_t time() const { return _time + _duration(); }
};

View File

@ -22,6 +22,8 @@ namespace Genode { class Vm_state; }
#include "pd.h"
#include "signal_receiver.h"
#include <board.h>
namespace Kernel
{
/**
@ -36,19 +38,22 @@ class Kernel::Vm : public Cpu_job,
{
private:
using State = Board::Vm_state;
/*
* Noncopyable
*/
Vm(Vm const &);
Vm &operator = (Vm const &);
enum State { ACTIVE, INACTIVE };
enum Scheduler_state { ACTIVE, INACTIVE };
unsigned _id = 0;
Genode::Vm_state * const _state;
Signal_context * const _context;
void * const _table;
State _scheduled = INACTIVE;
unsigned _id = 0;
State & _state;
Signal_context & _context;
void * const _table;
Scheduler_state _scheduled = INACTIVE;
Board::Vcpu_context _vcpu_context;
public:
@ -59,9 +64,10 @@ class Kernel::Vm : public Cpu_job,
* \param context signal for VM exceptions other than interrupts
* \param table translation table for guest to host physical memory
*/
Vm(void * const state,
Signal_context * const context,
void * const table);
Vm(unsigned cpu,
State & state,
Signal_context & context,
void * const table);
~Vm();
@ -84,12 +90,14 @@ class Kernel::Vm : public Cpu_job,
*
* \retval cap id when successful, otherwise invalid cap id
*/
static capid_t syscall_create(void * const dst, void * const state,
capid_t const signal_context_id,
void * const table)
static capid_t syscall_create(Genode::Kernel_object<Vm> & vm,
unsigned cpu,
void * const state,
capid_t const signal_context_id,
void * const table)
{
return call(call_id_new_vm(), (Call_arg)dst, (Call_arg)state,
(Call_arg)table, signal_context_id);
return call(call_id_new_vm(), (Call_arg)&vm, (Call_arg)cpu,
(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
*/
static void syscall_destroy(Vm * const vm) {
call(call_id_delete_vm(), (Call_arg) vm); }
static void syscall_destroy(Genode::Kernel_object<Vm> & vm) {
call(call_id_delete_vm(), (Call_arg) &vm); }
/****************

View File

@ -18,13 +18,14 @@
void Kernel::Thread::_call_new_vm()
{
Signal_context * context =
pd().cap_tree().find<Signal_context>(user_arg_4());
pd().cap_tree().find<Signal_context>(user_arg_5());
if (!context) {
user_arg_0(cap_id_invalid());
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());
}

View File

@ -15,7 +15,7 @@
#define _CORE__OBJECT_H_
/* Genode includes */
#include <util/construct_at.h>
#include <util/reconstructible.h>
/* base-internal includes */
#include <base/internal/capability_space.h>
@ -35,13 +35,8 @@ namespace Genode {
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:
Untyped_capability _cap { };
@ -55,15 +50,17 @@ class Genode::Kernel_object
*/
template <typename... 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()))
{
if (!syscall) construct_at<T>(&_data, args...);
if (!syscall) Genode::Constructible<Kernel::Core_object<T>>::construct(args...);
}
~Kernel_object() { T::syscall_destroy(kernel_object()); }
T * kernel_object() { return reinterpret_cast<T*>(_data); }
~Kernel_object()
{
if (Genode::Constructible<Kernel::Core_object<T>>::constructed())
T::syscall_destroy(*this);
}
Untyped_capability cap() { return _cap; }
@ -73,8 +70,10 @@ class Genode::Kernel_object
template <typename... ARGS>
bool create(ARGS &&... args)
{
if (_cap.valid()) return false;
_cap = Capability_space::import(T::syscall_create(&_data, args...));
if (Genode::Constructible<Kernel::Core_object<T>>::constructed())
return false;
_cap = Capability_space::import(T::syscall_create(*this, args...));
return _cap.valid();
}
};

View File

@ -53,12 +53,12 @@ void Pager_object::wake_up()
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 Entry = Object_pool<Pager_object>::Entry;
create(receiver, (unsigned long)this);
create(*receiver, (unsigned long)this);
Entry::cap(Object::_cap);
}
@ -103,13 +103,13 @@ void Pager_entrypoint::dissolve(Pager_object &o)
Pager_entrypoint::Pager_entrypoint(Rpc_cap_factory &)
: Thread_deprecated<PAGER_EP_STACK_SIZE>("pager_ep"),
Kernel_object<Kernel::Signal_receiver>(true)
_kobj(true)
{ start(); }
Pager_capability Pager_entrypoint::manage(Pager_object &o)
{
o.start_paging(kernel_object());
o.start_paging(_kobj);
insert(&o);
return reinterpret_cap_cast<Pager_object>(o.cap());
}

View File

@ -69,26 +69,29 @@ void Hw::Address_space::flush(addr_t virt, size_t size, Core_local_addr)
try {
_tt.remove_translation(virt, size, _tt_alloc);
Kernel::invalidate_tlb(&_kernel_pd, virt, size);
Kernel::invalidate_tlb(*_kobj, virt, size);
} catch(...) {
error("tried to remove invalid region!");
}
}
Hw::Address_space::Address_space(Kernel::Pd & pd, Page_table & tt,
Page_table::Allocator & tt_alloc)
: _tt(tt), _tt_phys(Platform::core_page_table()),
_tt_alloc(tt_alloc), _kernel_pd(pd) { }
Hw::Address_space::Address_space(Page_table & tt,
Page_table::Allocator & tt_alloc,
Platform_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_phys((addr_t)_cma().phys_addr(&_tt)),
_tt_array(new (_cma()) Array([] (void * virt) {
return (addr_t)_cma().phys_addr(virt);})),
_tt_alloc(_tt_array->alloc()),
_kernel_pd(pd) { }
_kobj(true, *(Page_table*)translation_table_phys(), pd) { }
Hw::Address_space::~Address_space()
@ -142,20 +145,13 @@ void Platform_pd::assign_parent(Native_capability parent)
Platform_pd::Platform_pd(Page_table & tt,
Page_table::Allocator & alloc)
:
Hw::Address_space(*kernel_object(), tt, alloc),
Kernel_object<Kernel::Pd>(false, *(Page_table*)translation_table_phys(), *this),
_label("core")
{ }
: Hw::Address_space(tt, alloc, *this), _label("core") { }
Platform_pd::Platform_pd(Allocator &, char const *label)
:
Hw::Address_space(*kernel_object()),
Kernel_object<Kernel::Pd>(true, *(Page_table*)translation_table_phys(), *this),
_label(label)
: Hw::Address_space(*this), _label(label)
{
if (!_cap.valid()) {
if (!_kobj.cap().valid()) {
error("failed to create kernel object");
throw Service_denied();
}

View File

@ -54,7 +54,7 @@ Platform_thread::~Platform_thread()
void Platform_thread::quota(size_t const 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 */
_kobj.kernel_object()->regs->ip = reinterpret_cast<addr_t>(ip);
_kobj.kernel_object()->regs->sp = reinterpret_cast<addr_t>(sp);
_kobj->regs->ip = reinterpret_cast<addr_t>(ip);
_kobj->regs->sp = reinterpret_cast<addr_t>(sp);
/* start executing new thread */
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(_utcb));
}
Kernel::start_thread(_kobj.kernel_object(), cpu, &_pd->kernel_pd(),
_utcb_core_addr);
Kernel::start_thread(*_kobj, cpu, _pd->kernel_pd(), *_utcb_core_addr);
return 0;
}
@ -189,7 +188,7 @@ void Platform_thread::pager(Pager_object &pager)
{
using namespace Kernel;
thread_pager(_kobj.kernel_object(), Capability_space::capid(pager.cap()));
thread_pager(*_kobj, Capability_space::capid(pager.cap()));
_pager = &pager;
}
@ -205,14 +204,14 @@ Genode::Pager_object &Platform_thread::pager()
Thread_state Platform_thread::state()
{
Thread_state bstate(*_kobj.kernel_object()->regs);
Thread_state bstate(*_kobj->regs);
return Thread_state(bstate);
}
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);
}

View File

@ -36,7 +36,7 @@ void Pager_entrypoint::entry()
if (cap.valid()) Kernel::ack_signal(Capability_space::capid(cap));
/* 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();
cap = po->cap();

View File

@ -55,19 +55,21 @@ struct Genode::Signal_source_component : private Kernel_object<Kernel::Signal_re
using Signal_source_pool::Entry::cap;
Signal_source_component()
:
Kernel_object<Kernel::Signal_receiver>(true),
Signal_source_pool::Entry(Kernel_object<Kernel::Signal_receiver>::_cap)
: Kernel_object<Kernel::Signal_receiver>(true),
Signal_source_pool::Entry(Kernel_object<Kernel::Signal_receiver>::cap())
{ }
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,
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)
{ }

View File

@ -12,6 +12,7 @@
*/
#include <board.h>
#include <cpu.h>
#include <platform.h>
@ -21,41 +22,109 @@ Board::Pic::Pic()
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) {
irq = TIMER_IRQ;
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;
}
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)
{
if (cpu > 0)
Genode::raw("multi-core irq controller not implemented yet");
if (i == TIMER_IRQ) {
write<Core0_timer_irq_control::Cnt_p_ns_irq>(1);
return;
switch (i) {
case TIMER_IRQ: _timer_irq(cpu, true); return;
case IPI: _ipi(cpu, true); 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)
{
if (i == TIMER_IRQ) {
write<Core0_timer_irq_control::Cnt_p_ns_irq>(0);
return;
unsigned cpu = Genode::Cpu::executing_id();
switch (i) {
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::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;
}
}

View File

@ -23,43 +23,45 @@ class Board::Pic : Genode::Mmio
public:
enum {
IPI = 0,
NR_OF_IRQ = 64,
/*
* dummy IPI value on non-SMP platform,
* only used in interrupt reservation within generic code
*/
IPI,
};
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> {};
struct Core2_timer_irq_control : Register<0x48, 32> {};
struct Core3_timer_irq_control : Register<0x4c, 32> {};
template <unsigned CPU_NUM>
struct Core_mailbox_irq_control : Register<0x50+CPU_NUM*0x4, 32> {};
struct Core0_irq_source : Register<0x60, 32> {};
struct Core1_irq_source : Register<0x64, 32> {};
struct Core2_irq_source : Register<0x68, 32> {};
struct Core3_irq_source : Register<0x6c, 32> {};
template <unsigned CPU_NUM>
struct Core_irq_source : Register<0x60+CPU_NUM*0x4, 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:
Pic();
void init_cpu_local();
bool take_request(unsigned &irq);
void finish_request() { }
void mask();
void unmask(unsigned const i, unsigned);
void mask(unsigned const i);
void irq_mode(unsigned, unsigned, unsigned);
void send_ipi(unsigned);
static constexpr bool fast_interrupts() { return false; }
};

View File

@ -17,11 +17,16 @@
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()
: _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_sgi(Platform::mmio_to_virt(Board::Cpu_mmio::IRQ_CONTROLLER_REDIST_BASE)
+ Board::Cpu_mmio::IRQ_CONTROLLER_REDIST_SIZE / 2),
_redistr(redistributor_addr()),
_redistr_sgi(redistributor_addr() + 0x10000),
_max_irq(_distr.max_irq())
{
_redistributor_init();

View File

@ -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_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_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_1() const { return regs->r1; }
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_4() const { return regs->r4; }
Kernel::Call_arg Thread::user_arg_5() const { return regs->r5; }

View 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_ */

View 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