mirror of
https://github.com/mmueller41/genode.git
synced 2026-01-21 12:32:56 +01:00
Merge branch 'master' into ealan to sync with upstream.
This commit is contained in:
61
doc/news.txt
61
doc/news.txt
@@ -4,6 +4,67 @@
|
|||||||
===========
|
===========
|
||||||
|
|
||||||
|
|
||||||
|
Sculpt OS release 22.10 | 2022-10-13
|
||||||
|
####################################
|
||||||
|
|
||||||
|
| Sculpt OS 22.10 is a maintenance release of our Genode-based
|
||||||
|
| general-purpose OS. It imposes a new rigid regime to the management of
|
||||||
|
| low-level devices, improves USB hotplug support, and comes with numerous
|
||||||
|
| performance optimizations.
|
||||||
|
|
||||||
|
The just released version 22.10 of the Sculpt operating system bears the fruit
|
||||||
|
of our year-long effort to apply the rigidity of Genode's architecture to the
|
||||||
|
management of PCI configuration and device interrupts. This sweeping change
|
||||||
|
left no single device driver unturned. If we did our job right, you should not
|
||||||
|
notice any visible difference from the previous Sculpt version.
|
||||||
|
|
||||||
|
However, you should definitely _feel_ a difference when using the new version.
|
||||||
|
We put several performance optimizations in place - from accelerated system
|
||||||
|
startup, over increased network thoughput, to improved user-interface
|
||||||
|
responsiveness. Moreover, we put much emphasis on stressing Sculpt's USB
|
||||||
|
hotplug support, which includes the dynamic assignment and revocation of
|
||||||
|
USB devices to and from virtual machines.
|
||||||
|
|
||||||
|
With respect to available software, Sculpt users can enjoy an updated
|
||||||
|
Chromium engine - via the Falkon or Morph web browsers - and an updated
|
||||||
|
audio driver based on OpenBSD 7.1.
|
||||||
|
|
||||||
|
Sculpt OS 22.10 is available as ready-to-use system image at the
|
||||||
|
[https://genode.org/download/sculpt - Sculpt download page] along with
|
||||||
|
updated [https://genode.org/documentation/articles/sculpt-22-10 - documentation].
|
||||||
|
|
||||||
|
|
||||||
|
Genode OS Framework release 22.08 | 2022-08-31
|
||||||
|
##############################################
|
||||||
|
|
||||||
|
| The overarching theme of Genode 22.08 is the emerging phone variant of
|
||||||
|
| Sculpt OS, touching topics as diverse as USB ECM, Mali-400 GPU, SD-card
|
||||||
|
| access, telephony, mobile-data connectivity, the Morph web browser, and a
|
||||||
|
| custom user interface. Among the further highlights are new tracing tools,
|
||||||
|
| improved network performance USB smart-card support, and VirtIO drivers for
|
||||||
|
| RISC-V.
|
||||||
|
|
||||||
|
The vision of a Genode-based smart phone is certainly our most ambitious
|
||||||
|
undertaking since we created Sculpt OS for the PC. Over the past two years, we
|
||||||
|
relentlessly pursued this vision while targeting the PinePhone hardware.
|
||||||
|
The scope of work reaches from custom firmware for the system-control
|
||||||
|
processor, over kernel development, a staggering variety of device drivers, to
|
||||||
|
the user-interface and application level. With Genode 22.08, those efforts
|
||||||
|
culminate in a first complete system - a phone variant of Sculpt OS. The
|
||||||
|
[https://genode.org/documentation/release-notes/22.08 - release documentation]
|
||||||
|
tells the story behind this line of work in great detail.
|
||||||
|
|
||||||
|
Beside phone-related topics, the new release features new tooling for
|
||||||
|
gathering and analyzing system traces that allow for holistic performance
|
||||||
|
studies covering the interplay between components. One particular success
|
||||||
|
story of the new trace recorder is a profoundly improved network performance.
|
||||||
|
Further highlights are the support for USB smart cards via PKCS#11, VirtIO
|
||||||
|
drivers for RISC-V, and the update of Qt5 to version 5.15.2.
|
||||||
|
|
||||||
|
For the complete picture, please enjoy the official
|
||||||
|
[https:/documentation/release-notes/22.08 - release documentation of version 22.08...]
|
||||||
|
|
||||||
|
|
||||||
Genode OS Framework release 22.05 | 2022-05-31
|
Genode OS Framework release 22.05 | 2022-05-31
|
||||||
##############################################
|
##############################################
|
||||||
|
|
||||||
|
|||||||
866
doc/release_notes/22-08.txt
Normal file
866
doc/release_notes/22-08.txt
Normal file
@@ -0,0 +1,866 @@
|
|||||||
|
|
||||||
|
|
||||||
|
===============================================
|
||||||
|
Release notes for the Genode OS Framework 22.08
|
||||||
|
===============================================
|
||||||
|
|
||||||
|
Genode Labs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
The overarching topic of version 22.08 is the emerging phone version of the
|
||||||
|
Genode-based Sculpt OS, targeting the PinePhone. The immense breadth and depth
|
||||||
|
of this line of work presented in Section [Genode coming to the phone]
|
||||||
|
touches topics as diverse as telephony, mobile-data connectivity, a custom
|
||||||
|
user interface, a mobile web browser, the GPU, SD-card access, USB, and audio
|
||||||
|
control.
|
||||||
|
|
||||||
|
With the growing sophistication of Genode-based systems, performance
|
||||||
|
optimizations come more and more into focus. Aided by the new tools introduced
|
||||||
|
in Section [Enhanced tooling for system tracing], we were able to profoundly
|
||||||
|
improve the network performance of Genode's user-level network routing
|
||||||
|
component. Speaking of optimizations, the current release reduces the CPU
|
||||||
|
overhead of our Linux device-driver environment
|
||||||
|
(Section [Linux-device-driver environment (DDE Linux)]) and
|
||||||
|
improves the responsiveness of GUIs based on Genode's menu-view component
|
||||||
|
(Section [Menu-view performance]).
|
||||||
|
|
||||||
|
Further topics of the new version reach from our forthcoming platform-driver
|
||||||
|
consolidation across PC and ARM-based devices, over the use of USB smart
|
||||||
|
cards, to new VirtIO drivers on RISC-V.
|
||||||
|
|
||||||
|
|
||||||
|
Genode coming to the phone
|
||||||
|
##########################
|
||||||
|
|
||||||
|
Our [https://genode.org/about/road-map - road map] for this year states the
|
||||||
|
goal of reaching a useful base line of functionality of Genode on the
|
||||||
|
PinePhone. This entails the principle ability to use the device as a phone -
|
||||||
|
receiving and issuing voice calls - and a mobile internet browser. Once
|
||||||
|
reached, this base line of functionality will allow us to routinely use Genode
|
||||||
|
on the device ("eating our own dog food"), experience pain points, guide
|
||||||
|
optimization efforts towards user-visible areas that matter, and faithfully
|
||||||
|
evaluate non-functional aspects like battery lifetime with real-world work
|
||||||
|
loads under realistic conditions.
|
||||||
|
|
||||||
|
For the Genode-based phone, we pursue the combination of a minimally-complex
|
||||||
|
trustworthy base system with a generally untrusted Web browser as application
|
||||||
|
runtime. The feature set of the base system corresponds to the bare-bones
|
||||||
|
[https://genode.org/download/sculpt - Sculpt OS] extended with appliance-like
|
||||||
|
feature-phone functionality. Thanks to Sculpt's rigid component-based
|
||||||
|
structure and the overall low complexity, it promises high reliability and
|
||||||
|
security. The application runtime is hosted on top of the base system without
|
||||||
|
tainting the assurance of the base system. In contrast to the appliance-like
|
||||||
|
and rather static feature set of the base system, the application runtime
|
||||||
|
anticipates a great variety of modern-day application scenarios, universally
|
||||||
|
expected commodity user-interface paradigms, and fast-paced software updates.
|
||||||
|
E.g., we aspire the use of WebRTC-based video conferencing via Jitsi as one
|
||||||
|
reference scenario.
|
||||||
|
|
||||||
|
Since we succeeded in bringing the Chromium web engine - the base technology
|
||||||
|
of most modern web browsers - to life as a
|
||||||
|
[https://genodians.org/nfeske/2022-01-27-browser-odyssey - native Genode component],
|
||||||
|
users of Sculpt OS are able to use a fully featured web browser without
|
||||||
|
relying on virtualization. With the use case of the browser on a mobile phone
|
||||||
|
in sight, we already ensured that the browser would work on 64-bit ARM
|
||||||
|
hardware. However, whereas we could showcase the technical feasibility of
|
||||||
|
Chromium on Genode, the practical usability eventually depends on a suitable
|
||||||
|
mobile user experience, which was largely disregarded by the desktop-oriented
|
||||||
|
Falkon browser that we enabled on Genode.
|
||||||
|
|
||||||
|
|
||||||
|
Assessment
|
||||||
|
----------
|
||||||
|
|
||||||
|
Fortunately, we discovered the Morph web browser while experimenting with
|
||||||
|
[https://xnux.eu/p-boot-demo/ - various Linux distributions] on the PinePhone.
|
||||||
|
Among the various alternatives to Android, the Ubuntu Touch UI - alongside
|
||||||
|
Sailfish OS - stood out for its refined user experience, subjectively.
|
||||||
|
The unobtrusive Morph browser as used by default on Ubuntu Touch left a
|
||||||
|
particularly good impression on us. To our delight, we found that this
|
||||||
|
browser relies on Qt5 and the Chromium web engine as its foundation, both of
|
||||||
|
which we already had enabled on Genode. Out of this observation grew the idea
|
||||||
|
of reusing the Morph browser as application runtime on our Genode-based phone.
|
||||||
|
But we had to consider several risks.
|
||||||
|
|
||||||
|
First, would the heaviness of Chromium overwhelm the rather resource-constrained
|
||||||
|
PinePhone hardware when executed on Genode? In contrast to Linux, Genode's
|
||||||
|
POSIX environment is less sophisticated and - most importantly - does not
|
||||||
|
provide the over-provisioning of memory resources. The latter could be a show
|
||||||
|
stopper.
|
||||||
|
|
||||||
|
Second, the build mechanics of the browser deviate from the beaten track we
|
||||||
|
covered so far, specifically the use of QMake. The Morph browser
|
||||||
|
unconditionally depends on CMake as build tool. Even though we gathered
|
||||||
|
[https://genodians.org/nfeske/2019-11-25-goa - early experiences], with using
|
||||||
|
CMake for building Genode executables, we did not attempt using CMake for
|
||||||
|
complex Qt5 applications targeting Genode so far.
|
||||||
|
|
||||||
|
Finally, we discovered a so-called Ubuntu-Touch-UI toolkit as an
|
||||||
|
additional dependency over Qt5. It presumably extends Qt5's QML with
|
||||||
|
custom user-interface widgets for mobile user interfaces. In contrast
|
||||||
|
to the multi-platform Qt5 framework, Ubuntu Touch generally targets
|
||||||
|
Linux only, which raised a number of concerns with respect to hidden
|
||||||
|
assumptions on the underlying platform. For example, the expectation
|
||||||
|
of a certain service manager, the direct use of the Linux kernel interface,
|
||||||
|
or accidentally complex library dependencies.
|
||||||
|
|
||||||
|
|
||||||
|
Methodology
|
||||||
|
===========
|
||||||
|
|
||||||
|
As practiced during our work with bringing the Chromium-based Falkon web
|
||||||
|
browser to Genode, we took several intermediate steps to mitigate technical
|
||||||
|
risks as far as possible.
|
||||||
|
|
||||||
|
Pruning dependencies
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
The first step was building the Morph browser from source for its regular
|
||||||
|
designated target platform, namely Linux. This step allowed us to validate the
|
||||||
|
functionality of the browser built from source as opposed to merely testing a
|
||||||
|
binary package. During this process, we learned about the mandatory dependence
|
||||||
|
on CMake as build tool. We also identified the following library dependencies
|
||||||
|
as sources of uncertainty.
|
||||||
|
|
||||||
|
*Ubuntu-UI toolkit* is a collection of QML widgets for smartphone apps.
|
||||||
|
It is built via QMake and comes with its own set of dependencies.
|
||||||
|
We were specifically concerned by QtSystemInfo, QtOrganizer, D-Bus, and
|
||||||
|
gettext. Genode has no meaningful equivalent to any of these dependencies.
|
||||||
|
The *Ubuntu Themes* dependency comprises graphical assets, used on Ubuntu
|
||||||
|
Touch. *Ubuntu-UI extras* extends Qt's feature set by functionality like the
|
||||||
|
'TabsBar' QML-Widget introduces additional transitive dependencies
|
||||||
|
such as the [https://www.cups.org/ - CUPS printing system] or
|
||||||
|
the [https://exiv2.org/ - Exiv2] image metadata library.
|
||||||
|
|
||||||
|
Further dependencies worth noting are QNetworkInterface, QtConcurrent, QtDBus,
|
||||||
|
QtSystemInfo, unity-action-api, and D-Bus. Those libraries do not exist in
|
||||||
|
Genode and may even raise conceptual problems. For example, the D-Bus
|
||||||
|
inter-component mechanism on Linux is not in line with Genode's
|
||||||
|
capability-based inter-component communication.
|
||||||
|
|
||||||
|
With the first manually built executable of Morph created on Linux, we could
|
||||||
|
repeatedly remove dependencies piece by piece and validate the functioning of
|
||||||
|
the browser after each step. We ultimately reached a point where most of the
|
||||||
|
library dependencies could be cut off while the core functionality of the
|
||||||
|
browser - the ability to view web pages - stayed intact. The resulting
|
||||||
|
minimized version of the Morph browser thereby served as starting point for
|
||||||
|
the subsequent porting work to Genode.
|
||||||
|
|
||||||
|
Re-targeting to Genode
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
To stay as close as possible to the original browser, we decided to reuse the
|
||||||
|
browser's build system by tweaking the CMake build tool such that the project
|
||||||
|
could be cross compiled for Genode, similar to the approach we successfully
|
||||||
|
employed for QMake in the past. At first, we targeted Genode/Linux on x86,
|
||||||
|
which is still close to the browser's natural environment. Once the first
|
||||||
|
version of the browser came to life, we immediately cross-validated the result
|
||||||
|
on the 64-bit ARM architecture as this is our primary target. Subsequently, we
|
||||||
|
moved away from Linux by moving the browser over to NOVA (on Sculpt) on PC
|
||||||
|
hardware as well as our custom base-hw microkernel in order to target the
|
||||||
|
actual PinePhone.
|
||||||
|
|
||||||
|
[image touch_ui]
|
||||||
|
Ubuntu-Touch UI gallery demo running on Genode
|
||||||
|
|
||||||
|
The methodology mirrored in large parts the approach we took for the original
|
||||||
|
porting of the Chromium web engine, but it was a much smoother experience
|
||||||
|
given that all road blocks we encountered during our Chromium work are solved
|
||||||
|
problems by now. Image [touch_ui] shows the browser's underlying
|
||||||
|
user-interface tool kit in action, running directly on Genode. Image [morph]
|
||||||
|
shows the Morph browser hosted in Genode's window system.
|
||||||
|
|
||||||
|
[image morph]
|
||||||
|
Morph browser running on Genode
|
||||||
|
|
||||||
|
|
||||||
|
Unexpected caveats
|
||||||
|
==================
|
||||||
|
|
||||||
|
However, the smooth ride of re-targeting the browser to Genode ended once
|
||||||
|
we discovered the extremely poor interactive performance of the browser
|
||||||
|
running on Genode. This is in contrast to our prior experience with the
|
||||||
|
Chromium-based Falkon browser which achieved comparable performance to Linux.
|
||||||
|
|
||||||
|
The performance degradation originated from the Ubuntu-UI toolkit, which
|
||||||
|
has a hard dependency on OpenGL despite being built atop the Qt5 framework.
|
||||||
|
In several instances, the Ubuntu-UI toolkit accesses the OpenGL context
|
||||||
|
directly, which is handled by a software fallback implementation in the
|
||||||
|
Mesa library. We found the removal of those offending accesses infeasible
|
||||||
|
because this change would cause several widgets appearing incomplete.
|
||||||
|
To attain the visual completeness of the user interface, we also had to
|
||||||
|
enhance the Genode-specific back end of Qt (QPA). However, even though
|
||||||
|
we achieved correctly looking results, the performance of Mesa3D without
|
||||||
|
GPU acceleration made the user interface practically unusable, even on
|
||||||
|
powerful PC hardware, not speaking of the resource-constrained PinePhone.
|
||||||
|
We came to the conclusion that the Morph browser's hard dependency
|
||||||
|
on hardware-accelerated graphics cannot be worked around. This realization,
|
||||||
|
in turn, spawned the line of work reported in
|
||||||
|
Section [Hardware-accelerated graphics].
|
||||||
|
|
||||||
|
As another - but arguably much less dramatic - caveat, we found the touch user
|
||||||
|
interface behaving strangely in some situations when running on Genode. The
|
||||||
|
reason turned out to be a disparity of Genode's notion of touch-release events
|
||||||
|
from the expectations of Qt. Whereas Genode's input-event interface does not
|
||||||
|
report a positional value of a touch-release event, Qt expects a positional
|
||||||
|
value that corresponds to the original touch event. Fortunately, once this
|
||||||
|
disparity had been identified, we could easily emulate the expected behavior
|
||||||
|
locally in Genode's QPA plugin.
|
||||||
|
|
||||||
|
|
||||||
|
Hardware-accelerated graphics
|
||||||
|
=============================
|
||||||
|
|
||||||
|
As mentioned above, we were taken by surprise by the hard dependency of the
|
||||||
|
Morph browser on GPU-accelerated graphics. Even though we have explored the
|
||||||
|
principle use of a GPU on an ARM-based platform before, our prior line of work
|
||||||
|
was targeting the Vivante GPU of the NXP i.MX8 SoC, which is different from
|
||||||
|
the Mali-400 GPU as present in the PinePhone's A64 SoC. Originally, we did not
|
||||||
|
plan to deal with the PinePhone's GPU at the current stage. But the
|
||||||
|
requirement of the Morph browser abruptly changed our priorities.
|
||||||
|
|
||||||
|
As a rapid experiment, we took the challenge to port the Lima driver for the
|
||||||
|
Mali-400 GPU from Linux to Genode and combine it with the matching user-level
|
||||||
|
driver code of the Mesa library. Even though this experiment was pursued on
|
||||||
|
short notice and risky, it was at least a tangible straw. To our delight,
|
||||||
|
however, the first functional rapid prototype came to life after merely two
|
||||||
|
weeks of work, which is almost an order of magnitude faster than our past
|
||||||
|
efforts. The reason of this success is many-fold. First, our recently
|
||||||
|
established methodology and tooling for porting Linux device drivers - as
|
||||||
|
described in our comprehensive
|
||||||
|
[https://genode.org/documentation/genode-platforms-22-05.pdf - Porting Guide] -
|
||||||
|
streamlines the formerly labor-intensive grunt work. Second, we greatly
|
||||||
|
benefited from our practical experience with GPUs accumulated over the past
|
||||||
|
few years. And third, even though the Mali-400 is different from the Vivante
|
||||||
|
GPU, the integration into the Linux GPU stack follows very similar patterns,
|
||||||
|
unlike Intel GPUs. So we found our existing knowledge largely applicable.
|
||||||
|
|
||||||
|
[image glmark2]
|
||||||
|
GLMark2 reference application using the GPU
|
||||||
|
|
||||||
|
Following the initial rapid prototype, we successively refined this work to
|
||||||
|
the point where the GPU driver became usable for the Morph browser on the
|
||||||
|
PinePhone. Thanks to the added driver, the interactive performance got boosted
|
||||||
|
to an acceptable level.
|
||||||
|
|
||||||
|
|
||||||
|
Mobile data connectivity
|
||||||
|
========================
|
||||||
|
|
||||||
|
It goes without saying that a web browser requires network connectivity,
|
||||||
|
which is a topic we had left unaddressed on the PinePhone until now.
|
||||||
|
However, given our
|
||||||
|
[https://genode.org/documentation/release-notes/22.05#Telephony - recent line]
|
||||||
|
of modem-related work in the context of telephony, we foresaw a low-complexity
|
||||||
|
solution to attain mobile data connectivity.
|
||||||
|
|
||||||
|
Today's LTE modems offer
|
||||||
|
[https://genodians.org/ssumpf/2020-12-04-mbim - QMI or MBIM] protocol support
|
||||||
|
in order to configure and handle mobile data connections. Both protocols are
|
||||||
|
in binary format and require a separate USB device (called Wireless Mobile
|
||||||
|
Communication Device). For Genode, this would mean to add support for this
|
||||||
|
device to USB while additionally the QMI or MBIM library would have to be
|
||||||
|
ported and adjusted to Genode. For the
|
||||||
|
[https://www.quectel.com/product/lte-eg25-g - Quectel EG25 modem]
|
||||||
|
in the PinePhone, we found a much simpler solution to handle mobile data
|
||||||
|
connections. The modem can be configured to emulate a USB Ethernet device
|
||||||
|
([https://en.wikipedia.org/wiki/Ethernet_over_USB - ECM device]).
|
||||||
|
In this operational mode, the modem will automatically connect to the carrier
|
||||||
|
and register itself as USB Ethernet device at the PinePhone's USB host
|
||||||
|
controller. Genode can thereby access the device through the USB networking
|
||||||
|
and CDC Ethernet drivers. The modem also offers a DHCP server and will hand
|
||||||
|
out a local IP address upon a DHCP request to Genode. Internally the modem
|
||||||
|
will use [https://en.wikipedia.org/wiki/Network_address_translation - NAT] in
|
||||||
|
order to translate IP requests from Genode to the address received from the
|
||||||
|
carrier.
|
||||||
|
|
||||||
|
As a prerequisite to conduct this solution, we had to enable a USB
|
||||||
|
host-controller driver for the PinePhone. Of course, we took advantage of our
|
||||||
|
modern DDE Linux porting approach for this work, which allowed to attain a
|
||||||
|
functional USB driver in merely two weeks. This driver must be combined with
|
||||||
|
our existing USB Ethernet driver (usb_net) that we swiftly extended to support
|
||||||
|
ECM based devices.
|
||||||
|
|
||||||
|
With this driver infrastructure in place, the USB network device of the modem
|
||||||
|
appears as uplink to Genode's NIC router. The NIC router, in turn,
|
||||||
|
successfully obtains a local IP address that is network-translated by the
|
||||||
|
modem. At the carrier side, IP network connectivity can be established by
|
||||||
|
issuing AT-protocol commands over UART. So the first prototype of the
|
||||||
|
low-level network connectivity worked as anticipated. With this practical way
|
||||||
|
of keeping the complexity of binary configuration protocols out of the loop,
|
||||||
|
we can maintain the low-complexity implementation of telephony and SIM
|
||||||
|
configuration via the UART control channel while regarding IP connectivity -
|
||||||
|
and the unavoidable complexity of USB - as an entirely complementary feature.
|
||||||
|
|
||||||
|
|
||||||
|
Phone flavor of Sculpt OS
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Seeing the various puzzle pieces of the Morph browser scenario - GPU
|
||||||
|
acceleration, data connectivity, the browser itself - coming together, it was
|
||||||
|
time for the integration of those pieces into an overall system. The natural
|
||||||
|
basis of such a Genode-based system is
|
||||||
|
[https://genode.org/download/sculpt - Sculpt OS],
|
||||||
|
which complements Genode with universally expected operating-system features
|
||||||
|
such as interactive system configuration as well as the installation and
|
||||||
|
deployment of software packages.
|
||||||
|
|
||||||
|
Sculpt OS was originally designed for PC-based use cases. Its administrative
|
||||||
|
user interface is largely mouse and keyboard driven, and network connectivity
|
||||||
|
is usually attained by a wired or wireless LAN connection. Although we
|
||||||
|
presented a first version of
|
||||||
|
[https://fosdem.org/2022/schedule/event/nfeske/ - Sculpt OS on the PinePhone]
|
||||||
|
earlier this year, the call for a touch-oriented user interface is more than
|
||||||
|
obvious. Hence, we went forward with creating a phone-specific variant
|
||||||
|
of Sculpt. Similar to the original Sculpt OS, the system consists of two
|
||||||
|
largely isolated domains, the administrative domain called Leitzentrale and
|
||||||
|
the domain of user-installed components called desktop. The user can switch
|
||||||
|
between both domains at any time using a secure attention key or gesture.
|
||||||
|
On the phone, the Leitzentrale domain plays the role of a feature-phone
|
||||||
|
appliance that provides the most fundamental device functionality such
|
||||||
|
as the interaction with the SIM card, power control, telephony, network
|
||||||
|
configuration, storage management, and software installation. We approached
|
||||||
|
the concept of the user interface from a clean slate striving for simplicity.
|
||||||
|
|
||||||
|
[image sim_pin]
|
||||||
|
Emerging mobile-phone flavor of Sculpt OS
|
||||||
|
|
||||||
|
As the first use case, we addressed telephony, displaying incoming calls,
|
||||||
|
presenting the options for accepting/rejecting calls, and initiating calls
|
||||||
|
using a dial pad. By modelling these scenarios, we could validate the
|
||||||
|
user-interface concept of the evolving phone version of Sculpt's Leitzentrale.
|
||||||
|
|
||||||
|
|
||||||
|
User interaction with the SIM card
|
||||||
|
==================================
|
||||||
|
|
||||||
|
The administrative user interface mentioned above must be matched by the
|
||||||
|
underlying middleware that talks to the modem. Remember that our
|
||||||
|
[https://genode.org/documentation/release-notes/22.05#Telephony - original]
|
||||||
|
telephony scenario relied on the manual use of the modem's AT commands.
|
||||||
|
We ultimately have to control the modem's control channel by software using an
|
||||||
|
AT protocol stack. To bridge this gap with the lowest complexity possible, we
|
||||||
|
created a simple AT protocol implementation that is specifically designed for
|
||||||
|
Genode's state-driven component model.
|
||||||
|
The modem driver - hosting the AT protocol driver - accepts a configuration
|
||||||
|
that expresses the desired state (as opposed to desired actions). For example,
|
||||||
|
a configuration may look as simple as follows.
|
||||||
|
|
||||||
|
! <config speaker="yes" pin="1234">
|
||||||
|
! <call number="+49123123123"/>
|
||||||
|
! </config>
|
||||||
|
|
||||||
|
The AT protocol implementation takes this configuration and the current modem
|
||||||
|
state as the basis for determining a sequence of modem commands needed to
|
||||||
|
attain the desired state. For example, if the modem is not powered, the driver
|
||||||
|
steps through the powering sequence. Or in case the SIM PIN is required, the
|
||||||
|
driver supplies the corresponding command to supply the configured PIN.
|
||||||
|
|
||||||
|
To allow interactive usage, the driver supports dynamic reconfiguration.
|
||||||
|
E.g., to cancel the outbound call of the example above, the configuration
|
||||||
|
would be updated with the '<call>' node removed. Given this approach, an
|
||||||
|
interactive user interface comes down to generating such simple
|
||||||
|
configurations.
|
||||||
|
|
||||||
|
Vice versa, the driver exports the modem's state as a state report, which is
|
||||||
|
updated whenever the modem state changes. E.g., an incoming call is reflected
|
||||||
|
to the consumer of this state report with all information relevant for an
|
||||||
|
interactive user interface. For example, the state report entails the power
|
||||||
|
state, PIN state, and call states (incoming, outbound, alerting, rejected).
|
||||||
|
This design nicely hides the peculiarities of the AT protocol from Genode's
|
||||||
|
component interfaces.
|
||||||
|
|
||||||
|
At the current stage, with less than 1000 lines of code, the AT protocol
|
||||||
|
implementation suffices for basic telephony needs, supporting the interaction
|
||||||
|
with the SIM card, managing call states, initiating calls, and driving the
|
||||||
|
modem power up and down. It also takes care of establishing the modem
|
||||||
|
configuration needed for USB ECM networking.
|
||||||
|
|
||||||
|
|
||||||
|
Current state
|
||||||
|
=============
|
||||||
|
|
||||||
|
The current version of the phone variant of Sculpt OS is able to control the
|
||||||
|
power state of the modem, interact with the SIM card (PIN entry), initiate
|
||||||
|
phone calls via a dial pad, pick up inbound calls, establish mobile-data
|
||||||
|
network connectivity, and deploy a preconfigured application scenario.
|
||||||
|
The interactive switching between the base system and the application runtime
|
||||||
|
can be triggered at any time by touching the left border of the touch screen.
|
||||||
|
|
||||||
|
[image sculpt_pinephone]
|
||||||
|
The runtime graph of the base system (left) reveals the relationships of the
|
||||||
|
Morph browser with other components (right).
|
||||||
|
|
||||||
|
This flavor of Sculpt OS evolves in the
|
||||||
|
[https://github.com/nfeske/genode-allwinner - genode-allwinner] repository,
|
||||||
|
specifically within the _sculpt/_ and _src/app/phone_manager/_ directories.
|
||||||
|
The latter asserts the role of Sculpt's _gems/src/app/sculpt_manager_.
|
||||||
|
We invite seasoned developers - especially those who are following the
|
||||||
|
[https://genodians.org/nfeske/index - Pine-fun article series] - to experiment
|
||||||
|
with the new phone variant. It can be built via the following command:
|
||||||
|
|
||||||
|
! built/arm_v8a$ make run/sculpt KERNEL=hw BOARD=pinephone SCULPT=phone
|
||||||
|
|
||||||
|
For a broader audience, we plan to provide a ready-to-use SD-card image for
|
||||||
|
the PinePhone in tandem with the next release of Sculpt OS.
|
||||||
|
|
||||||
|
|
||||||
|
Enhanced tooling for system tracing
|
||||||
|
###################################
|
||||||
|
|
||||||
|
Since release 13.08, Genode features a
|
||||||
|
[https://genode.org/documentation/release-notes/13.08#Light-weight_event_tracing - light-weight event-tracing facility]
|
||||||
|
that comes in form of core's TRACE service. Up to now, it has merely been used
|
||||||
|
for capturing textual trace messages. The two prominent monitor components are
|
||||||
|
the
|
||||||
|
[https://genode.org/documentation/release-notes/18.02#New_trace-logging_component - trace_logger]
|
||||||
|
and the
|
||||||
|
[https://genode.org/documentation/release-notes/19.08#Tracing - VFS plugin]
|
||||||
|
|
||||||
|
The trace recorder is a new monitor component that is designed for binary trace
|
||||||
|
formats. Currently, it supports the Common Trace Format (CTF) and pcapng.
|
||||||
|
CTF is a compact and scalable format for storing event traces. It is supported
|
||||||
|
by [https://www.eclipse.org/tracecompass/ - TraceCompass], an Eclipse-based
|
||||||
|
tool for trace analysis and visualization. Pcapng is a packet-capture format
|
||||||
|
used by Wireshark.
|
||||||
|
|
||||||
|
In order to support capturing network packets, we added a 'trace_eth_packet()'
|
||||||
|
method to Genode's trace-policy API and equipped the NIC router with a
|
||||||
|
'trace_packets' option to control packet capturing on domain level. For manual
|
||||||
|
instrumentation of components, we also added a 'checkpoint()' method to the
|
||||||
|
trace-policy API.
|
||||||
|
|
||||||
|
For more details, please refer to the following Genodians article.
|
||||||
|
|
||||||
|
:Identifying network-throughput bottlenecks with trace recording:
|
||||||
|
|
||||||
|
[https://genodians.org/jschlatow/2022-08-29-trace-recorder]
|
||||||
|
|
||||||
|
|
||||||
|
Base framework and OS-level infrastructure
|
||||||
|
##########################################
|
||||||
|
|
||||||
|
Networking optimizations
|
||||||
|
========================
|
||||||
|
|
||||||
|
With the new trace recorder at hand, we took an effort in optimizing Genode's
|
||||||
|
network throughput. First, we implemented a benchmark component called
|
||||||
|
"nic_perf" that sends and/or receives an infinite stream of UDP packets in
|
||||||
|
order to stimulate the involved networking components in separation. As a
|
||||||
|
consequence of its central role, we particularly focused on the NIC router as
|
||||||
|
a starting point.
|
||||||
|
|
||||||
|
As a base line, we took two 'nic_perf' components: one as a sender and the other
|
||||||
|
as a receiver. By taking any copying or packet inspection out of the loop, we
|
||||||
|
could verify that the packet-stream interface holds up to our expectations with
|
||||||
|
respect to attainable throughput. However, as soon as we put a NIC router in
|
||||||
|
between, the throughput dropped to approx. 10% of our base line. On older
|
||||||
|
ThinkPads, this meant sub-gigabit throughput and on a Cortex-A9 @ 666MHz we
|
||||||
|
barely jumped over the 100Mbit mark.
|
||||||
|
|
||||||
|
Since we were not able to explain the substantial decrease in packet throughput,
|
||||||
|
we investigated with the help of the trace recorder and 'GENODE_LOG_TSC'.
|
||||||
|
As it turned out, the NIC router spent most of its time with exception handling
|
||||||
|
during routing-rule lookup, which is done for every packet. Since there are
|
||||||
|
multiple types of rules, a lookup takes place for every rule type. If no rule
|
||||||
|
was found for particular type, an exception was thrown and caught, which
|
||||||
|
turned out to be incredibly expensive. We therefore eliminated exceptions from
|
||||||
|
common-case code paths, more precisely from rule lookup, from ARP-cache
|
||||||
|
lookup, and from packet allocation. The result impressed us with a tripled
|
||||||
|
throughput.
|
||||||
|
|
||||||
|
Another bottleneck that we identified were frequent 'trigger_once' and
|
||||||
|
'elapsed_ms' RPCs. Given that the NIC router only maintains very
|
||||||
|
coarse-grained timeouts, such frequent RPCs to the timer seemed finical.
|
||||||
|
Sparing the details, we were able to significantly reduce the number of
|
||||||
|
these RPCs by relaxing the precision of the NIC router's time keeping.
|
||||||
|
|
||||||
|
Along the way, we identified a few more, minor, tweaks:
|
||||||
|
|
||||||
|
* We increased the default value of 'max_packets_per_signal' from 32 to 150.
|
||||||
|
This value determines the maximum number of packets that are consumed from an
|
||||||
|
interface at once.
|
||||||
|
* We eliminated eager packet-stream signalling from the NIC router to improve
|
||||||
|
batch processing of packets. With this change, packet-stream signals are only
|
||||||
|
emitted once the NIC router processed all available or
|
||||||
|
'max_packets_per_signal' packets.
|
||||||
|
* We implemented incremental checksum update for UDP/TCP according to RFC1071.
|
||||||
|
* We discovered and fixed a few corner cases in the packet-stream interface
|
||||||
|
with respect to the signalling.
|
||||||
|
* We fixed allocation errors in the 'ipxe_nic_drv' that popped up during high
|
||||||
|
TX load.
|
||||||
|
|
||||||
|
In the end, we attained a ~5x speed up (exact values depending on the hardware)
|
||||||
|
for the NIC router.
|
||||||
|
|
||||||
|
|
||||||
|
Event-filter improvements for touch devices
|
||||||
|
===========================================
|
||||||
|
|
||||||
|
The phone variant of Sculpt OS calls for a way to trigger certain low-level
|
||||||
|
buttons or keys using the touch screen. In particular, the switch between the
|
||||||
|
administrative user interface and the runtime system must be possible at any
|
||||||
|
time. On the [https://genode.org/download/sculpt - PC version], this switch
|
||||||
|
is triggered by pressing F12, which is remapped to KEY_DASHBOARD. Even though
|
||||||
|
a physical button could be used on the phone in principle, there are three
|
||||||
|
arguments in favor of a virtual key. First, there are only three physical
|
||||||
|
buttons available (volume +/- and power) on the PinePhone. Remapping one of
|
||||||
|
those buttons to KEY_DASHBOARD deprives the button of its original purpose.
|
||||||
|
Second, the force needed for pressing a physical button may impede the
|
||||||
|
ergonomics of the device depending on how often the switch is needed. And
|
||||||
|
third, the physical buttons require a driver. When enabling a new device, this
|
||||||
|
barrier can be nicely sidestepped by a virtual key.
|
||||||
|
|
||||||
|
Given this rationale, we extended Genode's event-filter component with a new
|
||||||
|
'<touch-key>' filter type. Once added to the filter chain, it triggers an
|
||||||
|
artificial key tap (a press event followed by a release event) whenever the
|
||||||
|
user touches a preconfigured area on the touch screen. The filter node can
|
||||||
|
host any number of '<tap>' sub nodes. Each sub node must define a rectangular
|
||||||
|
area - using the attributes 'xpos', 'ypos', 'width', and 'height' - and the
|
||||||
|
name of the tapped key as 'key' attribute.
|
||||||
|
|
||||||
|
! <touch-key>
|
||||||
|
! <tap xpos="0" ypos="400" width="25" height="600" key="KEY_DASHBOARD"/>
|
||||||
|
! ...
|
||||||
|
! </touch-key>
|
||||||
|
|
||||||
|
The example above repurposes the 25 left-most pixels of the touch screen as
|
||||||
|
dashboard key. When touched, a pair of press and release events is fired at
|
||||||
|
once.
|
||||||
|
|
||||||
|
|
||||||
|
Menu-view performance
|
||||||
|
=====================
|
||||||
|
|
||||||
|
The administrative user interface of Sculpt OS is based on Genode's custom
|
||||||
|
menu-view component, which renders and updates graphical dialogs based on
|
||||||
|
high-level XML descriptions. Up to now, the component operated on Genode's
|
||||||
|
GUI-session interface with alpha-channel support. However, the alpha channel
|
||||||
|
noticeably impedes the software-rendering performance on lower-end devices
|
||||||
|
like the PinePhone. In the latter case, we'd prefer to trade the nice-looking
|
||||||
|
alpha blending for a better UI responsiveness.
|
||||||
|
|
||||||
|
We have now enhanced the menu-view component with two new optional
|
||||||
|
configuration attributes 'opaque' and 'background'. Setting 'opaque' to "yes"
|
||||||
|
suppresses the use of the alpha channel at the GUI session. This improves the
|
||||||
|
drawing performance by 20% on the PinePhone. The 'background' attribute can be
|
||||||
|
specified to define the reset color of the GUI buffer. It alleviates the need
|
||||||
|
to create a frame widget for the top level, significantly reducing the costs
|
||||||
|
for drawing the background pixels.
|
||||||
|
|
||||||
|
Finally, we found that the use of GCC's optimization level -O3 instead of the
|
||||||
|
default level -O2 increases the drawing performance on the PinePhone by 30%.
|
||||||
|
Combined, those optimizations result in an acceptable user experience of
|
||||||
|
Sculpt's administrative user interface on the PinePhone.
|
||||||
|
|
||||||
|
|
||||||
|
Device drivers
|
||||||
|
##############
|
||||||
|
|
||||||
|
USB networking via Ethernet control model (ECM)
|
||||||
|
===============================================
|
||||||
|
|
||||||
|
To implement mobile data connectivity on the PinePhone
|
||||||
|
(Section [Mobile data connectivity]), we added USB host-controller support
|
||||||
|
(EHCI) for the Allwinner A64 SoC to Genode by porting the corresponding
|
||||||
|
host-controller driver from Linux using our DDE approach. Since our existing
|
||||||
|
USB-over-Ethernet
|
||||||
|
[https://github.com/genodelabs/genode/tree/master/repos/dde_linux/src/drivers/usb_net - driver]
|
||||||
|
on Genode lacked support for the Ethernet Control Model, which is provided by
|
||||||
|
the modem, we added support for ECM as well.
|
||||||
|
|
||||||
|
|
||||||
|
GPU and Mesa driver for Mali-400
|
||||||
|
================================
|
||||||
|
|
||||||
|
As mentioned in Section [Genode coming to the phone], we enabled the principle
|
||||||
|
ability to use the Mali-400 GPU of the PinePhone under Genode. This support
|
||||||
|
entails two parts. The first part is the low-level driver code called Lima
|
||||||
|
that normally resides in the Linux kernel. This component provides a GPU
|
||||||
|
session interface. We transplanted the driver code to a dedicated Genode
|
||||||
|
component, which is hosted at the
|
||||||
|
[https://github.com/genodelabs/genode-allwinner - genode-allwinner] repository.
|
||||||
|
The second part is the user-level Mesa3D driver stack - hosted at the libports
|
||||||
|
repository - that is linked local to the application and uses the GPU session
|
||||||
|
to access the GPU.
|
||||||
|
|
||||||
|
The combination of both parts was successfully tested on the PinePhone and
|
||||||
|
the Pine-A64-LTS V1.2 board. Given that the primary motivation for this
|
||||||
|
line of work was our ambition to run the Morph web browser, we disregarded the
|
||||||
|
multiplexing of the GPU for now. The GPU driver currently supports only one
|
||||||
|
client at a time.
|
||||||
|
|
||||||
|
|
||||||
|
SD-card driver for the PinePhone
|
||||||
|
================================
|
||||||
|
|
||||||
|
In anticipation of running Sculpt OS on the PinePhone, we ported the Linux
|
||||||
|
SD/MMC-card driver to Genode. The driver - hosted at the
|
||||||
|
[https://github.com/genodelabs/genode-allwinner - genode-allwinner] repository -
|
||||||
|
was successfully tested with the PinePhone and Pine-A64LTS V1.2 board. For the
|
||||||
|
moment, only SD cards (no eMMC) are supported.
|
||||||
|
The provided _a64_sd_card_drv.run_ script illustrates the integration and use
|
||||||
|
of the driver.
|
||||||
|
|
||||||
|
|
||||||
|
Linux-device-driver environment (DDE Linux)
|
||||||
|
===========================================
|
||||||
|
|
||||||
|
Tickless idle operation
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
The DDE-Linux emulation library and thereby all ported drivers now support
|
||||||
|
the NO_HZ_IDLE Linux kernel configuration option, which disables periodic
|
||||||
|
timer ticks when ported drivers are idle. With this option, energy and up to
|
||||||
|
3% CPU time per driver can be preserved, which becomes significant especially
|
||||||
|
if multiple ported drivers are in use in sophisticated scenarios like Sculpt
|
||||||
|
OS.
|
||||||
|
|
||||||
|
Consistent use of SMP configuration
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
All kernel threads in the Linux device driver ports are currently mapped to one
|
||||||
|
and the same native Genode thread, using cooperative scheduling within the
|
||||||
|
emulation environment. Intuitively, it does not make much sense to address
|
||||||
|
multi-processing support provided by the original Linux kernel code.
|
||||||
|
Nonetheless, the drivers that we ported are normally used in the context of
|
||||||
|
SMP-aware Linux kernel configurations only. To not leave the well tested and
|
||||||
|
beaten track, we decided to switch on SMP support in all kernel configurations
|
||||||
|
we use as porting base.
|
||||||
|
|
||||||
|
This especially applies to the Linux drivers within the _repos/pc_
|
||||||
|
sub-directory, and the WireGuard port. Other driver ports already used SMP
|
||||||
|
support in their configuration.
|
||||||
|
|
||||||
|
As a side effect, we removed the insufficient emulation of so called "softirqs"
|
||||||
|
formerly used by the non-SMP driver ports, and replaced them with the original
|
||||||
|
implementation.
|
||||||
|
|
||||||
|
|
||||||
|
Forthcoming platform-driver modernization
|
||||||
|
=========================================
|
||||||
|
|
||||||
|
During the past year, we switched from board-specific platform driver APIs
|
||||||
|
step-by-step to one generic interface. But PC-related drivers still depend on
|
||||||
|
the legacy x86-specific platform driver and API, especially to the PCI-related
|
||||||
|
part of it.
|
||||||
|
|
||||||
|
To finalize the unification and modernization of the platform driver and its
|
||||||
|
API, there were still some pieces missing, which we added with the current
|
||||||
|
release.
|
||||||
|
|
||||||
|
While trying to switch PC-related Linux device driver ports to the new API, we
|
||||||
|
recognized that some drivers depend on additional information of the PCI
|
||||||
|
configuration space that were not exported so far. Namely, the fields for
|
||||||
|
sub-vendor, sub-product, and revision IDs were needed. Moreover, some ported
|
||||||
|
drivers use hard-coded indices of PCI base-address registers (BAR) to refer to
|
||||||
|
I/O resources of the device.
|
||||||
|
|
||||||
|
Therefore, we extended the pci_decode tool to export this additional
|
||||||
|
information, and to annotate I/O port ranges and memory attributes with the
|
||||||
|
corresponding BAR index. The generic platform driver parses this additional
|
||||||
|
information from a given devices ROM, and exports it to the corresponding
|
||||||
|
clients accordingly. The correlation between I/O resources and BAR indices is
|
||||||
|
only unveiled to clients where the platform driver's policy states that
|
||||||
|
physical information has to be provided, like in this example:
|
||||||
|
|
||||||
|
! <config>
|
||||||
|
! <policy label="usb_drv -> " info="yes">
|
||||||
|
! <pci class="USB"/>
|
||||||
|
! </policy>
|
||||||
|
! ...
|
||||||
|
! </config>
|
||||||
|
|
||||||
|
UHCI-specific platform extensions
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
Some device-specific registers are only present within the PCI configuration
|
||||||
|
space. For instance UHCI controllers in the PC architecture provide a special
|
||||||
|
legacy support register only accessible via the PCI configuration space. This
|
||||||
|
register is used to hand over the USB hardware from the BIOS to the operating
|
||||||
|
system.
|
||||||
|
|
||||||
|
We did not want to pollute the platform API with a lot of device specific
|
||||||
|
tweaks nor provide unlimited access to the PCI configuration space to a
|
||||||
|
driver. Therefore, we implement the hand-over of the UHCI PCI device in the
|
||||||
|
platform driver if available. Moreover, we handle the Intel-specific resume
|
||||||
|
register whenever a session to the corresponding UHCI controller is opened.
|
||||||
|
|
||||||
|
Intel GPU information from Host Bridge
|
||||||
|
--------------------------------------
|
||||||
|
|
||||||
|
Some information needed by Intel GPU and framebuffer drivers is derived from
|
||||||
|
the Intel Graphics and Controller HUB (GMCH) respectively its control
|
||||||
|
register. It is used to calculate the GPU's Global Translation Table (GTT),
|
||||||
|
and the stolen memory sizes. Again we do not want to give access to the whole
|
||||||
|
configuration space of this sensitive device to either the GPU or the
|
||||||
|
framebuffer driver. Instead, the platform driver now detects Intel PCI graphic
|
||||||
|
cards, and exports the information found within the GMCH control register to
|
||||||
|
the corresponding client as part of the platform session's devices ROM.
|
||||||
|
|
||||||
|
Transition of PC drivers
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
Although there is everything in place now to switch the remaining PC-drivers
|
||||||
|
to the generic platform driver and its API, we decided to do this step after
|
||||||
|
the current release. This way, we have time to stress-test the drivers during
|
||||||
|
our daily use of Genode, the remaining transitional work is planned for the
|
||||||
|
upcoming Sculpt OS release instead.
|
||||||
|
|
||||||
|
|
||||||
|
Libraries and applications
|
||||||
|
##########################
|
||||||
|
|
||||||
|
Qt5 and Morph browser
|
||||||
|
=====================
|
||||||
|
|
||||||
|
As mentioned in Section [Genode coming to the phone], we had to improve
|
||||||
|
Genode's Qt support to get the Morph browser to work. This work includes
|
||||||
|
added support for building Qt projects with CMake, the addition of missing Qt
|
||||||
|
modules like QtGraphicalEffects, and improving the OpenGL support of the QPA
|
||||||
|
plugin. The latter was needed for the Ubuntu UI Toolkit to display its widgets
|
||||||
|
correctly. Note that this change implies that QtQuick applications now use
|
||||||
|
OpenGL by default instead of the QtQuick software rendering fallback back end.
|
||||||
|
This can improve the experience when an accelerated GPU driver is available
|
||||||
|
but can also slow down a QtQuick application if only the Mesa software driver
|
||||||
|
('softpipe') is available on the target platform. In that case, it is possible
|
||||||
|
to enforce the use of the software QtQuick renderer by setting the following
|
||||||
|
environment variable in the configuration of the application:
|
||||||
|
|
||||||
|
! <env key="QT_QUICK_BACKEND" value="software"/>
|
||||||
|
|
||||||
|
When we tried to use the free public Jitsi server at [https://meet.jit.si] with
|
||||||
|
our ported web browsers, we noticed that our QtWebEngine Chromium version was
|
||||||
|
too old and caused issues like a non-working join button and failed WebRTC
|
||||||
|
connections. For this reason, we updated our Qt port to the latest version with
|
||||||
|
QtWebEngine support on FreeBSD, which at this time is version 5.15.2.
|
||||||
|
|
||||||
|
To use this new version, it is necessary to update the Qt5 host tools with the
|
||||||
|
'tool/tool_chain_qt5' script.
|
||||||
|
|
||||||
|
We also updated the Falkon web browser to the latest version 3.2.0.
|
||||||
|
|
||||||
|
Up-to-date Sculpt packages of both the Falkon and Morph browsers for x86_64 are
|
||||||
|
available in the 'cproc' depot.
|
||||||
|
|
||||||
|
|
||||||
|
USB smart cards via PKCS#11
|
||||||
|
===========================
|
||||||
|
|
||||||
|
With this release, Genode gains support for accessing USB smart-card devices
|
||||||
|
via PKCS#11. This is achieved through a port of the OpenSC PKCS#11 tool that is
|
||||||
|
now available as package for the Sculpt OS. A quick look into the features and
|
||||||
|
integration of the tool is possible using the new _pkcs11_tool_ run script
|
||||||
|
hosted in the [https://github.com/genodelabs/genode-world - genode-world]
|
||||||
|
repository. For a more detailed guide to the tool, you may read the
|
||||||
|
corresponding Genodians article.
|
||||||
|
|
||||||
|
:USB smart cards via PKCS#11:
|
||||||
|
|
||||||
|
[https://genodians.org/m-stein/2022-08-18-pkcs11-tool-1]
|
||||||
|
|
||||||
|
|
||||||
|
Sculpt OS improvements
|
||||||
|
======================
|
||||||
|
|
||||||
|
In addition to the major developments described in
|
||||||
|
Section [Genode coming to the phone], Sculpt OS has received several minor
|
||||||
|
refinements.
|
||||||
|
|
||||||
|
When integrating a
|
||||||
|
[https://genode.org/documentation/release-notes/22.02#Framework_for_special-purpose_Sculpt-based_operating_systems - Sculpt-based appliance]
|
||||||
|
with a predefined deploy configuration, the _sculpt.run_ script automatically
|
||||||
|
adds the required software packages as tar archive to the boot image. However,
|
||||||
|
for complex scenarios, it is sometimes desirable to keep the boot image small
|
||||||
|
and fetch the packages at runtime over the network. To support such use cases,
|
||||||
|
we added the new run-script argument 'DEPOT' with the possible values 'tar'
|
||||||
|
(default) and 'omit'. If the latter is specified, the deployed software
|
||||||
|
packages are excluded from the boot image and the run script merely prints the
|
||||||
|
versions of the required packages. This information can conveniently be used
|
||||||
|
as input for publishing the packages.
|
||||||
|
|
||||||
|
We added two new packages 'part_block' and 'ext2_fs' that simplify the access
|
||||||
|
of multiple block devices and partitions in manually curated deploy
|
||||||
|
configurations. The part_block package can be used in Sculpt's
|
||||||
|
_/config/deploy_ as follows.
|
||||||
|
|
||||||
|
! <start name="nvme-0.part_block" pkg="part_block">
|
||||||
|
! <route>
|
||||||
|
! <service name="Block">
|
||||||
|
! <parent label="nvme-0"/>
|
||||||
|
! </service>
|
||||||
|
! <service name="Report" label="partitions">
|
||||||
|
! <parent/>
|
||||||
|
! </service>
|
||||||
|
! </route>
|
||||||
|
! </start>
|
||||||
|
|
||||||
|
It can be combined with the 'ext2_fs' package to access the files stored on a
|
||||||
|
particular partition.
|
||||||
|
|
||||||
|
! <start name="nvme-0.4.fs" pkg="ext2_fs">
|
||||||
|
! <route>
|
||||||
|
! <service name="Block">
|
||||||
|
! <child name="nvme-0.part_block" label="4"/>
|
||||||
|
! </service>
|
||||||
|
! <service name="RM">
|
||||||
|
! <parent/>
|
||||||
|
! </service>
|
||||||
|
! </route>
|
||||||
|
! </start>
|
||||||
|
|
||||||
|
|
||||||
|
Platforms
|
||||||
|
#########
|
||||||
|
|
||||||
|
Qemu virtual platform
|
||||||
|
=====================
|
||||||
|
|
||||||
|
Because more and more architectures on Genode now support VirtIO drivers on
|
||||||
|
Qemu (ARMv7, ARMv8, and RISC-V), the generic board name "virt_qemu" did not
|
||||||
|
suffice for keeping a clean distinction between the separate architecture
|
||||||
|
requirements. Therefore, we decided to make the board name architecture
|
||||||
|
specific. The following board names are now supported on base-hw:
|
||||||
|
"virt_qemu_arm_v7a", "virt_qemu_arm_v8a", and "virt_qemu_riscv".
|
||||||
|
The "virt_qemu" board name was removed.
|
||||||
|
|
||||||
|
|
||||||
|
RISC-V
|
||||||
|
======
|
||||||
|
|
||||||
|
As suggested above Genode's RISC-V support got extended by VirtIO drivers.
|
||||||
|
This includes a block driver, a networking driver, keyboard and mouse handling
|
||||||
|
as well as basic framebuffer support. This way, it has become possible to test
|
||||||
|
interactive and networking scenarios on Genode's RISC-V version using Qemu.
|
||||||
|
|
||||||
|
This work was contributed by Piotr Tworek. Thanks a lot!
|
||||||
|
|
||||||
|
|
||||||
|
Allwinner A64
|
||||||
|
=============
|
||||||
|
|
||||||
|
In the
|
||||||
|
[https://genode.org/documentation/release-notes/22.05#Custom_system-control_processor__SCP__firmware - previous release],
|
||||||
|
we introduced our custom firmware for the PinePhone's system-control processor
|
||||||
|
(SCP). We have now generalized the firmware to cover also the Pine-A64-LTS
|
||||||
|
board. By establishing our custom SCP firmware as a base line for all A64-based
|
||||||
|
boards, we can make our A64 platform driver depend on the SCP for accessing the
|
||||||
|
PMIC (power management chip) instead of driving the RSB and PMIC by itself.
|
||||||
|
|
||||||
|
|
||||||
|
Build system and tools
|
||||||
|
######################
|
||||||
|
|
||||||
|
In this release, we improve support for booting Genode/Sculpt on UEFI
|
||||||
|
platforms in several aspects. First, the Bender tool gains a more robust
|
||||||
|
UEFI-boot detection mechanism while retrieving serial-device parameters. Also,
|
||||||
|
the GRUB boot loader was updated to version 2.06 and now keeps lower RAM
|
||||||
|
untouched from internal memory allocations, which prevents nasty surprises on
|
||||||
|
booting some UEFI devices. And last, our [https://ipxe.org/ - iPXE-based] boot
|
||||||
|
option received support for UEFI images when using the following run-tool
|
||||||
|
configuration.
|
||||||
|
|
||||||
|
! RUN_OPT += --include image/uefi
|
||||||
|
! RUN_OPT += --include load/ipxe
|
||||||
|
|
||||||
@@ -21,6 +21,5 @@ content:
|
|||||||
for spec in x86_32; do \
|
for spec in x86_32; do \
|
||||||
mv lib/mk/spec/$$spec/ld-fiasco.mk lib/mk/spec/$$spec/ld.mk; \
|
mv lib/mk/spec/$$spec/ld-fiasco.mk lib/mk/spec/$$spec/ld.mk; \
|
||||||
done;
|
done;
|
||||||
sed -i "s/ld-fiasco/ld/" src/lib/ld/fiasco/target.mk
|
|
||||||
sed -i "s/fiasco_timer_drv/timer/" src/timer/fiasco/target.mk
|
sed -i "s/fiasco_timer_drv/timer/" src/timer/fiasco/target.mk
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2022-05-24 1790ce242c001ed77aab9695f69923a44d1dc1d1
|
2022-10-11 1f0607de6493bad0e47b24e66d84474652e8b6be
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
TARGET = ld-fiasco
|
|
||||||
LIBS = ld-fiasco
|
|
||||||
@@ -1 +1 @@
|
|||||||
2022-05-24 f7900083623a2009d35234c47d2475dea8f6cf53
|
2022-10-11 d258920f8664460c78eeea25fafb89eaa5e7adf5
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2022-05-24 f7d228f6419c2fc9b1b0faf4ba8d88862ba61e81
|
2022-10-11 1c94d29566bccccced246eeaf90702348e2b1a7f
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2022-05-24 391b798b7c1d1b44ff65d855980eb41a8f4a87c1
|
2022-10-11 2668fd23d5cbd45b8f632073fc7c155f96ecb848
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2022-05-24 79eab679e71dd70803b0e1647a23e2ba86c76f50
|
2022-10-11 8da054ff9e4c37895816fd30857b3c42d9e75eb0
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2022-05-24 7a16aeb081d1392c36d83f526936f17cc9560442
|
2022-10-11 f41df6b57d2c4b090a84427e02950df84fb385ad
|
||||||
|
|||||||
@@ -39,5 +39,4 @@ content:
|
|||||||
for spec in x86_32 x86_64 arm arm_64; do \
|
for spec in x86_32 x86_64 arm arm_64; do \
|
||||||
mv lib/mk/spec/$$spec/ld-foc.mk lib/mk/spec/$$spec/ld.mk; \
|
mv lib/mk/spec/$$spec/ld-foc.mk lib/mk/spec/$$spec/ld.mk; \
|
||||||
done;
|
done;
|
||||||
sed -i "s/ld-foc/ld/" src/lib/ld/foc/target.mk
|
|
||||||
sed -i "s/foc_timer_drv/timer/" src/timer/foc/target.mk
|
sed -i "s/foc_timer_drv/timer/" src/timer/foc/target.mk
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
TARGET = ld-foc
|
|
||||||
LIBS = ld-foc
|
|
||||||
@@ -1,2 +1 @@
|
|||||||
arm_v7a
|
arm_v7a
|
||||||
arm_v8a
|
|
||||||
1
repos/base-hw/board/virt_qemu_arm_v8a/arch
Normal file
1
repos/base-hw/board/virt_qemu_arm_v8a/arch
Normal file
@@ -0,0 +1 @@
|
|||||||
|
arm_v8a
|
||||||
1
repos/base-hw/board/virt_qemu_arm_v8a/image_link_address
Normal file
1
repos/base-hw/board/virt_qemu_arm_v8a/image_link_address
Normal file
@@ -0,0 +1 @@
|
|||||||
|
0x40000000
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
REP_INC_DIR += src/bootstrap/board/virt_qemu
|
REP_INC_DIR += src/bootstrap/board/virt_qemu_arm_v7a
|
||||||
|
|
||||||
SRC_CC += bootstrap/board/virt_qemu/platform.cc
|
SRC_CC += bootstrap/board/virt_qemu_arm_v7a/platform.cc
|
||||||
SRC_CC += bootstrap/spec/arm/arm_v7_cpu.cc
|
SRC_CC += bootstrap/spec/arm/arm_v7_cpu.cc
|
||||||
SRC_CC += bootstrap/spec/arm/cortex_a15_cpu.cc
|
SRC_CC += bootstrap/spec/arm/cortex_a15_cpu.cc
|
||||||
SRC_CC += bootstrap/spec/arm/gicv2.cc
|
SRC_CC += bootstrap/spec/arm/gicv2.cc
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
REP_INC_DIR += src/core/board/virt_qemu
|
REP_INC_DIR += src/core/board/virt_qemu_arm_v7a
|
||||||
REP_INC_DIR += src/core/spec/arm/virtualization
|
REP_INC_DIR += src/core/spec/arm/virtualization
|
||||||
|
|
||||||
# add C++ sources
|
# add C++ sources
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
REP_INC_DIR += src/bootstrap/board/virt_qemu_64
|
REP_INC_DIR += src/bootstrap/board/virt_qemu_arm_v8a
|
||||||
|
|
||||||
SRC_CC += bootstrap/spec/arm/gicv3.cc
|
SRC_CC += bootstrap/spec/arm/gicv3.cc
|
||||||
SRC_CC += bootstrap/spec/arm_64/cortex_a53_mmu.cc
|
SRC_CC += bootstrap/spec/arm_64/cortex_a53_mmu.cc
|
||||||
SRC_CC += bootstrap/board/virt_qemu_64/platform.cc
|
SRC_CC += bootstrap/board/virt_qemu_arm_v8a/platform.cc
|
||||||
SRC_CC += lib/base/arm_64/kernel/interface.cc
|
SRC_CC += lib/base/arm_64/kernel/interface.cc
|
||||||
SRC_CC += spec/64bit/memory_map.cc
|
SRC_CC += spec/64bit/memory_map.cc
|
||||||
SRC_S += bootstrap/spec/arm_64/crt0.s
|
SRC_S += bootstrap/spec/arm_64/crt0.s
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
REP_INC_DIR += src/core/board/virt_qemu_64
|
REP_INC_DIR += src/core/board/virt_qemu_arm_v8a
|
||||||
REP_INC_DIR += src/core/spec/arm/virtualization
|
REP_INC_DIR += src/core/spec/arm/virtualization
|
||||||
|
|
||||||
# add C++ sources
|
# add C++ sources
|
||||||
@@ -4,6 +4,6 @@ SRC_CC += timer_connection_time.cc
|
|||||||
SRC_CC += hw/timer_connection_timestamp.cc
|
SRC_CC += hw/timer_connection_timestamp.cc
|
||||||
SRC_CC += duration.cc
|
SRC_CC += duration.cc
|
||||||
|
|
||||||
INC_DIR += $(BASE_DIR)/src/include
|
REP_INC_DIR += src/include
|
||||||
|
|
||||||
vpath % $(BASE_DIR)/src/lib/timeout
|
vpath % $(call select_from_repositories,src/lib/timeout)
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2022-05-24 ab1cb582165e76bda4abf27870f44ad7d1ae5b6d
|
2022-10-11 50db06fe21eca6c46c9b4bf7fcbc81538ac74f32
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
CONTENT += src/core/board/imx53_qsb \
|
CONTENT += src/core/board/imx53_qsb \
|
||||||
src/bootstrap/board/imx53_qsb
|
src/bootstrap/board/imx53_qsb \
|
||||||
|
lib/mk/spec/arm_v7/core-hw-imx53_qsb.inc \
|
||||||
|
lib/mk/spec/arm_v7/bootstrap-hw-imx53_qsb.inc
|
||||||
|
|
||||||
include $(GENODE_DIR)/repos/base-hw/recipes/src/base-hw_content.inc
|
include $(GENODE_DIR)/repos/base-hw/recipes/src/base-hw_content.inc
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2022-05-24 0fff6ce83b962b3fd54cf6eda0a157cb0cb0c9d5
|
2022-10-11 1377d3a2b7afaa265cc5ae6bbd515679be527c40
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2022-05-24 8c17512664a648eaed876c815ea678770eda3280
|
2022-10-11 c32cf899ce00bd69aff5bbd4f7b6b611d2bfa47d
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2022-05-24 edc396d9bc9a2ebf73590e70c1363020226909be
|
2022-10-11 39ff297bc573b8e8bf4f2e6e233bf0b1b21f13af
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2022-05-24 da90478c4c0b8993041bc59488eedb124e680e78
|
2022-10-11 f5456c3ed55b53ccaefee603fdb8d9b1e3ca84ab
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2022-05-24 1b34e317209c48bfc88af6118db32be261ce3e0c
|
2022-10-11 de2f50d9164952dbbf6ce76d29abad5d96da8512
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2022-05-24 46e9f88209bbc95228d3882cc0831770315402e4
|
2022-10-11 5d72eb4e34f582c06c086345b225cee91ce539cc
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
CONTENT += src/core/board/virt_qemu_64 \
|
|
||||||
src/bootstrap/board/virt_qemu_64
|
|
||||||
|
|
||||||
include $(GENODE_DIR)/repos/base-hw/recipes/src/base-hw_content.inc
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
2022-05-24 bb6c39c093a24d2ec4ff1d00e397529c51e95fa7
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
CONTENT += src/core/board/virt_qemu_arm_v7a \
|
||||||
|
src/bootstrap/board/virt_qemu_arm_v7a
|
||||||
|
|
||||||
|
include $(GENODE_DIR)/repos/base-hw/recipes/src/base-hw_content.inc
|
||||||
1
repos/base-hw/recipes/src/base-hw-virt_qemu_arm_v7a/hash
Normal file
1
repos/base-hw/recipes/src/base-hw-virt_qemu_arm_v7a/hash
Normal file
@@ -0,0 +1 @@
|
|||||||
|
2022-10-11 70e53c98ef4b3215440efb2ea09e07ff7cd97c4f
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
CONTENT += src/core/board/virt_qemu_arm_v8a \
|
||||||
|
src/bootstrap/board/virt_qemu_arm_v8a
|
||||||
|
|
||||||
|
include $(GENODE_DIR)/repos/base-hw/recipes/src/base-hw_content.inc
|
||||||
1
repos/base-hw/recipes/src/base-hw-virt_qemu_arm_v8a/hash
Normal file
1
repos/base-hw/recipes/src/base-hw-virt_qemu_arm_v8a/hash
Normal file
@@ -0,0 +1 @@
|
|||||||
|
2022-10-11 c146d70c9bde3f928110c868a54b8c800beffd79
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
base-hw
|
||||||
|
base
|
||||||
@@ -115,6 +115,12 @@ SRC_LIB_BASE += $(notdir $(wildcard $(BASE_HW_DIR)/src/lib/base/*.cc)) \
|
|||||||
$(notdir $(wildcard $(BASE_DIR)/src/lib/base/*.cc)) \
|
$(notdir $(wildcard $(BASE_DIR)/src/lib/base/*.cc)) \
|
||||||
${call selected_content,SRC_LIB_BASE_SPECS}
|
${call selected_content,SRC_LIB_BASE_SPECS}
|
||||||
|
|
||||||
|
SRC_LIB_TIMEOUT += duration.cc \
|
||||||
|
hw/timer_connection_timestamp.cc \
|
||||||
|
timeout.cc \
|
||||||
|
timer_connection.cc \
|
||||||
|
timer_connection_time.cc
|
||||||
|
|
||||||
SRC_LIB_STARTUP += init_main_thread.cc _main.cc \
|
SRC_LIB_STARTUP += init_main_thread.cc _main.cc \
|
||||||
$(addprefix spec/,${call selected_content,SRC_LIB_STARTUP_SPECS})
|
$(addprefix spec/,${call selected_content,SRC_LIB_STARTUP_SPECS})
|
||||||
|
|
||||||
@@ -125,15 +131,24 @@ SRC_CORE += $(notdir $(wildcard $(BASE_HW_DIR)/src/core/*.cc)) \
|
|||||||
$(addprefix board/,$(BOARD)) \
|
$(addprefix board/,$(BOARD)) \
|
||||||
version.inc target.inc include hw kernel
|
version.inc target.inc include hw kernel
|
||||||
|
|
||||||
LIB_MK := base-hw-common.mk base-hw.mk bootstrap-hw.inc core-hw.inc \
|
# names of the lib/mk/ files to consider for inclusion in the src archive
|
||||||
timeout-hw.mk cxx.mk base.inc base-common.inc startup.inc \
|
LIB_MK_FILES := base-common.inc base-hw-common.mk \
|
||||||
$(addprefix spec/,${call selected_content,LIB_MK_SPECS})
|
base.inc base-hw.mk \
|
||||||
|
bootstrap-hw.inc bootstrap-hw-$(BOARD).inc bootstrap-hw-$(BOARD).mk \
|
||||||
|
core-hw.inc core-hw-$(BOARD).inc core-hw-$(BOARD).mk \
|
||||||
|
startup.inc startup-hw.mk \
|
||||||
|
timeout-hw.mk cxx.mk ld-hw.mk syscall-hw.mk
|
||||||
|
|
||||||
|
LIB_MK_DIRS := lib/mk $(addprefix lib/mk/spec/,${call selected_content,LIB_MK_SPECS})
|
||||||
|
|
||||||
|
CONTENT += $(foreach D,$(LIB_MK_DIRS),$(addprefix $D/,$(LIB_MK_FILES)))
|
||||||
|
|
||||||
CONTENT += $(addprefix src/timer/,$(SRC_TIMER)) \
|
CONTENT += $(addprefix src/timer/,$(SRC_TIMER)) \
|
||||||
$(addprefix src/include/hw/,$(SRC_INCLUDE_HW)) \
|
$(addprefix src/include/hw/,$(SRC_INCLUDE_HW)) \
|
||||||
$(addprefix src/bootstrap/,$(SRC_BOOTSTRAP)) \
|
$(addprefix src/bootstrap/,$(SRC_BOOTSTRAP)) \
|
||||||
$(addprefix lib/mk/,$(LIB_MK)) \
|
$(addprefix lib/mk/,$(LIB_MK)) \
|
||||||
$(addprefix src/lib/base/,$(SRC_LIB_BASE)) \
|
$(addprefix src/lib/base/,$(SRC_LIB_BASE)) \
|
||||||
|
$(addprefix src/lib/timeout/,$(SRC_LIB_TIMEOUT)) \
|
||||||
$(addprefix src/lib/startup/,$(SRC_LIB_STARTUP)) \
|
$(addprefix src/lib/startup/,$(SRC_LIB_STARTUP)) \
|
||||||
$(addprefix src/core/,$(SRC_CORE)) \
|
$(addprefix src/core/,$(SRC_CORE)) \
|
||||||
src/lib/hw src/lib/ld src/lib/cxx \
|
src/lib/hw src/lib/ld src/lib/cxx \
|
||||||
@@ -180,7 +195,6 @@ generalize_target_names: $(CONTENT)
|
|||||||
# apply kernel-agnostic convention of naming the timer and ld.lib.so
|
# apply kernel-agnostic convention of naming the timer and ld.lib.so
|
||||||
for subdir in ${call selected_content,LD_MK_DIRS}; do \
|
for subdir in ${call selected_content,LD_MK_DIRS}; do \
|
||||||
mv $$subdir/ld-hw.mk $$subdir/ld.mk; done
|
mv $$subdir/ld-hw.mk $$subdir/ld.mk; done
|
||||||
sed -i "s/ld-hw/ld/" src/lib/ld/hw/target.mk
|
|
||||||
sed -i "s/hw_timer_drv/timer/" src/timer/hw/target.mk
|
sed -i "s/hw_timer_drv/timer/" src/timer/hw/target.mk
|
||||||
# supplement BOARD definition that normally comes form the build dir
|
# supplement BOARD definition that normally comes form the build dir
|
||||||
sed -i "s/\?= unknown/:= $(BOARD)/" src/core/hw/target.mk
|
sed -i "s/\?= unknown/:= $(BOARD)/" src/core/hw/target.mk
|
||||||
@@ -189,5 +203,4 @@ generalize_target_names: $(CONTENT)
|
|||||||
sed -i "1aREQUIRES := $(ARCH)" src/core/hw/target.mk
|
sed -i "1aREQUIRES := $(ARCH)" src/core/hw/target.mk
|
||||||
sed -i "1aREQUIRES := $(ARCH)" src/bootstrap/hw/target.mk
|
sed -i "1aREQUIRES := $(ARCH)" src/bootstrap/hw/target.mk
|
||||||
sed -i "/REQUIRES/s/hw/hw $(ARCH)/" src/timer/hw/target.mk
|
sed -i "/REQUIRES/s/hw/hw $(ARCH)/" src/timer/hw/target.mk
|
||||||
sed -i "1aREQUIRES := $(ARCH)" src/lib/ld/hw/target.mk
|
|
||||||
|
|
||||||
|
|||||||
@@ -109,7 +109,8 @@ Cpu::Idle_thread::Idle_thread(Board::Address_space_id_allocator &addr_space_id_a
|
|||||||
Cpu &cpu,
|
Cpu &cpu,
|
||||||
Pd &core_pd)
|
Pd &core_pd)
|
||||||
:
|
:
|
||||||
Thread { addr_space_id_alloc, user_irq_pool, cpu_pool, core_pd, "idle" }
|
Thread { addr_space_id_alloc, user_irq_pool, cpu_pool, core_pd,
|
||||||
|
Cpu_priority::min(), 0, "idle", Thread::IDLE }
|
||||||
{
|
{
|
||||||
regs->ip = (addr_t)&idle_thread_main;
|
regs->ip = (addr_t)&idle_thread_main;
|
||||||
|
|
||||||
@@ -120,14 +121,9 @@ Cpu::Idle_thread::Idle_thread(Board::Address_space_id_allocator &addr_space_id_a
|
|||||||
|
|
||||||
void Cpu::schedule(Job * const job)
|
void Cpu::schedule(Job * const job)
|
||||||
{
|
{
|
||||||
if (_id == executing_id())
|
_scheduler.ready(job->share());
|
||||||
_scheduler.ready(job->share());
|
if (_id != executing_id() && _scheduler.need_to_schedule())
|
||||||
else {
|
trigger_ip_interrupt();
|
||||||
_scheduler.ready_check(job->share());
|
|
||||||
|
|
||||||
if (_scheduler.need_to_schedule())
|
|
||||||
trigger_ip_interrupt();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -191,45 +191,17 @@ void Cpu_scheduler::update(time_t time)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Cpu_scheduler::ready_check(Share &s1)
|
|
||||||
{
|
|
||||||
assert(_head);
|
|
||||||
|
|
||||||
ready(s1);
|
|
||||||
|
|
||||||
if (_need_to_schedule)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Share * s2 = _head;
|
|
||||||
if (!s1._claim) {
|
|
||||||
_need_to_schedule = s2 == &_idle;
|
|
||||||
} else if (!_head_claims) {
|
|
||||||
_need_to_schedule = true;
|
|
||||||
} else if (s1._prio != s2->_prio) {
|
|
||||||
_need_to_schedule = s1._prio > s2->_prio;
|
|
||||||
} else {
|
|
||||||
for (
|
|
||||||
; s2 && s2 != &s1;
|
|
||||||
s2 =
|
|
||||||
Double_list<Cpu_share>::next(&s2->_claim_item) != nullptr ?
|
|
||||||
&Double_list<Cpu_share>::next(&s2->_claim_item)->payload() :
|
|
||||||
nullptr) ;
|
|
||||||
|
|
||||||
_need_to_schedule = !s2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Cpu_scheduler::ready(Share &s)
|
void Cpu_scheduler::ready(Share &s)
|
||||||
{
|
{
|
||||||
assert(!s._ready && &s != &_idle);
|
assert(!s._ready && &s != &_idle);
|
||||||
|
|
||||||
_need_to_schedule = true;
|
|
||||||
|
|
||||||
s._ready = 1;
|
s._ready = 1;
|
||||||
s._fill = _fill;
|
s._fill = _fill;
|
||||||
_fills.insert_tail(&s._fill_item);
|
_fills.insert_tail(&s._fill_item);
|
||||||
|
|
||||||
|
if (_head == &_idle)
|
||||||
|
_need_to_schedule = true;
|
||||||
|
|
||||||
if (!s._quota)
|
if (!s._quota)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -239,6 +211,28 @@ void Cpu_scheduler::ready(Share &s)
|
|||||||
_rcl[s._prio].insert_head(&s._claim_item);
|
_rcl[s._prio].insert_head(&s._claim_item);
|
||||||
else
|
else
|
||||||
_rcl[s._prio].insert_tail(&s._claim_item);
|
_rcl[s._prio].insert_tail(&s._claim_item);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check whether we need to re-schedule
|
||||||
|
*/
|
||||||
|
if (_need_to_schedule)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* current head has no quota left */
|
||||||
|
if (!_head_claims) {
|
||||||
|
_need_to_schedule = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if current head has different priority */
|
||||||
|
if (s._prio != _head->_prio) {
|
||||||
|
_need_to_schedule = s._prio > _head->_prio;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if current head has same priority, the ready share gets active */
|
||||||
|
if (s._claim)
|
||||||
|
_need_to_schedule = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -246,7 +240,8 @@ void Cpu_scheduler::unready(Share &s)
|
|||||||
{
|
{
|
||||||
assert(s._ready && &s != &_idle);
|
assert(s._ready && &s != &_idle);
|
||||||
|
|
||||||
_need_to_schedule = true;
|
if (&s == _head)
|
||||||
|
_need_to_schedule = true;
|
||||||
|
|
||||||
s._ready = 0;
|
s._ready = 0;
|
||||||
_fills.remove(&s._fill_item);
|
_fills.remove(&s._fill_item);
|
||||||
@@ -270,21 +265,15 @@ void Cpu_scheduler::remove(Share &s)
|
|||||||
{
|
{
|
||||||
assert(&s != &_idle);
|
assert(&s != &_idle);
|
||||||
|
|
||||||
_need_to_schedule = true;
|
if (s._ready) unready(s);
|
||||||
|
|
||||||
if (&s == _head)
|
if (&s == _head)
|
||||||
_head = nullptr;
|
_head = nullptr;
|
||||||
|
|
||||||
if (s._ready)
|
|
||||||
_fills.remove(&s._fill_item);
|
|
||||||
|
|
||||||
if (!s._quota)
|
if (!s._quota)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (s._ready)
|
_ucl[s._prio].remove(&s._claim_item);
|
||||||
_rcl[s._prio].remove(&s._claim_item);
|
|
||||||
else
|
|
||||||
_ucl[s._prio].remove(&s._claim_item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -292,8 +281,6 @@ void Cpu_scheduler::insert(Share &s)
|
|||||||
{
|
{
|
||||||
assert(!s._ready);
|
assert(!s._ready);
|
||||||
|
|
||||||
_need_to_schedule = true;
|
|
||||||
|
|
||||||
if (!s._quota)
|
if (!s._quota)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@@ -180,15 +180,10 @@ class Kernel::Cpu_scheduler
|
|||||||
void timeout() { _need_to_schedule = true; }
|
void timeout() { _need_to_schedule = true; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update head according to the consumed time
|
* Update head according to the current (absolute) time
|
||||||
*/
|
*/
|
||||||
void update(time_t time);
|
void update(time_t time);
|
||||||
|
|
||||||
/**
|
|
||||||
* Set 's1' ready and return wether this outdates current head
|
|
||||||
*/
|
|
||||||
void ready_check(Share &s1);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set share 's' ready
|
* Set share 's' ready
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -329,6 +329,23 @@ void Thread::_call_start_thread()
|
|||||||
/* join protection domain */
|
/* join protection domain */
|
||||||
thread._pd = (Pd *) user_arg_3();
|
thread._pd = (Pd *) user_arg_3();
|
||||||
thread._ipc_init(*(Native_utcb *)user_arg_4(), *this);
|
thread._ipc_init(*(Native_utcb *)user_arg_4(), *this);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sanity check core threads!
|
||||||
|
*
|
||||||
|
* Currently, the model assumes that there is only one core
|
||||||
|
* entrypoint, which serves requests, and which can destroy
|
||||||
|
* threads and pds. If this changes, we have to inform all
|
||||||
|
* cpus about pd destructions to remove their page-tables
|
||||||
|
* from the hardware in case that a core-thread running with
|
||||||
|
* that same pd is currently active. Therefore, warn if the
|
||||||
|
* semantic changes, and additional core threads are started
|
||||||
|
* across cpu cores.
|
||||||
|
*/
|
||||||
|
if (thread._pd == &_core_pd && cpu.id() != _cpu_pool.primary_cpu().id())
|
||||||
|
Genode::raw("Error: do not start core threads"
|
||||||
|
" on CPU cores different than boot cpu");
|
||||||
|
|
||||||
thread._become_active();
|
thread._become_active();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -369,7 +386,7 @@ void Thread::_call_restart_thread()
|
|||||||
|
|
||||||
Thread &thread = *thread_ptr;
|
Thread &thread = *thread_ptr;
|
||||||
|
|
||||||
if (!_core && (&pd() != &thread.pd())) {
|
if (_type == USER && (&pd() != &thread.pd())) {
|
||||||
raw(*this, ": failed to lookup thread ", (unsigned)user_arg_1(),
|
raw(*this, ": failed to lookup thread ", (unsigned)user_arg_1(),
|
||||||
" to restart it");
|
" to restart it");
|
||||||
_die();
|
_die();
|
||||||
@@ -447,6 +464,18 @@ void Thread::_call_delete_thread()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Thread::_call_delete_pd()
|
||||||
|
{
|
||||||
|
Genode::Kernel_object<Pd> & pd =
|
||||||
|
*(Genode::Kernel_object<Pd>*)user_arg_1();
|
||||||
|
|
||||||
|
if (_cpu->active(pd->mmu_regs))
|
||||||
|
_cpu->switch_to(_core_pd.mmu_regs);
|
||||||
|
|
||||||
|
_call_delete<Pd>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread::_call_await_request_msg()
|
void Thread::_call_await_request_msg()
|
||||||
{
|
{
|
||||||
if (_ipc_node.can_await_request()) {
|
if (_ipc_node.can_await_request()) {
|
||||||
@@ -793,7 +822,7 @@ void Thread::_call()
|
|||||||
case call_id_pause_vm(): _call_pause_vm(); return;
|
case call_id_pause_vm(): _call_pause_vm(); return;
|
||||||
default:
|
default:
|
||||||
/* check wether this is a core thread */
|
/* check wether this is a core thread */
|
||||||
if (!_core) {
|
if (_type != CORE) {
|
||||||
Genode::raw(*this, ": not entitled to do kernel call");
|
Genode::raw(*this, ": not entitled to do kernel call");
|
||||||
_die();
|
_die();
|
||||||
return;
|
return;
|
||||||
@@ -805,7 +834,7 @@ void Thread::_call()
|
|||||||
_call_new<Thread>(_addr_space_id_alloc, _user_irq_pool, _cpu_pool,
|
_call_new<Thread>(_addr_space_id_alloc, _user_irq_pool, _cpu_pool,
|
||||||
_core_pd, (unsigned) user_arg_2(),
|
_core_pd, (unsigned) user_arg_2(),
|
||||||
(unsigned) _core_to_kernel_quota(user_arg_3()),
|
(unsigned) _core_to_kernel_quota(user_arg_3()),
|
||||||
(char const *) user_arg_4());
|
(char const *) user_arg_4(), USER);
|
||||||
return;
|
return;
|
||||||
case call_id_new_core_thread():
|
case call_id_new_core_thread():
|
||||||
_call_new<Thread>(_addr_space_id_alloc, _user_irq_pool, _cpu_pool,
|
_call_new<Thread>(_addr_space_id_alloc, _user_irq_pool, _cpu_pool,
|
||||||
@@ -822,7 +851,7 @@ void Thread::_call()
|
|||||||
*(Genode::Platform_pd *) user_arg_3(),
|
*(Genode::Platform_pd *) user_arg_3(),
|
||||||
_addr_space_id_alloc);
|
_addr_space_id_alloc);
|
||||||
return;
|
return;
|
||||||
case call_id_delete_pd(): _call_delete<Pd>(); return;
|
case call_id_delete_pd(): _call_delete_pd(); return;
|
||||||
case call_id_new_signal_receiver(): _call_new<Signal_receiver>(); return;
|
case call_id_new_signal_receiver(): _call_new<Signal_receiver>(); return;
|
||||||
case call_id_new_signal_context():
|
case call_id_new_signal_context():
|
||||||
_call_new<Signal_context>(*(Signal_receiver*) user_arg_2(), user_arg_3());
|
_call_new<Signal_context>(*(Signal_receiver*) user_arg_2(), user_arg_3());
|
||||||
@@ -857,7 +886,7 @@ void Thread::_mmu_exception()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_core)
|
if (_type != USER)
|
||||||
Genode::raw(*this, " raised a fault, which should never happen ",
|
Genode::raw(*this, " raised a fault, which should never happen ",
|
||||||
_fault);
|
_fault);
|
||||||
|
|
||||||
@@ -874,7 +903,7 @@ Thread::Thread(Board::Address_space_id_allocator &addr_space_id_alloc,
|
|||||||
unsigned const priority,
|
unsigned const priority,
|
||||||
unsigned const quota,
|
unsigned const quota,
|
||||||
char const *const label,
|
char const *const label,
|
||||||
bool core)
|
Type type)
|
||||||
:
|
:
|
||||||
Kernel::Object { *this },
|
Kernel::Object { *this },
|
||||||
Cpu_job { priority, quota },
|
Cpu_job { priority, quota },
|
||||||
@@ -885,8 +914,8 @@ Thread::Thread(Board::Address_space_id_allocator &addr_space_id_alloc,
|
|||||||
_ipc_node { *this },
|
_ipc_node { *this },
|
||||||
_state { AWAITS_START },
|
_state { AWAITS_START },
|
||||||
_label { label },
|
_label { label },
|
||||||
_core { core },
|
_type { type },
|
||||||
regs { core }
|
regs { type != USER }
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,10 @@ struct Kernel::Thread_fault
|
|||||||
*/
|
*/
|
||||||
class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout
|
class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum Type { USER, CORE, IDLE };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -149,7 +153,7 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout
|
|||||||
capid_t _timeout_sigid { 0 };
|
capid_t _timeout_sigid { 0 };
|
||||||
bool _paused { false };
|
bool _paused { false };
|
||||||
bool _cancel_next_await_signal { false };
|
bool _cancel_next_await_signal { false };
|
||||||
bool const _core { false };
|
Type const _type;
|
||||||
|
|
||||||
Genode::Constructible<Tlb_invalidation> _tlb_invalidation {};
|
Genode::Constructible<Tlb_invalidation> _tlb_invalidation {};
|
||||||
Genode::Constructible<Destroy> _destroy {};
|
Genode::Constructible<Destroy> _destroy {};
|
||||||
@@ -230,6 +234,7 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout
|
|||||||
void _call_restart_thread();
|
void _call_restart_thread();
|
||||||
void _call_yield_thread();
|
void _call_yield_thread();
|
||||||
void _call_delete_thread();
|
void _call_delete_thread();
|
||||||
|
void _call_delete_pd();
|
||||||
void _call_await_request_msg();
|
void _call_await_request_msg();
|
||||||
void _call_send_request_msg();
|
void _call_send_request_msg();
|
||||||
void _call_send_reply_msg();
|
void _call_send_reply_msg();
|
||||||
@@ -301,7 +306,7 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout
|
|||||||
unsigned const priority,
|
unsigned const priority,
|
||||||
unsigned const quota,
|
unsigned const quota,
|
||||||
char const *const label,
|
char const *const label,
|
||||||
bool core = false);
|
Type const type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for core/kernel thread
|
* Constructor for core/kernel thread
|
||||||
@@ -315,7 +320,7 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout
|
|||||||
char const *const label)
|
char const *const label)
|
||||||
:
|
:
|
||||||
Thread(addr_space_id_alloc, user_irq_pool, cpu_pool, core_pd,
|
Thread(addr_space_id_alloc, user_irq_pool, cpu_pool, core_pd,
|
||||||
Cpu_priority::min(), 0, label, true)
|
Cpu_priority::min(), 0, label, CORE)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
~Thread();
|
~Thread();
|
||||||
@@ -432,6 +437,7 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout
|
|||||||
char const * label() const { return _label; }
|
char const * label() const { return _label; }
|
||||||
Thread_fault fault() const { return _fault; }
|
Thread_fault fault() const { return _fault; }
|
||||||
Genode::Native_utcb *utcb() { return _utcb; }
|
Genode::Native_utcb *utcb() { return _utcb; }
|
||||||
|
Type type() const { return _type; }
|
||||||
|
|
||||||
Pd &pd() const
|
Pd &pd() const
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -77,6 +77,8 @@ class Kernel::Vm : private Kernel::Object, public Cpu_job
|
|||||||
Kernel::Signal_context & context,
|
Kernel::Signal_context & context,
|
||||||
Identity & id);
|
Identity & id);
|
||||||
|
|
||||||
|
~Vm();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inject an interrupt to this VM
|
* Inject an interrupt to this VM
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -22,13 +22,17 @@
|
|||||||
|
|
||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
using namespace Kernel;
|
using namespace Kernel;
|
||||||
using Device = Board::Timer;
|
|
||||||
|
using Device = Board::Timer;
|
||||||
|
using counter_t = Board::Timer::Counter::access_t;
|
||||||
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
TICS_PER_MS =
|
TICS_PER_MS =
|
||||||
Board::CORTEX_A9_PRIVATE_TIMER_CLK /
|
Board::CORTEX_A9_PRIVATE_TIMER_CLK /
|
||||||
Board::CORTEX_A9_PRIVATE_TIMER_DIV / 1000
|
Board::CORTEX_A9_PRIVATE_TIMER_DIV / 1000,
|
||||||
|
|
||||||
|
MAX_COUNTER_VAL = ~(counter_t)0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -79,12 +83,33 @@ time_t Timer::us_to_ticks(time_t const us) const {
|
|||||||
|
|
||||||
time_t Timer::_duration() const
|
time_t Timer::_duration() const
|
||||||
{
|
{
|
||||||
Device::Counter::access_t last = _last_timeout_duration;
|
counter_t const start_counter_val { (counter_t)_last_timeout_duration };
|
||||||
Device::Counter::access_t cnt = _device.read<Device::Counter>();
|
counter_t const curr_counter_val { _device.read<Device::Counter>() };
|
||||||
Device::Counter::access_t ret = (_device.read<Device::Interrupt_status::Event>())
|
|
||||||
? _max_value() - cnt + last : last - cnt;
|
/*
|
||||||
return ret;
|
* Calculate result depending on whether the counter already wrapped or
|
||||||
|
* not. See the comment in the implementation of '_max_value' for an
|
||||||
|
* explanation why this comparison is done instead of checking the IRQ
|
||||||
|
* status and why it is sufficient.
|
||||||
|
*/
|
||||||
|
if (curr_counter_val > start_counter_val)
|
||||||
|
return start_counter_val + (MAX_COUNTER_VAL - curr_counter_val);
|
||||||
|
|
||||||
|
return start_counter_val - curr_counter_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
time_t Timer::_max_value() const { return 0xfffffffe; }
|
time_t Timer::_max_value() const
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We propagate a max timeout value far lower than the one required
|
||||||
|
* by the hardware. This is because on some platforms (Qemu 4.2.1 PBXA9),
|
||||||
|
* the IRQ status register is not reliable. Sometimes, it indicates an IRQ
|
||||||
|
* too early, i.e., shortly before the counter wraps. Therefore we have to
|
||||||
|
* accomplish wrap detection via counter comparison only. Therefore, we
|
||||||
|
* have to make sure that we always read out the counter before it hits
|
||||||
|
* the max timout value again. And, therefore, the max timeout value has
|
||||||
|
* to be far away from the first value the counter has after wrapping.
|
||||||
|
*/
|
||||||
|
return MAX_COUNTER_VAL >> 1;
|
||||||
|
}
|
||||||
|
|||||||
@@ -87,24 +87,25 @@ void Arm_cpu::mmu_fault_status(Fsr::access_t fsr, Thread_fault & fault)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Arm_cpu::switch_to(Arm_cpu::Context&, Arm_cpu::Mmu_context & o)
|
bool Arm_cpu::active(Arm_cpu::Mmu_context & ctx)
|
||||||
{
|
{
|
||||||
if (o.cidr == 0) return;
|
return (Cidr::read() == ctx.cidr);
|
||||||
|
}
|
||||||
|
|
||||||
Cidr::access_t cidr = Cidr::read();
|
|
||||||
if (cidr != o.cidr) {
|
void Arm_cpu::switch_to(Arm_cpu::Mmu_context & ctx)
|
||||||
/**
|
{
|
||||||
* First switch to global mappings only to prevent
|
/**
|
||||||
* that wrong branch predicts result due to ASID
|
* First switch to global mappings only to prevent
|
||||||
* and Page-Table not being in sync (see ARM RM B 3.10.4)
|
* that wrong branch predicts result due to ASID
|
||||||
*/
|
* and Page-Table not being in sync (see ARM RM B 3.10.4)
|
||||||
Cidr::write(0);
|
*/
|
||||||
Cpu::synchronization_barrier();
|
Cidr::write(0);
|
||||||
Ttbr0::write(o.ttbr0);
|
Cpu::synchronization_barrier();
|
||||||
Cpu::synchronization_barrier();
|
Ttbr0::write(ctx.ttbr0);
|
||||||
Cidr::write(o.cidr);
|
Cpu::synchronization_barrier();
|
||||||
Cpu::synchronization_barrier();
|
Cidr::write(ctx.cidr);
|
||||||
}
|
Cpu::synchronization_barrier();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -104,7 +104,8 @@ struct Genode::Arm_cpu : public Hw::Arm_cpu
|
|||||||
else Tlbiall::write(0);
|
else Tlbiall::write(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void switch_to(Context&, Mmu_context & o);
|
bool active(Mmu_context &);
|
||||||
|
void switch_to(Mmu_context &);
|
||||||
|
|
||||||
static void mmu_fault(Context & c, Kernel::Thread_fault & fault);
|
static void mmu_fault(Context & c, Kernel::Thread_fault & fault);
|
||||||
static void mmu_fault_status(Fsr::access_t fsr,
|
static void mmu_fault_status(Fsr::access_t fsr,
|
||||||
|
|||||||
@@ -67,7 +67,8 @@ void Kernel::Thread::Tlb_invalidation::execute() { };
|
|||||||
|
|
||||||
void Thread::proceed(Cpu & cpu)
|
void Thread::proceed(Cpu & cpu)
|
||||||
{
|
{
|
||||||
cpu.switch_to(*regs, pd().mmu_regs);
|
if (!cpu.active(pd().mmu_regs) && type() != CORE)
|
||||||
|
cpu.switch_to(pd().mmu_regs);
|
||||||
|
|
||||||
regs->cpu_exception = cpu.stack_start();
|
regs->cpu_exception = cpu.stack_start();
|
||||||
kernel_to_user_context_switch((static_cast<Cpu::Context*>(&*regs)),
|
kernel_to_user_context_switch((static_cast<Cpu::Context*>(&*regs)),
|
||||||
|
|||||||
@@ -38,6 +38,9 @@ Vm::Vm(Irq::Pool & user_irq_pool,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Vm::~Vm() {}
|
||||||
|
|
||||||
|
|
||||||
void Vm::exception(Cpu & cpu)
|
void Vm::exception(Cpu & cpu)
|
||||||
{
|
{
|
||||||
switch(_state.cpu_exception) {
|
switch(_state.cpu_exception) {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
push { r0 }
|
push { r0 }
|
||||||
mrc p15, 4, r0, c1, c1, 0 /* read HCR register */
|
mrc p15, 4, r0, c1, c1, 0 /* read HCR register */
|
||||||
tst r0, #1 /* check VM bit */
|
tst r0, #1 /* check VM bit */
|
||||||
beq _host_to_vm
|
beq _from_host
|
||||||
mov r0, #\exception_type
|
mov r0, #\exception_type
|
||||||
b _vm_to_host
|
b _vm_to_host
|
||||||
.endm /* _vm_exit */
|
.endm /* _vm_exit */
|
||||||
@@ -47,10 +47,27 @@ _vt_dab_entry: _vm_exit 5
|
|||||||
_vt_irq_entry: _vm_exit 6
|
_vt_irq_entry: _vm_exit 6
|
||||||
_vt_trp_entry: _vm_exit 8
|
_vt_trp_entry: _vm_exit 8
|
||||||
|
|
||||||
_host_to_vm:
|
_from_host:
|
||||||
|
pop { r0 }
|
||||||
|
cmp r0, #0
|
||||||
|
beq _to_vm
|
||||||
|
cmp r0, #1
|
||||||
|
beq _invalidate_tlb
|
||||||
|
eret
|
||||||
|
|
||||||
|
|
||||||
|
_invalidate_tlb:
|
||||||
|
push { r3, r4 }
|
||||||
|
mrrc p15, 6, r3, r4, c2 /* save VTTBR */
|
||||||
|
mcrr p15, 6, r1, r2, c2 /* write VTTBR */
|
||||||
|
mcr p15, 0, r0, c8, c3, 0 /* TLBIALLIS */
|
||||||
|
mcrr p15, 6, r3, r4, c2 /* restore VTTBR */
|
||||||
|
eret
|
||||||
|
|
||||||
|
_to_vm:
|
||||||
push { r1 }
|
push { r1 }
|
||||||
ldr r0, [sp, #1*4]
|
push { r2 }
|
||||||
add r0, r0, #13*4
|
add r0, r1, #13*4
|
||||||
ldmia r0!, { r1-r5 }
|
ldmia r0!, { r1-r5 }
|
||||||
msr sp_usr, r1
|
msr sp_usr, r1
|
||||||
mov lr, r2
|
mov lr, r2
|
||||||
@@ -115,6 +132,7 @@ _host_to_vm:
|
|||||||
ldmia r0, {r0-r12} /* load vm's r0-r12 */
|
ldmia r0, {r0-r12} /* load vm's r0-r12 */
|
||||||
eret
|
eret
|
||||||
|
|
||||||
|
|
||||||
_vm_to_host:
|
_vm_to_host:
|
||||||
push { r0 } /* push cpu excep. */
|
push { r0 } /* push cpu excep. */
|
||||||
ldr r0, [sp, #3*4] /* load vm state ptr */
|
ldr r0, [sp, #3*4] /* load vm state ptr */
|
||||||
@@ -218,6 +236,7 @@ _vm_to_host:
|
|||||||
|
|
||||||
|
|
||||||
/* host kernel must jump to this point to switch to a vm */
|
/* host kernel must jump to this point to switch to a vm */
|
||||||
.global hypervisor_enter_vm
|
.global hypervisor_call
|
||||||
hypervisor_enter_vm:
|
hypervisor_call:
|
||||||
hvc #0
|
hvc #0
|
||||||
|
bx lr
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* \brief Interface between kernel and hypervisor
|
||||||
|
* \author Stefan Kalkowski
|
||||||
|
* \date 2022-06-13
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Genode Labs GmbH
|
||||||
|
*
|
||||||
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SPEC__ARM_V7__VIRTUALIZATION_HYPERVISOR_H_
|
||||||
|
#define _SPEC__ARM_V7__VIRTUALIZATION_HYPERVISOR_H_
|
||||||
|
|
||||||
|
#include <base/stdint.h>
|
||||||
|
#include <cpu/vm_state_virtualization.h>
|
||||||
|
|
||||||
|
namespace Hypervisor {
|
||||||
|
|
||||||
|
struct Host_context;
|
||||||
|
|
||||||
|
enum Call_number {
|
||||||
|
WORLD_SWITCH = 0,
|
||||||
|
TLB_INVALIDATE = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
using Call_arg = Genode::umword_t;
|
||||||
|
using Call_ret = Genode::umword_t;
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
Call_ret hypervisor_call(Call_arg call_id,
|
||||||
|
Call_arg arg0,
|
||||||
|
Call_arg arg1);
|
||||||
|
|
||||||
|
|
||||||
|
inline void invalidate_tlb(Genode::uint64_t vttbr)
|
||||||
|
{
|
||||||
|
hypervisor_call(TLB_INVALIDATE,
|
||||||
|
(vttbr & 0xffffffff),
|
||||||
|
((vttbr >> 32U) & 0xffffffff));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void switch_world(Genode::Vm_state & vm_state,
|
||||||
|
Host_context & host_state)
|
||||||
|
{
|
||||||
|
hypervisor_call(WORLD_SWITCH,
|
||||||
|
(Call_arg)&vm_state,
|
||||||
|
(Call_arg)&host_state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _SPEC__ARM_V7__VIRTUALIZATION_HYPERVISOR_H_ */
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
#include <kernel/cpu.h>
|
#include <kernel/cpu.h>
|
||||||
#include <kernel/vm.h>
|
#include <kernel/vm.h>
|
||||||
#include <kernel/main.h>
|
#include <kernel/main.h>
|
||||||
|
#include <spec/arm_v7/virtualization/hypervisor.h>
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
@@ -41,7 +42,7 @@ namespace Kernel {
|
|||||||
using namespace Kernel;
|
using namespace Kernel;
|
||||||
|
|
||||||
|
|
||||||
struct Host_context
|
struct Hypervisor::Host_context
|
||||||
{
|
{
|
||||||
Cpu::Ttbr_64bit::access_t vttbr;
|
Cpu::Ttbr_64bit::access_t vttbr;
|
||||||
Cpu::Hcr::access_t hcr;
|
Cpu::Hcr::access_t hcr;
|
||||||
@@ -61,15 +62,13 @@ struct Host_context
|
|||||||
} vt_host_context;
|
} vt_host_context;
|
||||||
|
|
||||||
|
|
||||||
extern "C" void hypervisor_enter_vm(Genode::Vm_state&, Host_context&);
|
static Hypervisor::Host_context & host_context(Cpu & cpu)
|
||||||
|
|
||||||
|
|
||||||
static Host_context & host_context(Cpu & cpu)
|
|
||||||
{
|
{
|
||||||
static Genode::Constructible<Host_context> host_context[NR_OF_CPUS];
|
static Genode::Constructible<Hypervisor::Host_context>
|
||||||
|
host_context[NR_OF_CPUS];
|
||||||
if (!host_context[cpu.id()].constructed()) {
|
if (!host_context[cpu.id()].constructed()) {
|
||||||
host_context[cpu.id()].construct();
|
host_context[cpu.id()].construct();
|
||||||
Host_context & c = *host_context[cpu.id()];
|
Hypervisor::Host_context & c = *host_context[cpu.id()];
|
||||||
c.sp = cpu.stack_start();
|
c.sp = cpu.stack_start();
|
||||||
c.ttbr0 = Cpu::Ttbr0_64bit::read();
|
c.ttbr0 = Cpu::Ttbr0_64bit::read();
|
||||||
c.ttbr1 = Cpu::Ttbr1_64bit::read();
|
c.ttbr1 = Cpu::Ttbr1_64bit::read();
|
||||||
@@ -152,6 +151,15 @@ Kernel::Vm::Vm(Irq::Pool & user_irq_pool,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Kernel::Vm::~Vm()
|
||||||
|
{
|
||||||
|
Cpu::Ttbr_64bit::access_t vttbr =
|
||||||
|
Cpu::Ttbr_64bit::Ba::masked((Cpu::Ttbr_64bit::access_t)_id.table);
|
||||||
|
Cpu::Ttbr_64bit::Asid::set(vttbr, _id.id);
|
||||||
|
Hypervisor::invalidate_tlb(vttbr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Kernel::Vm::exception(Cpu & cpu)
|
void Kernel::Vm::exception(Cpu & cpu)
|
||||||
{
|
{
|
||||||
switch(_state.cpu_exception) {
|
switch(_state.cpu_exception) {
|
||||||
@@ -190,7 +198,7 @@ void Kernel::Vm::proceed(Cpu & cpu)
|
|||||||
_state.esr_el2 = Cpu::Hstr::init();
|
_state.esr_el2 = Cpu::Hstr::init();
|
||||||
_state.hpfar_el2 = Cpu::Hcr::init();
|
_state.hpfar_el2 = Cpu::Hcr::init();
|
||||||
|
|
||||||
hypervisor_enter_vm(_state, host_context(cpu));
|
Hypervisor::switch_world(_state, host_context(cpu));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -26,12 +26,15 @@ Genode::Cpu::Context::Context(bool privileged)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Genode::Cpu::switch_to(Context&, Mmu_context & mmu_context)
|
bool Genode::Cpu::active(Mmu_context & mmu_context)
|
||||||
{
|
{
|
||||||
if (mmu_context.id() == 0) return;
|
return (mmu_context.id() == Ttbr::Asid::get(Ttbr0_el1::read()));
|
||||||
|
}
|
||||||
|
|
||||||
if (mmu_context.id() != Ttbr::Asid::get(Ttbr0_el1::read()))
|
|
||||||
Ttbr0_el1::write(mmu_context.ttbr);
|
void Genode::Cpu::switch_to(Mmu_context & mmu_context)
|
||||||
|
{
|
||||||
|
Ttbr0_el1::write(mmu_context.ttbr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -99,7 +99,8 @@ struct Genode::Cpu : Hw::Arm_64_cpu
|
|||||||
return Ttbr::Asid::get(ttbr) & 0xffff; }
|
return Ttbr::Asid::get(ttbr) & 0xffff; }
|
||||||
};
|
};
|
||||||
|
|
||||||
void switch_to(Context&, Mmu_context &);
|
bool active(Mmu_context &);
|
||||||
|
void switch_to(Mmu_context &);
|
||||||
|
|
||||||
static void mmu_fault(Context &, Kernel::Thread_fault &);
|
static void mmu_fault(Context &, Kernel::Thread_fault &);
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,16 @@ void Thread::exception(Cpu & cpu)
|
|||||||
" ISS=", Cpu::Esr::Iss::get(esr),
|
" ISS=", Cpu::Esr::Iss::get(esr),
|
||||||
" ip=", (void*)regs->ip);
|
" ip=", (void*)regs->ip);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the machine exception is caused by a non-privileged
|
||||||
|
* component, mark it dead, and continue execution.
|
||||||
|
*/
|
||||||
|
if (regs->exception_type == Cpu::SYNC_LEVEL_EL0) {
|
||||||
|
Genode::raw("Will freeze thread ", *this);
|
||||||
|
_become_inactive(DEAD);
|
||||||
|
return;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -75,10 +85,14 @@ void Thread::exception(Cpu & cpu)
|
|||||||
void Kernel::Thread::Tlb_invalidation::execute() { };
|
void Kernel::Thread::Tlb_invalidation::execute() { };
|
||||||
|
|
||||||
|
|
||||||
bool Kernel::Pd::invalidate_tlb(Cpu &, addr_t addr, size_t size)
|
bool Kernel::Pd::invalidate_tlb(Cpu & cpu, addr_t addr, size_t size)
|
||||||
{
|
{
|
||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
|
|
||||||
|
/* only apply to the active cpu */
|
||||||
|
if (cpu.id() != Cpu::executing_id())
|
||||||
|
return false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The kernel part of the address space is mapped as global
|
* The kernel part of the address space is mapped as global
|
||||||
* therefore we have to invalidate it differently
|
* therefore we have to invalidate it differently
|
||||||
@@ -108,7 +122,9 @@ bool Kernel::Pd::invalidate_tlb(Cpu &, addr_t addr, size_t size)
|
|||||||
|
|
||||||
void Thread::proceed(Cpu & cpu)
|
void Thread::proceed(Cpu & cpu)
|
||||||
{
|
{
|
||||||
cpu.switch_to(*regs, pd().mmu_regs);
|
if (!cpu.active(pd().mmu_regs) && type() != CORE)
|
||||||
|
cpu.switch_to(pd().mmu_regs);
|
||||||
|
|
||||||
kernel_to_user_context_switch((static_cast<Cpu::Context*>(&*regs)),
|
kernel_to_user_context_switch((static_cast<Cpu::Context*>(&*regs)),
|
||||||
(void*)cpu.stack_start());
|
(void*)cpu.stack_start());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,24 +22,34 @@
|
|||||||
.global hypervisor_exception_vector
|
.global hypervisor_exception_vector
|
||||||
hypervisor_exception_vector:
|
hypervisor_exception_vector:
|
||||||
.rept 16
|
.rept 16
|
||||||
add sp, sp, #-16 /* push x0, x1 to stack */
|
add sp, sp, #-16 /* push x29, x30 to stack */
|
||||||
stp x0, x1, [sp]
|
stp x29, x30, [sp]
|
||||||
mrs x1, hcr_el2 /* read HCR register */
|
mrs x30, hcr_el2 /* read HCR register */
|
||||||
tst x1, #1 /* check VM bit */
|
tst x30, #1 /* check VM bit */
|
||||||
beq _host_to_vm /* if VM bit is not set, switch to VM */
|
beq _from_host /* if VM bit is not set, its a host call */
|
||||||
ldr x0, [sp, #32] /* otherwise, load vm_state pointer */
|
ldr x29, [sp, #32] /* otherwise, load vm_state pointer */
|
||||||
adr x1, . /* hold exception vector offset in x1 */
|
adr x30, . /* hold exception vector offset in x30 */
|
||||||
and x1, x1, #0xf80
|
and x30, x30, #0xf80
|
||||||
b _vm_to_host
|
b _from_vm
|
||||||
.balign 128
|
.balign 128
|
||||||
.endr
|
.endr
|
||||||
|
|
||||||
_host_to_vm:
|
_from_host:
|
||||||
|
ldp x29, x30, [sp], #2*8 /* pop x29, x30 from stack */
|
||||||
|
cmp x0, #0
|
||||||
|
beq _to_vm
|
||||||
|
cmp x0, #1
|
||||||
|
beq _invalidate_tlb
|
||||||
|
eret
|
||||||
|
|
||||||
add sp, sp, #-16 /* push arg2 (vm pic state) to stack */
|
_to_vm:
|
||||||
str x2, [sp]
|
add sp, sp, #-16 /* push arg1/2 (vm/host state to stack */
|
||||||
|
stp x1, x2, [sp]
|
||||||
|
add sp, sp, #-16 /* push arg3 (vm pic state) to stack */
|
||||||
|
str x3, [sp]
|
||||||
|
|
||||||
msr vttbr_el2, x3 /* stage2 table pointer was arg3 */
|
msr vttbr_el2, x4 /* stage2 table pointer was arg4 */
|
||||||
|
mov x0, x1
|
||||||
|
|
||||||
add x0, x0, #31*8 /* skip x0...x30, loaded later */
|
add x0, x0, #31*8 /* skip x0...x30, loaded later */
|
||||||
|
|
||||||
@@ -179,27 +189,38 @@ _host_to_vm:
|
|||||||
|
|
||||||
eret
|
eret
|
||||||
|
|
||||||
_vm_to_host:
|
|
||||||
|
_invalidate_tlb:
|
||||||
|
msr vttbr_el2, x1
|
||||||
|
tlbi vmalle1is
|
||||||
|
msr vttbr_el2, xzr
|
||||||
|
eret
|
||||||
|
|
||||||
|
|
||||||
|
_from_vm:
|
||||||
|
|
||||||
/*********************
|
/*********************
|
||||||
** Save vm context **
|
** Save vm context **
|
||||||
*********************/
|
*********************/
|
||||||
|
|
||||||
/** general-purpose register **/
|
/** general-purpose register **/
|
||||||
add x0, x0, #2*8 /* skip x0 and x1 for now */
|
stp x0, x1, [x29], #2*8
|
||||||
stp x2, x3, [x0], #2*8
|
stp x2, x3, [x29], #2*8
|
||||||
stp x4, x5, [x0], #2*8
|
stp x4, x5, [x29], #2*8
|
||||||
stp x6, x7, [x0], #2*8
|
stp x6, x7, [x29], #2*8
|
||||||
stp x8, x9, [x0], #2*8
|
stp x8, x9, [x29], #2*8
|
||||||
stp x10, x11, [x0], #2*8
|
stp x10, x11, [x29], #2*8
|
||||||
stp x12, x13, [x0], #2*8
|
stp x12, x13, [x29], #2*8
|
||||||
stp x14, x15, [x0], #2*8
|
stp x14, x15, [x29], #2*8
|
||||||
stp x16, x17, [x0], #2*8
|
stp x16, x17, [x29], #2*8
|
||||||
stp x18, x19, [x0], #2*8
|
stp x18, x19, [x29], #2*8
|
||||||
stp x20, x21, [x0], #2*8
|
stp x20, x21, [x29], #2*8
|
||||||
stp x22, x23, [x0], #2*8
|
stp x22, x23, [x29], #2*8
|
||||||
stp x24, x25, [x0], #2*8
|
stp x24, x25, [x29], #2*8
|
||||||
stp x26, x27, [x0], #2*8
|
stp x26, x27, [x29], #2*8
|
||||||
|
mov x0, x29
|
||||||
|
mov x1, x30
|
||||||
|
ldp x29, x30, [sp], #2*8 /* pop x29, x30 from stack */
|
||||||
stp x28, x29, [x0], #2*8
|
stp x28, x29, [x0], #2*8
|
||||||
str x30, [x0], #1*8
|
str x30, [x0], #1*8
|
||||||
|
|
||||||
@@ -284,11 +305,8 @@ _vm_to_host:
|
|||||||
mov x0, #0b111
|
mov x0, #0b111
|
||||||
msr cnthctl_el2, x0
|
msr cnthctl_el2, x0
|
||||||
|
|
||||||
|
ldr x29, [sp], #2*8 /* pop vm pic state from stack */
|
||||||
ldp x0, x1, [sp], #2*8 /* pop x0, x1 from stack */
|
ldp x2, x30, [sp], #2*8 /* pop vm, and host state from stack */
|
||||||
ldr x29, [sp], #2*8 /* pop vm pic state from stack */
|
|
||||||
ldp x2, x30, [sp], #2*8 /* pop vm, and host state from stack */
|
|
||||||
stp x0, x1, [x2] /* save x0, x1 to vm state */
|
|
||||||
|
|
||||||
|
|
||||||
/**********************
|
/**********************
|
||||||
@@ -364,6 +382,7 @@ _vm_to_host:
|
|||||||
eret
|
eret
|
||||||
|
|
||||||
/* host kernel must jump to this point to switch to a vm */
|
/* host kernel must jump to this point to switch to a vm */
|
||||||
.global hypervisor_enter_vm
|
.global hypervisor_call
|
||||||
hypervisor_enter_vm:
|
hypervisor_call:
|
||||||
hvc #0
|
hvc #0
|
||||||
|
ret
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* \brief Interface between kernel and hypervisor
|
||||||
|
* \author Stefan Kalkowski
|
||||||
|
* \date 2022-06-13
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Genode Labs GmbH
|
||||||
|
*
|
||||||
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SPEC__ARM_V8__VIRTUALIZATION_HYPERVISOR_H_
|
||||||
|
#define _SPEC__ARM_V8__VIRTUALIZATION_HYPERVISOR_H_
|
||||||
|
|
||||||
|
#include <base/stdint.h>
|
||||||
|
|
||||||
|
namespace Hypervisor {
|
||||||
|
|
||||||
|
enum Call_number {
|
||||||
|
WORLD_SWITCH = 0,
|
||||||
|
TLB_INVALIDATE = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
using Call_arg = Genode::umword_t;
|
||||||
|
using Call_ret = Genode::umword_t;
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
Call_ret hypervisor_call(Call_arg call_id,
|
||||||
|
Call_arg arg0,
|
||||||
|
Call_arg arg1,
|
||||||
|
Call_arg arg2,
|
||||||
|
Call_arg arg3);
|
||||||
|
|
||||||
|
|
||||||
|
inline void invalidate_tlb(Call_arg ttbr)
|
||||||
|
{
|
||||||
|
hypervisor_call(TLB_INVALIDATE, ttbr, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void switch_world(Call_arg guest_state,
|
||||||
|
Call_arg host_state,
|
||||||
|
Call_arg pic_state,
|
||||||
|
Call_arg ttbr)
|
||||||
|
{
|
||||||
|
hypervisor_call(WORLD_SWITCH, guest_state, host_state, pic_state, ttbr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _SPEC__ARM_V8__VIRTUALIZATION_HYPERVISOR_H_ */
|
||||||
@@ -23,14 +23,12 @@
|
|||||||
#include <kernel/vm.h>
|
#include <kernel/vm.h>
|
||||||
#include <kernel/main.h>
|
#include <kernel/main.h>
|
||||||
|
|
||||||
|
#include <spec/arm_v8/virtualization/hypervisor.h>
|
||||||
|
|
||||||
using Genode::addr_t;
|
using Genode::addr_t;
|
||||||
using Kernel::Cpu;
|
using Kernel::Cpu;
|
||||||
using Kernel::Vm;
|
using Kernel::Vm;
|
||||||
|
|
||||||
extern void * kernel_stack;
|
|
||||||
extern "C" void hypervisor_enter_vm(addr_t vm, addr_t host,
|
|
||||||
addr_t pic, addr_t guest_table);
|
|
||||||
|
|
||||||
|
|
||||||
static Genode::Vm_state & host_context(Cpu & cpu)
|
static Genode::Vm_state & host_context(Cpu & cpu)
|
||||||
{
|
{
|
||||||
@@ -154,6 +152,15 @@ Vm::Vm(Irq::Pool & user_irq_pool,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Vm::~Vm()
|
||||||
|
{
|
||||||
|
Cpu::Vttbr_el2::access_t vttbr_el2 =
|
||||||
|
Cpu::Vttbr_el2::Ba::masked((Cpu::Vttbr_el2::access_t)_id.table);
|
||||||
|
Cpu::Vttbr_el2::Asid::set(vttbr_el2, _id.id);
|
||||||
|
Hypervisor::invalidate_tlb(vttbr_el2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Vm::exception(Cpu & cpu)
|
void Vm::exception(Cpu & cpu)
|
||||||
{
|
{
|
||||||
switch (_state.exception_type) {
|
switch (_state.exception_type) {
|
||||||
@@ -197,7 +204,7 @@ void Vm::proceed(Cpu & cpu)
|
|||||||
addr_t pic = Hw::Mm::el2_addr(&_vcpu_context.pic);
|
addr_t pic = Hw::Mm::el2_addr(&_vcpu_context.pic);
|
||||||
addr_t host = Hw::Mm::el2_addr(&host_context(cpu));
|
addr_t host = Hw::Mm::el2_addr(&host_context(cpu));
|
||||||
|
|
||||||
hypervisor_enter_vm(guest, host, pic, vttbr_el2);
|
Hypervisor::switch_world(guest, host, pic, vttbr_el2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -115,11 +115,14 @@ class Genode::Cpu : public Arm_v7_cpu
|
|||||||
*/
|
*/
|
||||||
static unsigned executing_id() { return Mpidr::Aff_0::get(Mpidr::read()); }
|
static unsigned executing_id() { return Mpidr::Aff_0::get(Mpidr::read()); }
|
||||||
|
|
||||||
|
bool active(Mmu_context & mmu_context)
|
||||||
void switch_to(Context &, Mmu_context & mmu_context)
|
|
||||||
{
|
{
|
||||||
if (mmu_context.id() && (Ttbr0_64bit::read() != mmu_context.ttbr0))
|
return (Ttbr0_64bit::read() == mmu_context.ttbr0);
|
||||||
Ttbr0_64bit::write(mmu_context.ttbr0);
|
}
|
||||||
|
|
||||||
|
void switch_to(Mmu_context & mmu_context)
|
||||||
|
{
|
||||||
|
Ttbr0_64bit::write(mmu_context.ttbr0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -53,22 +53,16 @@ Mmu_context::~Mmu_context()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Genode::Cpu::active(Mmu_context & context)
|
||||||
|
{
|
||||||
|
return Satp::read() == context.satp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Genode::Cpu::switch_to(Mmu_context & context)
|
void Genode::Cpu::switch_to(Mmu_context & context)
|
||||||
{
|
{
|
||||||
/*
|
Satp::write(context.satp);
|
||||||
* The sstatus register defines to which privilege level
|
sfence();
|
||||||
* the machin returns when doing an exception return
|
|
||||||
*/
|
|
||||||
bool user = Satp::Asid::get(context.satp);
|
|
||||||
Sstatus::access_t v = Sstatus::read();
|
|
||||||
Sstatus::Spp::set(v, user ? 0 : 1);
|
|
||||||
Sstatus::write(v);
|
|
||||||
|
|
||||||
/* change the translation table when necessary */
|
|
||||||
if (user) {
|
|
||||||
Satp::write(context.satp);
|
|
||||||
sfence();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ class Genode::Cpu : public Hw::Riscv_cpu
|
|||||||
|
|
||||||
static void invalidate_tlb_by_pid(unsigned const /* pid */) { sfence(); }
|
static void invalidate_tlb_by_pid(unsigned const /* pid */) { sfence(); }
|
||||||
|
|
||||||
|
bool active(Mmu_context & context);
|
||||||
void switch_to(Mmu_context & context);
|
void switch_to(Mmu_context & context);
|
||||||
static void mmu_fault(Context & c, Kernel::Thread_fault & f);
|
static void mmu_fault(Context & c, Kernel::Thread_fault & f);
|
||||||
|
|
||||||
|
|||||||
@@ -100,7 +100,16 @@ void Kernel::Thread::_call_cache_invalidate_data_region() { }
|
|||||||
|
|
||||||
void Kernel::Thread::proceed(Cpu & cpu)
|
void Kernel::Thread::proceed(Cpu & cpu)
|
||||||
{
|
{
|
||||||
cpu.switch_to(_pd->mmu_regs);
|
/*
|
||||||
|
* The sstatus register defines to which privilege level
|
||||||
|
* the machine returns when doing an exception return
|
||||||
|
*/
|
||||||
|
Cpu::Sstatus::access_t v = Cpu::Sstatus::read();
|
||||||
|
Cpu::Sstatus::Spp::set(v, (type() == USER) ? 0 : 1);
|
||||||
|
Cpu::Sstatus::write(v);
|
||||||
|
|
||||||
|
if (!cpu.active(pd().mmu_regs) && type() != CORE)
|
||||||
|
cpu.switch_to(_pd->mmu_regs);
|
||||||
|
|
||||||
asm volatile("csrw sscratch, %1 \n"
|
asm volatile("csrw sscratch, %1 \n"
|
||||||
"mv x31, %0 \n"
|
"mv x31, %0 \n"
|
||||||
|
|||||||
@@ -111,11 +111,20 @@ extern void const * const kernel_stack;
|
|||||||
extern Genode::size_t const kernel_stack_size;
|
extern Genode::size_t const kernel_stack_size;
|
||||||
|
|
||||||
|
|
||||||
void Genode::Cpu::switch_to(Context & context, Mmu_context &mmu_context)
|
bool Genode::Cpu::active(Mmu_context &mmu_context)
|
||||||
{
|
{
|
||||||
if ((context.cs != 0x8) && (mmu_context.cr3 != Cr3::read()))
|
return (mmu_context.cr3 == Cr3::read());
|
||||||
Cr3::write(mmu_context.cr3);
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Genode::Cpu::switch_to(Mmu_context &mmu_context)
|
||||||
|
{
|
||||||
|
Cr3::write(mmu_context.cr3);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Genode::Cpu::switch_to(Context & context)
|
||||||
|
{
|
||||||
tss.ist[0] = (addr_t)&context + sizeof(Genode::Cpu_state);
|
tss.ist[0] = (addr_t)&context + sizeof(Genode::Cpu_state);
|
||||||
|
|
||||||
addr_t const stack_base = reinterpret_cast<addr_t>(&kernel_stack);
|
addr_t const stack_base = reinterpret_cast<addr_t>(&kernel_stack);
|
||||||
|
|||||||
@@ -126,7 +126,10 @@ class Genode::Cpu : public Hw::X86_64_cpu
|
|||||||
*
|
*
|
||||||
* \param context next CPU context
|
* \param context next CPU context
|
||||||
*/
|
*/
|
||||||
void switch_to(Context & context, Mmu_context &mmu_context);
|
void switch_to(Context & context);
|
||||||
|
|
||||||
|
bool active(Mmu_context &mmu_context);
|
||||||
|
void switch_to(Mmu_context &mmu_context);
|
||||||
|
|
||||||
static void mmu_fault(Context & regs, Kernel::Thread_fault & fault);
|
static void mmu_fault(Context & regs, Kernel::Thread_fault & fault);
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,10 @@ void Kernel::Thread::_call_cache_invalidate_data_region() { }
|
|||||||
|
|
||||||
void Kernel::Thread::proceed(Cpu & cpu)
|
void Kernel::Thread::proceed(Cpu & cpu)
|
||||||
{
|
{
|
||||||
cpu.switch_to(*regs, pd().mmu_regs);
|
if (!cpu.active(pd().mmu_regs) && type() != CORE)
|
||||||
|
cpu.switch_to(pd().mmu_regs);
|
||||||
|
|
||||||
|
cpu.switch_to(*regs);
|
||||||
|
|
||||||
asm volatile("fxrstor (%1) \n"
|
asm volatile("fxrstor (%1) \n"
|
||||||
"mov %0, %%rsp \n"
|
"mov %0, %%rsp \n"
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
TARGET = ld-hw
|
|
||||||
LIBS = ld-hw
|
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2014-2017 Genode Labs GmbH
|
* Copyright (C) 2014-2022 Genode Labs GmbH
|
||||||
*
|
*
|
||||||
* This file is part of the Genode OS framework, which is distributed
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
* under the terms of the GNU Affero General Public License version 3.
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
@@ -18,125 +18,110 @@
|
|||||||
/* core includes */
|
/* core includes */
|
||||||
#include <kernel/cpu_scheduler.h>
|
#include <kernel/cpu_scheduler.h>
|
||||||
|
|
||||||
/*
|
using namespace Genode;
|
||||||
* Utilities
|
using namespace Kernel;
|
||||||
*/
|
|
||||||
|
|
||||||
using Genode::size_t;
|
struct Main
|
||||||
using Genode::addr_t;
|
|
||||||
using Genode::construct_at;
|
|
||||||
using Kernel::Cpu_share;
|
|
||||||
using Kernel::Cpu_scheduler;
|
|
||||||
|
|
||||||
|
|
||||||
struct Data
|
|
||||||
{
|
{
|
||||||
Cpu_share idle;
|
enum { MAX_SHARES = 10 };
|
||||||
Cpu_scheduler scheduler;
|
|
||||||
char shares[9][sizeof(Cpu_share)];
|
|
||||||
|
|
||||||
Data() : idle(0, 0), scheduler(idle, 1000, 100) { }
|
Constructible<Cpu_share> shares[MAX_SHARES] {};
|
||||||
|
Cpu_scheduler scheduler;
|
||||||
|
time_t current_time { 0 };
|
||||||
|
|
||||||
|
Cpu_share & _idle()
|
||||||
|
{
|
||||||
|
if (!shares[0].constructed()) shares[0].construct(0, 0);
|
||||||
|
return *shares[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
Main() : scheduler(_idle(), 1000, 100) { }
|
||||||
|
|
||||||
|
void done()
|
||||||
|
{
|
||||||
|
Genode::log("done");
|
||||||
|
while (1) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned share_id(Cpu_share & share)
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < MAX_SHARES; i++)
|
||||||
|
if (shares[i].constructed() && (&*shares[i] == &share))
|
||||||
|
return i;
|
||||||
|
return ~0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cpu_share & share(unsigned const id)
|
||||||
|
{
|
||||||
|
return *shares[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
void create(unsigned const id)
|
||||||
|
{
|
||||||
|
switch (id) {
|
||||||
|
case 1: shares[id].construct(2, 230); break;
|
||||||
|
case 2: shares[id].construct(0, 170); break;
|
||||||
|
case 3: shares[id].construct(3, 110); break;
|
||||||
|
case 4: shares[id].construct(1, 90); break;
|
||||||
|
case 5: shares[id].construct(3, 120); break;
|
||||||
|
case 6: shares[id].construct(3, 0); break;
|
||||||
|
case 7: shares[id].construct(2, 180); break;
|
||||||
|
case 8: shares[id].construct(2, 100); break;
|
||||||
|
case 9: shares[id].construct(2, 0); break;
|
||||||
|
default: return;
|
||||||
|
}
|
||||||
|
scheduler.insert(*shares[id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy(unsigned const id)
|
||||||
|
{
|
||||||
|
if (!id || id >= MAX_SHARES)
|
||||||
|
return;
|
||||||
|
|
||||||
|
scheduler.remove(share(id));
|
||||||
|
shares[id].destruct();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned time()
|
||||||
|
{
|
||||||
|
return scheduler.quota() - scheduler.residual();
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_check(unsigned const l, unsigned const c, unsigned const t,
|
||||||
|
unsigned const s, unsigned const q)
|
||||||
|
{
|
||||||
|
current_time += c;
|
||||||
|
scheduler.update(current_time);
|
||||||
|
unsigned const st = time();
|
||||||
|
if (t != st) {
|
||||||
|
log("wrong time ", st, " in line ", l);
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
Cpu_share & hs = scheduler.head();
|
||||||
|
unsigned const hq = scheduler.head_quota();
|
||||||
|
if (&hs != &share(s)) {
|
||||||
|
log("wrong share ", share_id(hs), " in line ", l);
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
if (hq != q) {
|
||||||
|
log("wrong quota ", hq, " in line ", l);
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ready_check(unsigned const l, unsigned const s, bool const x)
|
||||||
|
{
|
||||||
|
scheduler.ready(share(s));
|
||||||
|
if (scheduler.need_to_schedule() != x) {
|
||||||
|
log("wrong check result ", scheduler.need_to_schedule(), " in line ", l);
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Data * data()
|
|
||||||
{
|
|
||||||
static Data d;
|
|
||||||
return &d;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void done()
|
|
||||||
{
|
|
||||||
Genode::log("done");
|
|
||||||
while (1) ;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
unsigned share_id(void * const pointer)
|
|
||||||
{
|
|
||||||
addr_t const address = (addr_t)pointer;
|
|
||||||
addr_t const base = (addr_t)data()->shares;
|
|
||||||
if (address < base || address >= base + sizeof(data()->shares)) {
|
|
||||||
return 0; }
|
|
||||||
return (unsigned)((address - base) / sizeof(Cpu_share) + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Cpu_share * share(unsigned const id)
|
|
||||||
{
|
|
||||||
if (!id) { return &data()->idle; }
|
|
||||||
return reinterpret_cast<Cpu_share *>(&data()->shares[id - 1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void create(unsigned const id)
|
|
||||||
{
|
|
||||||
Cpu_share * const s = share(id);
|
|
||||||
void * const p = (void *)s;
|
|
||||||
switch (id) {
|
|
||||||
case 1: construct_at<Cpu_share>(p, 2, 230); break;
|
|
||||||
case 2: construct_at<Cpu_share>(p, 0, 170); break;
|
|
||||||
case 3: construct_at<Cpu_share>(p, 3, 110); break;
|
|
||||||
case 4: construct_at<Cpu_share>(p, 1, 90); break;
|
|
||||||
case 5: construct_at<Cpu_share>(p, 3, 120); break;
|
|
||||||
case 6: construct_at<Cpu_share>(p, 3, 0); break;
|
|
||||||
case 7: construct_at<Cpu_share>(p, 2, 180); break;
|
|
||||||
case 8: construct_at<Cpu_share>(p, 2, 100); break;
|
|
||||||
case 9: construct_at<Cpu_share>(p, 2, 0); break;
|
|
||||||
default: return;
|
|
||||||
}
|
|
||||||
data()->scheduler.insert(*s);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void destroy(unsigned const id)
|
|
||||||
{
|
|
||||||
Cpu_share * const s = share(id);
|
|
||||||
data()->scheduler.remove(*s);
|
|
||||||
s->~Cpu_share();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
unsigned time()
|
|
||||||
{
|
|
||||||
return data()->scheduler.quota() -
|
|
||||||
data()->scheduler.residual();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void update_check(unsigned const l, unsigned const c, unsigned const t,
|
|
||||||
unsigned const s, unsigned const q)
|
|
||||||
{
|
|
||||||
data()->scheduler.update(c);
|
|
||||||
unsigned const st = time();
|
|
||||||
if (t != st) {
|
|
||||||
Genode::log("wrong time ", st, " in line ", l);
|
|
||||||
done();
|
|
||||||
}
|
|
||||||
Cpu_share &hs = data()->scheduler.head();
|
|
||||||
unsigned const hq = data()->scheduler.head_quota();
|
|
||||||
if (&hs != share(s)) {
|
|
||||||
unsigned const hi = share_id(&hs);
|
|
||||||
Genode::log("wrong share ", hi, " in line ", l);
|
|
||||||
done();
|
|
||||||
}
|
|
||||||
if (hq != q) {
|
|
||||||
Genode::log("wrong quota ", hq, " in line ", l);
|
|
||||||
done();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ready_check(unsigned const l, unsigned const s, bool const x)
|
|
||||||
{
|
|
||||||
data()->scheduler.ready_check(*share(s));
|
|
||||||
if (data()->scheduler.need_to_schedule() != x) {
|
|
||||||
Genode::log("wrong check result ", data()->scheduler.need_to_schedule(), " in line ", l);
|
|
||||||
done();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Shortcuts for all basic operations that the test consists of
|
* Shortcuts for all basic operations that the test consists of
|
||||||
@@ -144,10 +129,10 @@ void ready_check(unsigned const l, unsigned const s, bool const x)
|
|||||||
|
|
||||||
#define C(s) create(s);
|
#define C(s) create(s);
|
||||||
#define D(s) destroy(s);
|
#define D(s) destroy(s);
|
||||||
#define A(s) data()->scheduler.ready(*share(s));
|
#define A(s) scheduler.ready(share(s));
|
||||||
#define I(s) data()->scheduler.unready(*share(s));
|
#define I(s) scheduler.unready(share(s));
|
||||||
#define Y data()->scheduler.yield();
|
#define Y scheduler.yield();
|
||||||
#define Q(s, q) data()->scheduler.quota(*share(s), q);
|
#define Q(s, q) scheduler.quota(share(s), q);
|
||||||
#define U(c, t, s, q) update_check(__LINE__, c, t, s, q);
|
#define U(c, t, s, q) update_check(__LINE__, c, t, s, q);
|
||||||
#define O(s) ready_check(__LINE__, s, true);
|
#define O(s) ready_check(__LINE__, s, true);
|
||||||
#define N(s) ready_check(__LINE__, s, false);
|
#define N(s) ready_check(__LINE__, s, false);
|
||||||
@@ -157,6 +142,13 @@ void ready_check(unsigned const l, unsigned const s, bool const x)
|
|||||||
* Main routine
|
* Main routine
|
||||||
*/
|
*/
|
||||||
void Component::construct(Genode::Env &)
|
void Component::construct(Genode::Env &)
|
||||||
|
{
|
||||||
|
static Main main;
|
||||||
|
main.test();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Main::test()
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Step-by-step testing
|
* Step-by-step testing
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
FROM_BASE_LINUX := etc src/lib/syscall src/lib/lx_hybrid lib/import include
|
FROM_BASE_LINUX := etc src/lib/syscall src/lib/lx_hybrid lib/import include
|
||||||
FROM_BASE_LINUX_AND_BASE := lib/mk src/lib/base src/include
|
FROM_BASE_LINUX_AND_BASE := src/lib/base src/include
|
||||||
FROM_BASE := src/lib/timeout
|
|
||||||
|
|
||||||
content: $(FROM_BASE_LINUX) $(FROM_BASE_LINUX_AND_BASE) $(FROM_BASE) LICENSE
|
content: $(FROM_BASE_LINUX) $(FROM_BASE_LINUX_AND_BASE) LICENSE
|
||||||
|
|
||||||
$(FROM_BASE_LINUX):
|
$(FROM_BASE_LINUX):
|
||||||
mkdir -p $@
|
mkdir -p $@
|
||||||
@@ -13,9 +12,30 @@ $(FROM_BASE_LINUX_AND_BASE):
|
|||||||
cp -r $(GENODE_DIR)/repos/base/$@/* $@
|
cp -r $(GENODE_DIR)/repos/base/$@/* $@
|
||||||
cp -r $(REP_DIR)/$@/* $@
|
cp -r $(REP_DIR)/$@/* $@
|
||||||
|
|
||||||
$(FROM_BASE):
|
BASE_LIB_MK_CONTENT := \
|
||||||
|
$(addprefix lib/mk/,base-common.inc timeout.mk)
|
||||||
|
|
||||||
|
content: $(BASE_LIB_MK_CONTENT)
|
||||||
|
|
||||||
|
$(BASE_LIB_MK_CONTENT):
|
||||||
|
mkdir -p $(dir $@)
|
||||||
|
cp $(GENODE_DIR)/repos/base/$@ $@
|
||||||
|
|
||||||
|
content: src/lib/timeout
|
||||||
|
|
||||||
|
src/lib/timeout:
|
||||||
mkdir -p $@
|
mkdir -p $@
|
||||||
cp -r $(GENODE_DIR)/repos/base/$@/* $@
|
cp -r $(GENODE_DIR)/repos/base/$@/* $@
|
||||||
|
|
||||||
|
BASE_LINUX_LIB_MK_CONTENT := \
|
||||||
|
$(addprefix lib/mk/,lx_hybrid.mk base-linux.inc base-linux-common.mk) \
|
||||||
|
$(foreach S,arm arm_64 x86_32 x86_64,lib/mk/spec/$S/syscall-linux.mk)
|
||||||
|
|
||||||
|
content: $(BASE_LINUX_LIB_MK_CONTENT)
|
||||||
|
|
||||||
|
$(BASE_LINUX_LIB_MK_CONTENT):
|
||||||
|
mkdir -p $(dir $@)
|
||||||
|
cp $(REP_DIR)/$@ $@
|
||||||
|
|
||||||
LICENSE:
|
LICENSE:
|
||||||
cp $(GENODE_DIR)/LICENSE $@
|
cp $(GENODE_DIR)/LICENSE $@
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2022-04-12 dcb2c9200b333adb17f9a8737620cbd84f641408
|
2022-10-11 4544924c73b2ee1d8d2717672320f14732807267
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ content:
|
|||||||
mv lib/mk/spec/$$spec/ld-linux.mk lib/mk/spec/$$spec/ld.mk; done;
|
mv lib/mk/spec/$$spec/ld-linux.mk lib/mk/spec/$$spec/ld.mk; done;
|
||||||
sed -i "/TARGET/s/core-linux/core/" src/core/linux/target.mk
|
sed -i "/TARGET/s/core-linux/core/" src/core/linux/target.mk
|
||||||
sed -i "s/BOARD.*unknown/BOARD := linux/" lib/mk/core-linux.inc
|
sed -i "s/BOARD.*unknown/BOARD := linux/" lib/mk/core-linux.inc
|
||||||
sed -i "s/ld-linux/ld/" src/lib/ld/linux/target.mk
|
|
||||||
sed -i "s/linux_timer_drv/timer/" src/timer/linux/target.mk
|
sed -i "s/linux_timer_drv/timer/" src/timer/linux/target.mk
|
||||||
rm -rf src/lib/initramfs
|
rm -rf src/initramfs
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2022-05-24 4aea382035415c79bf5d551642ebfa64d42e4d21
|
2022-10-11 d7e12d81f12f081bb7c00233c18f3c8ac2f00d67
|
||||||
|
|||||||
@@ -5,14 +5,14 @@ REQUIRES = x86_64
|
|||||||
INITRAMFS = initramfs
|
INITRAMFS = initramfs
|
||||||
INITRAMFS_SRC_C = init.c
|
INITRAMFS_SRC_C = init.c
|
||||||
|
|
||||||
EXT_OBJECTS += $(BUILD_BASE_DIR)/lib/initramfs/$(INITRAMFS)
|
EXT_OBJECTS += $(BUILD_BASE_DIR)/initramfs/$(INITRAMFS)
|
||||||
|
|
||||||
$(TARGET): $(INITRAMFS)
|
$(TARGET): $(INITRAMFS)
|
||||||
|
|
||||||
$(INITRAMFS): $(INITRAMFS_SRC_C)
|
$(INITRAMFS): $(INITRAMFS_SRC_C)
|
||||||
$(MSG_BUILD)$(INITRAMFS)
|
$(MSG_BUILD)$(INITRAMFS)
|
||||||
$(VERBOSE)gcc $^ -O0 $(CC_MARCH) -Wall -W -Wextra -Werror -std=gnu99 -o $@ -Wl,-O3 -Wl,--as-needed -static
|
$(VERBOSE)gcc $^ -O0 $(CC_MARCH) -Wall -W -Wextra -Werror -std=gnu99 -o $@ -Wl,-O3 -Wl,--as-needed -static
|
||||||
$(VERBOSE)ln -sf $(BUILD_BASE_DIR)/lib/initramfs/$(INITRAMFS) $(BUILD_BASE_DIR)/bin/
|
$(VERBOSE)ln -sf $(BUILD_BASE_DIR)/initramfs/$(INITRAMFS) $(BUILD_BASE_DIR)/bin/
|
||||||
|
|
||||||
clean_initramfs:
|
clean_initramfs:
|
||||||
$(VERBOSE)rm -rf $(INITRAMFS)
|
$(VERBOSE)rm -rf $(INITRAMFS)
|
||||||
@@ -172,6 +172,24 @@ void Region_map_mmap::_add_to_rmap(Region const ®ion)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tracing must be inhibited in attach/detach as RPC trace points may trigger
|
||||||
|
* attachment of trace dataspaces, which would result in nested mutex
|
||||||
|
* acquisition.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Genode { extern bool inhibit_tracing; }
|
||||||
|
|
||||||
|
struct Inhibit_tracing_guard
|
||||||
|
{
|
||||||
|
bool old_value = inhibit_tracing;
|
||||||
|
|
||||||
|
Inhibit_tracing_guard() { inhibit_tracing = true; }
|
||||||
|
|
||||||
|
~Inhibit_tracing_guard() { inhibit_tracing = old_value; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
Region_map::Local_addr Region_map_mmap::attach(Dataspace_capability ds,
|
Region_map::Local_addr Region_map_mmap::attach(Dataspace_capability ds,
|
||||||
size_t size, off_t offset,
|
size_t size, off_t offset,
|
||||||
bool use_local_addr,
|
bool use_local_addr,
|
||||||
@@ -180,6 +198,8 @@ Region_map::Local_addr Region_map_mmap::attach(Dataspace_capability ds,
|
|||||||
{
|
{
|
||||||
Mutex::Guard mutex_guard(mutex());
|
Mutex::Guard mutex_guard(mutex());
|
||||||
|
|
||||||
|
Inhibit_tracing_guard it_guard { };
|
||||||
|
|
||||||
/* only support attach_at for sub RM sessions */
|
/* only support attach_at for sub RM sessions */
|
||||||
if (_sub_rm && !use_local_addr) {
|
if (_sub_rm && !use_local_addr) {
|
||||||
error("Region_map_mmap::attach: attaching w/o local addr not supported");
|
error("Region_map_mmap::attach: attaching w/o local addr not supported");
|
||||||
@@ -325,6 +345,8 @@ void Region_map_mmap::detach(Region_map::Local_addr local_addr)
|
|||||||
{
|
{
|
||||||
Mutex::Guard mutex_guard(mutex());
|
Mutex::Guard mutex_guard(mutex());
|
||||||
|
|
||||||
|
Inhibit_tracing_guard it_guard { };
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Cases
|
* Cases
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
TARGET = ld-linux.lib
|
|
||||||
LIBS = ld-linux
|
|
||||||
|
|
||||||
BUILD_ARTIFACTS := ld-linux.lib.so
|
|
||||||
@@ -260,6 +260,30 @@ namespace Nova {
|
|||||||
*/
|
*/
|
||||||
enum Pd_op { TRANSFER_QUOTA = 0U, PD_DEBUG = 2U };
|
enum Pd_op { TRANSFER_QUOTA = 0U, PD_DEBUG = 2U };
|
||||||
|
|
||||||
|
class Gsi_flags
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
uint8_t _value { 0 };
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum Mode { HIGH, LOW, EDGE };
|
||||||
|
|
||||||
|
Gsi_flags() { }
|
||||||
|
|
||||||
|
Gsi_flags(Mode m)
|
||||||
|
{
|
||||||
|
switch (m) {
|
||||||
|
case HIGH: _value = 0b110; break; /* level-high */
|
||||||
|
case LOW: _value = 0b111; break; /* level-low */
|
||||||
|
case EDGE: _value = 0b100; break; /* edge-triggered */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t value() const { return _value; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class Descriptor
|
class Descriptor
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -457,12 +457,12 @@ namespace Nova {
|
|||||||
ALWAYS_INLINE
|
ALWAYS_INLINE
|
||||||
inline uint8_t assign_gsi(mword_t sm, mword_t dev, mword_t cpu,
|
inline uint8_t assign_gsi(mword_t sm, mword_t dev, mword_t cpu,
|
||||||
mword_t &msi_addr, mword_t &msi_data,
|
mword_t &msi_addr, mword_t &msi_data,
|
||||||
mword_t si = ~0UL)
|
mword_t si = ~0UL, Gsi_flags flags = Gsi_flags())
|
||||||
{
|
{
|
||||||
msi_addr = dev;
|
msi_addr = dev;
|
||||||
msi_data = cpu;
|
msi_data = cpu;
|
||||||
|
|
||||||
return syscall_5(NOVA_ASSIGN_GSI, 0, sm, msi_addr, msi_data, si);
|
return syscall_5(NOVA_ASSIGN_GSI, flags.value(), sm, msi_addr, msi_data, si);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -402,11 +402,11 @@ namespace Nova {
|
|||||||
ALWAYS_INLINE
|
ALWAYS_INLINE
|
||||||
inline uint8_t assign_gsi(mword_t sm, mword_t dev, mword_t cpu,
|
inline uint8_t assign_gsi(mword_t sm, mword_t dev, mword_t cpu,
|
||||||
mword_t &msi_addr, mword_t &msi_data,
|
mword_t &msi_addr, mword_t &msi_data,
|
||||||
mword_t si = ~0UL)
|
mword_t si = ~0UL, Gsi_flags flags = Gsi_flags())
|
||||||
{
|
{
|
||||||
msi_addr = dev;
|
msi_addr = dev;
|
||||||
msi_data = cpu;
|
msi_data = cpu;
|
||||||
return syscall_5(NOVA_ASSIGN_GSI, 0, sm, msi_addr, msi_data, si);
|
return syscall_5(NOVA_ASSIGN_GSI, flags.value(), sm, msi_addr, msi_data, si);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* _INCLUDE__SPEC__64BIT__NOVA__SYSCALLS_H_ */
|
#endif /* _INCLUDE__SPEC__64BIT__NOVA__SYSCALLS_H_ */
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ LICENSE := GPLv2
|
|||||||
VERSION := git
|
VERSION := git
|
||||||
DOWNLOADS := nova.git
|
DOWNLOADS := nova.git
|
||||||
|
|
||||||
# r10 branch
|
# feature/numa branch
|
||||||
URL(nova) := https://github.com/mmueller41/NOVA.git
|
URL(nova) := https://github.com/mmueller41/NOVA.git
|
||||||
REV(nova) := 6479677bd61db47bcdcb4bd796566f83b9f655ef
|
REV(nova) := 6479677bd61db47bcdcb4bd796566f83b9f655ef
|
||||||
DIR(nova) := src/kernel/nova
|
DIR(nova) := src/kernel/nova
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
FROM_BASE_NOVA := etc include
|
FROM_BASE_NOVA := etc include
|
||||||
FROM_BASE := lib/mk/timeout.mk src/lib/timeout
|
|
||||||
|
# base-nova.lib.a depends on timeout.lib.a, which includes base/internal/gloabls.h
|
||||||
|
FROM_BASE := lib/mk/timeout.mk src/lib/timeout \
|
||||||
|
src/include/base/internal/globals.h
|
||||||
|
|
||||||
content: $(FROM_BASE_NOVA) $(FROM_BASE) LICENSE
|
content: $(FROM_BASE_NOVA) $(FROM_BASE) LICENSE
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2022-05-24 91bc8d51bbe703d56f5671019d14e4636f21bf1f
|
2022-10-11 4458ea63a69ae070e19a3cb09a403137755d2cb0
|
||||||
|
|||||||
@@ -15,8 +15,7 @@ src/kernel/nova: src/kernel
|
|||||||
|
|
||||||
content:
|
content:
|
||||||
for spec in x86_32 x86_64; do \
|
for spec in x86_32 x86_64; do \
|
||||||
mv lib/mk/spec/$$spec/ld-nova.mk lib/mk/spec/$$spec/ld.mk; \
|
mv lib/mk/spec/$$spec/ld-nova.mk lib/mk/spec/$$spec/ld.mk; \
|
||||||
done;
|
done;
|
||||||
sed -i "s/ld-nova/ld/" src/lib/ld/nova/target.mk
|
|
||||||
sed -i "s/nova_timer_drv/timer/" src/timer/nova/target.mk
|
sed -i "s/nova_timer_drv/timer/" src/timer/nova/target.mk
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2022-05-24 8b59a28ade1392bae4aa772bbead1584a2dde1de
|
2022-10-11 574204b7d442811236bba60e4fe3f79e34fe9985
|
||||||
|
|||||||
@@ -13,7 +13,9 @@
|
|||||||
#ifndef _CORE__INCLUDE__IRQ_OBJECT_H_
|
#ifndef _CORE__INCLUDE__IRQ_OBJECT_H_
|
||||||
#define _CORE__INCLUDE__IRQ_OBJECT_H_
|
#define _CORE__INCLUDE__IRQ_OBJECT_H_
|
||||||
|
|
||||||
namespace Genode { class Irq_object; }
|
#include <nova/syscall-generic.h> /* Gsi_flags */
|
||||||
|
|
||||||
|
namespace Genode { class Irq_object; class Irq_args; }
|
||||||
|
|
||||||
class Genode::Irq_object
|
class Genode::Irq_object
|
||||||
{
|
{
|
||||||
@@ -26,22 +28,24 @@ class Genode::Irq_object
|
|||||||
addr_t _msi_data;
|
addr_t _msi_data;
|
||||||
addr_t _device_phys = 0; /* PCI config extended address */
|
addr_t _device_phys = 0; /* PCI config extended address */
|
||||||
|
|
||||||
|
Nova::Gsi_flags _gsi_flags { };
|
||||||
|
|
||||||
enum { KERNEL_CAP_COUNT_LOG2 = 0 };
|
enum { KERNEL_CAP_COUNT_LOG2 = 0 };
|
||||||
|
|
||||||
Genode::addr_t irq_sel() const { return _kernel_caps; }
|
addr_t irq_sel() const { return _kernel_caps; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Irq_object();
|
Irq_object();
|
||||||
~Irq_object();
|
~Irq_object();
|
||||||
|
|
||||||
Genode::addr_t msi_address() const { return _msi_addr; }
|
addr_t msi_address() const { return _msi_addr; }
|
||||||
Genode::addr_t msi_value() const { return _msi_data; }
|
addr_t msi_value() const { return _msi_data; }
|
||||||
|
|
||||||
void sigh(Signal_context_capability cap);
|
void sigh(Signal_context_capability cap);
|
||||||
void ack_irq();
|
void ack_irq();
|
||||||
|
|
||||||
void start(unsigned irq, Genode::addr_t);
|
void start(unsigned irq, addr_t, Irq_args const &);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _CORE__INCLUDE__IRQ_OBJECT_H_ */
|
#endif /* _CORE__INCLUDE__IRQ_OBJECT_H_ */
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
/* core includes */
|
/* core includes */
|
||||||
#include <irq_root.h>
|
#include <irq_root.h>
|
||||||
|
#include <irq_args.h>
|
||||||
#include <platform.h>
|
#include <platform.h>
|
||||||
|
|
||||||
/* NOVA includes */
|
/* NOVA includes */
|
||||||
@@ -27,13 +28,12 @@
|
|||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
|
|
||||||
|
|
||||||
static bool irq_ctrl(Genode::addr_t irq_sel,
|
static bool irq_ctrl(addr_t irq_sel, addr_t &msi_addr, addr_t &msi_data,
|
||||||
Genode::addr_t &msi_addr, Genode::addr_t &msi_data,
|
addr_t sig_sel, Nova::Gsi_flags flags, addr_t virt_addr)
|
||||||
Genode::addr_t sig_sel, Genode::addr_t virt_addr = 0)
|
|
||||||
{
|
{
|
||||||
/* assign IRQ to CPU && request msi data to be used by driver */
|
/* assign IRQ to CPU && request msi data to be used by driver */
|
||||||
uint8_t res = Nova::assign_gsi(irq_sel, virt_addr, boot_cpu(),
|
uint8_t res = Nova::assign_gsi(irq_sel, virt_addr, boot_cpu(),
|
||||||
msi_addr, msi_data, sig_sel);
|
msi_addr, msi_data, sig_sel, flags);
|
||||||
|
|
||||||
if (res != Nova::NOVA_OK)
|
if (res != Nova::NOVA_OK)
|
||||||
error("setting up MSI failed - error ", res);
|
error("setting up MSI failed - error ", res);
|
||||||
@@ -46,30 +46,28 @@ static bool irq_ctrl(Genode::addr_t irq_sel,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool associate(Genode::addr_t irq_sel,
|
static bool associate_gsi(addr_t irq_sel, Signal_context_capability sig_cap,
|
||||||
Genode::addr_t &msi_addr, Genode::addr_t &msi_data,
|
Nova::Gsi_flags gsi_flags)
|
||||||
Genode::Signal_context_capability sig_cap,
|
|
||||||
Genode::addr_t virt_addr = 0)
|
|
||||||
{
|
|
||||||
return irq_ctrl(irq_sel, msi_addr, msi_data, sig_cap.local_name(),
|
|
||||||
virt_addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void deassociate(Genode::addr_t irq_sel)
|
|
||||||
{
|
{
|
||||||
addr_t dummy1 = 0, dummy2 = 0;
|
addr_t dummy1 = 0, dummy2 = 0;
|
||||||
|
|
||||||
if (!irq_ctrl(irq_sel, dummy1, dummy2, irq_sel))
|
return irq_ctrl(irq_sel, dummy1, dummy2, sig_cap.local_name(), gsi_flags, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void deassociate(addr_t irq_sel)
|
||||||
|
{
|
||||||
|
addr_t dummy1 = 0, dummy2 = 0;
|
||||||
|
|
||||||
|
if (!irq_ctrl(irq_sel, dummy1, dummy2, irq_sel, Nova::Gsi_flags(), 0))
|
||||||
warning("Irq could not be de-associated");
|
warning("Irq could not be de-associated");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool msi(Genode::addr_t irq_sel, Genode::addr_t phys_mem,
|
static bool associate_msi(addr_t irq_sel, addr_t phys_mem, addr_t &msi_addr,
|
||||||
Genode::addr_t &msi_addr, Genode::addr_t &msi_data,
|
addr_t &msi_data, Signal_context_capability sig_cap)
|
||||||
Genode::Signal_context_capability sig_cap)
|
|
||||||
{
|
{
|
||||||
return platform().region_alloc().alloc_aligned(4096, 12).convert<bool>(
|
return platform().region_alloc().alloc_aligned(4096, 12).convert<bool>(
|
||||||
|
|
||||||
[&] (void *virt_ptr) {
|
[&] (void *virt_ptr) {
|
||||||
|
|
||||||
@@ -89,7 +87,7 @@ static bool msi(Genode::addr_t irq_sel, Genode::addr_t phys_mem,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* try to assign MSI to device */
|
/* try to assign MSI to device */
|
||||||
bool res = associate(irq_sel, msi_addr, msi_data, sig_cap, virt_addr);
|
bool res = irq_ctrl(irq_sel, msi_addr, msi_data, sig_cap.local_name(), Nova::Gsi_flags(), virt_addr);
|
||||||
|
|
||||||
unmap_local(Nova::Mem_crd(virt_addr >> 12, 0, Rights(true, true, true)));
|
unmap_local(Nova::Mem_crd(virt_addr >> 12, 0, Rights(true, true, true)));
|
||||||
platform().region_alloc().free(virt_ptr, 4096);
|
platform().region_alloc().free(virt_ptr, 4096);
|
||||||
@@ -118,11 +116,12 @@ void Irq_object::sigh(Signal_context_capability cap)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* associate GSI or MSI to device belonging to device_phys */
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
if (_device_phys)
|
if (_device_phys)
|
||||||
ok = msi(irq_sel(), _device_phys, _msi_addr, _msi_data, cap);
|
ok = associate_msi(irq_sel(), _device_phys, _msi_addr, _msi_data, cap);
|
||||||
else
|
else
|
||||||
ok = associate(irq_sel(), _msi_addr, _msi_data, cap);
|
ok = associate_gsi(irq_sel(), cap, _gsi_flags);
|
||||||
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
deassociate(irq_sel());
|
deassociate(irq_sel());
|
||||||
@@ -141,7 +140,7 @@ void Irq_object::ack_irq()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Irq_object::start(unsigned irq, Genode::addr_t const device_phys)
|
void Irq_object::start(unsigned irq, addr_t const device_phys, Irq_args const &irq_args)
|
||||||
{
|
{
|
||||||
/* map IRQ SM cap from kernel to core at irq_sel selector */
|
/* map IRQ SM cap from kernel to core at irq_sel selector */
|
||||||
using Nova::Obj_crd;
|
using Nova::Obj_crd;
|
||||||
@@ -158,12 +157,29 @@ void Irq_object::start(unsigned irq, Genode::addr_t const device_phys)
|
|||||||
throw Service_denied();
|
throw Service_denied();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* initialize GSI IRQ flags */
|
||||||
|
auto gsi_flags = [] (Irq_args const &args) {
|
||||||
|
if (args.trigger() == Irq_session::TRIGGER_UNCHANGED
|
||||||
|
|| args.polarity() == Irq_session::POLARITY_UNCHANGED)
|
||||||
|
return Nova::Gsi_flags();
|
||||||
|
|
||||||
|
if (args.trigger() == Irq_session::TRIGGER_EDGE)
|
||||||
|
return Nova::Gsi_flags(Nova::Gsi_flags::EDGE);
|
||||||
|
|
||||||
|
if (args.polarity() == Irq_session::POLARITY_HIGH)
|
||||||
|
return Nova::Gsi_flags(Nova::Gsi_flags::HIGH);
|
||||||
|
else
|
||||||
|
return Nova::Gsi_flags(Nova::Gsi_flags::LOW);
|
||||||
|
};
|
||||||
|
|
||||||
|
_gsi_flags = gsi_flags(irq_args);
|
||||||
|
|
||||||
/* associate GSI or MSI to device belonging to device_phys */
|
/* associate GSI or MSI to device belonging to device_phys */
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
if (device_phys)
|
if (device_phys)
|
||||||
ok = msi(irq_sel(), device_phys, _msi_addr, _msi_data, _sigh_cap);
|
ok = associate_msi(irq_sel(), device_phys, _msi_addr, _msi_data, _sigh_cap);
|
||||||
else
|
else
|
||||||
ok = associate(irq_sel(), _msi_addr, _msi_data, _sigh_cap);
|
ok = associate_gsi(irq_sel(), _sigh_cap, _gsi_flags);
|
||||||
|
|
||||||
if (!ok)
|
if (!ok)
|
||||||
throw Service_denied();
|
throw Service_denied();
|
||||||
@@ -212,7 +228,9 @@ Irq_session_component::Irq_session_component(Range_allocator &irq_alloc,
|
|||||||
:
|
:
|
||||||
_irq_number(~0U), _irq_alloc(irq_alloc), _irq_object()
|
_irq_number(~0U), _irq_alloc(irq_alloc), _irq_object()
|
||||||
{
|
{
|
||||||
long irq_number = Arg_string::find_arg(args, "irq_number").long_value(-1);
|
Irq_args const irq_args(args);
|
||||||
|
|
||||||
|
long irq_number = irq_args.irq_number();
|
||||||
long device_phys = Arg_string::find_arg(args, "device_config_phys").long_value(0);
|
long device_phys = Arg_string::find_arg(args, "device_config_phys").long_value(0);
|
||||||
if (device_phys) {
|
if (device_phys) {
|
||||||
|
|
||||||
@@ -232,7 +250,7 @@ Irq_session_component::Irq_session_component(Range_allocator &irq_alloc,
|
|||||||
|
|
||||||
_irq_number = (unsigned)irq_number;
|
_irq_number = (unsigned)irq_number;
|
||||||
|
|
||||||
_irq_object.start(_irq_number, device_phys);
|
_irq_object.start(_irq_number, device_phys, irq_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -241,7 +259,7 @@ Irq_session_component::~Irq_session_component()
|
|||||||
if (_irq_number == ~0U)
|
if (_irq_number == ~0U)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Genode::addr_t free_irq = _irq_number;
|
addr_t free_irq = _irq_number;
|
||||||
_irq_alloc.free((void *)free_irq);
|
_irq_alloc.free((void *)free_irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,13 +270,13 @@ void Irq_session_component::ack_irq()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Irq_session_component::sigh(Genode::Signal_context_capability cap)
|
void Irq_session_component::sigh(Signal_context_capability cap)
|
||||||
{
|
{
|
||||||
_irq_object.sigh(cap);
|
_irq_object.sigh(cap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Genode::Irq_session::Info Irq_session_component::info()
|
Irq_session::Info Irq_session_component::info()
|
||||||
{
|
{
|
||||||
if (!_irq_object.msi_address() || !_irq_object.msi_value())
|
if (!_irq_object.msi_address() || !_irq_object.msi_value())
|
||||||
return { .type = Info::Type::INVALID, .address = 0, .value = 0 };
|
return { .type = Info::Type::INVALID, .address = 0, .value = 0 };
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
TARGET = ld-nova
|
|
||||||
LIBS = ld-nova
|
|
||||||
@@ -19,8 +19,7 @@ src/kernel/okl4: src/kernel
|
|||||||
|
|
||||||
content:
|
content:
|
||||||
for spec in x86_32; do \
|
for spec in x86_32; do \
|
||||||
mv lib/mk/spec/$$spec/ld-okl4.mk lib/mk/spec/$$spec/ld.mk; \
|
mv lib/mk/spec/$$spec/ld-okl4.mk lib/mk/spec/$$spec/ld.mk; \
|
||||||
done;
|
done;
|
||||||
sed -i "s/ld-okl4/ld/" src/lib/ld/okl4/target.mk
|
|
||||||
sed -i "s/pit_timer_drv/timer/" src/timer/pit/target.inc
|
sed -i "s/pit_timer_drv/timer/" src/timer/pit/target.inc
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2022-05-24 3b2acba4ebd649394e26217802598cf650a4b226
|
2022-10-11 b81b8b94731cda35017a740b0110ff4e8e233e07
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
TARGET = ld-okl4
|
|
||||||
LIBS = ld-okl4
|
|
||||||
@@ -21,6 +21,5 @@ content:
|
|||||||
for spec in x86_32; do \
|
for spec in x86_32; do \
|
||||||
mv lib/mk/spec/$$spec/ld-pistachio.mk lib/mk/spec/$$spec/ld.mk; \
|
mv lib/mk/spec/$$spec/ld-pistachio.mk lib/mk/spec/$$spec/ld.mk; \
|
||||||
done;
|
done;
|
||||||
sed -i "s/ld-pistachio/ld/" src/lib/ld/pistachio/target.mk
|
|
||||||
sed -i "s/pit_timer_drv/timer/" src/timer/pit/target.inc
|
sed -i "s/pit_timer_drv/timer/" src/timer/pit/target.inc
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2022-05-24 ca2c90ebcbaa61ade7373d6ea48a608912cd2629
|
2022-10-11 b522663f9c8c779f255e2a5eb37f98b4301c5446
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
TARGET = ld-pistachio
|
|
||||||
LIBS = ld-pistachio
|
|
||||||
@@ -35,7 +35,6 @@ etc/board.conf:
|
|||||||
|
|
||||||
content:
|
content:
|
||||||
mv lib/mk/spec/arm/ld-sel4.mk lib/mk/spec/arm/ld.mk;
|
mv lib/mk/spec/arm/ld-sel4.mk lib/mk/spec/arm/ld.mk;
|
||||||
sed -i "s/ld-sel4/ld/" src/lib/ld/sel4/target.mk
|
|
||||||
sed -i "s/imx6_timer_drv/timer/" src/timer/epit/imx6/target.inc
|
sed -i "s/imx6_timer_drv/timer/" src/timer/epit/imx6/target.inc
|
||||||
find lib/mk/spec -name kernel-sel4-*.mk -o -name syscall-sel4-*.mk |\
|
find lib/mk/spec -name kernel-sel4-*.mk -o -name syscall-sel4-*.mk |\
|
||||||
grep -v "sel4-imx6q_sabrelite.mk" | xargs rm -rf
|
grep -v "sel4-imx6q_sabrelite.mk" | xargs rm -rf
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user