diff --git a/VERSION b/VERSION index 3dce2e921c..f88da62e24 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -24.08 +24.11 diff --git a/doc/build_system.txt b/doc/build_system.txt deleted file mode 100644 index de926c09f3..0000000000 --- a/doc/build_system.txt +++ /dev/null @@ -1,517 +0,0 @@ - - - ======================= - The Genode build system - ======================= - - - Norman Feske - -Abstract -######## - -The Genode OS Framework comes with a custom build system that is designed for -the creation of highly modular and portable systems software. Understanding -its basic concepts is pivotal for using the full potential of the framework. -This document introduces those concepts and the best practises of putting them -to good use. Beside building software components from source code, common -and repetitive development tasks are the testing of individual components -and the integration of those components into complex system scenarios. To -streamline such tasks, the build system is accompanied with special tooling -support. This document introduces those tools. - - -Build directories and repositories -################################## - -The build system is supposed to never touch the source tree. The procedure of -building components and integrating them into system scenarios is done at -a distinct build directory. One build directory targets a specific platform, -i.e., a kernel and hardware architecture. Because the source tree is decoupled -from the build directory, one source tree can have many different build -directories associated, each targeted at another platform. - -The recommended way for creating a build directory is the use of the -'create_builddir' tool located at '/tool/'. By starting the tool -without arguments, its usage information will be printed. For creating a new -build directory, one of the listed target platforms must be specified. -Furthermore, the location of the new build directory has to be specified via -the 'BUILD_DIR=' argument. For example: - -! cd -! ./tool/create_builddir linux_x86 BUILD_DIR=/tmp/build.linux_x86 - -This command will create a new build directory for the Linux/x86 platform -at _/tmp/build.linux_x86/_. - - -Build-directory configuration via 'build.conf' -============================================== - -The fresh build directory will contain a 'Makefile', which is a symlink to -_tool/builddir/build.mk_. This makefile is the front end of the build system -and not supposed to be edited. Beside the makefile, there is a _etc/_ -subdirectory that contains the build-directory configuration. For most -platforms, there is only a single _build.conf_ file, which defines the parts of -the Genode source tree incorporated in the build process. Those parts are -called _repositories_. - -The repository concept allows for keeping the source code well separated for -different concerns. For example, the platform-specific code for each target -platform is located in a dedicated _base-_ repository. Also, different -abstraction levels and features of the system are residing in different -repositories. The _etc/build.conf_ file defines the set of repositories to -consider in the build process. At build time, the build system overlays the -directory structures of all repositories specified via the 'REPOSITORIES' -declaration to form a single logical source tree. By changing the list of -'REPOSITORIES', the view of the build system on the source tree can be altered. -The _etc/build.conf_ as found in a fresh created build directory will list the -_base-_ repository of the platform selected at the 'create_builddir' -command line as well as the 'base', 'os', and 'demo' repositories needed for -compiling Genode's default demonstration scenario. Furthermore, there are a -number of commented-out lines that can be uncommented for enabling additional -repositories. - -Note that the order of the repositories listed in the 'REPOSITORIES' declaration -is important. Front-most repositories shadow subsequent repositories. This -makes the repository mechanism a powerful tool for tweaking existing repositories: -By adding a custom repository in front of another one, customized versions of -single files (e.g., header files or target description files) can be supplied to -the build system without changing the original repository. - - -Building targets -================ - -To build all targets contained in the list of 'REPOSITORIES' as defined in -_etc/build.conf_, simply issue 'make'. This way, all components that are -compatible with the build directory's base platform will be built. In practice, -however, only some of those components may be of interest. Hence, the build -can be tailored to those components which are of actual interest by specifying -source-code subtrees. For example, using the following command -! make core server/nitpicker -the build system builds all targets found in the 'core' and 'server/nitpicker' -source directories. You may specify any number of subtrees to the build -system. As indicated by the build output, the build system revisits -each library that is used by each target found in the specified subtrees. -This is very handy for developing libraries because instead of re-building -your library and then your library-using program, you just build your program -and that's it. This concept even works recursively, which means that libraries -may depend on other libraries. - -In practice, you won't ever need to build the _whole tree_ but only the -targets that you are interested in. - - -Cleaning the build directory -============================ - -To remove all but kernel-related generated files, use -! make clean - -To remove all generated files, use -! make cleanall - -Both 'clean' and 'cleanall' won't remove any files from the _bin/_ -subdirectory. This makes the _bin/_ a safe place for files that are -unrelated to the build process, yet required for the integration stage, e.g., -binary data. - - -Controlling the verbosity of the build process -============================================== - -To understand the inner workings of the build process in more detail, you can -tell the build system to display each directory change by specifying - -! make VERBOSE_DIR= - -If you are interested in the arguments that are passed to each invocation of -'make', you can make them visible via - -! make VERBOSE_MK= - -Furthermore, you can observe each single shell-command invocation by specifying - -! make VERBOSE= - -Of course, you can combine these verboseness toggles for maximizing the noise. - - -Enabling parallel builds -======================== - -To utilize multiple CPU cores during the build process, you may invoke 'make' -with the '-j' argument. If manually specifying this argument becomes an -inconvenience, you may add the following line to your _etc/build.conf_ file: - -! MAKE += -j - -This way, the build system will always use '' CPUs for building. - - -Caching inter-library dependencies -================================== - -The build system allows to repeat the last build without performing any -library-dependency checks by using: - -! make again - -The use of this feature can significantly improve the work flow during -development because in contrast to source-codes, library dependencies rarely -change. So the time needed for re-creating inter-library dependencies at each -build can be saved. - - -Repository directory layout -########################### - -Each Genode repository has the following layout: - - Directory | Description - ------------------------------------------------------------ - 'doc/' | Documentation, specific for the repository - ------------------------------------------------------------ - 'etc/' | Default configuration of the build process - ------------------------------------------------------------ - 'mk/' | The build system - ------------------------------------------------------------ - 'include/' | Globally visible header files - ------------------------------------------------------------ - 'src/' | Source codes and target build descriptions - ------------------------------------------------------------ - 'lib/mk/' | Library build descriptions - - -Creating targets and libraries -############################## - -Target descriptions -=================== - -A good starting point is to look at the init target. The source code of init is -located at _os/src/init/_. In this directory, you will find a target description -file named _target.mk_. This file contains the building instructions and it is -usually very simple. The build process is controlled by defining the following -variables. - - -Build variables to be defined by you -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -:'TARGET': is the name of the binary to be created. This is the - only *mandatory variable* to be defined in a _target.mk_ file. - -:'REQUIRES': expresses the requirements that must be satisfied in order to - build the target. You find more details about the underlying mechanism in - Section [Specializations]. - -:'LIBS': is the list of libraries that are used by the target. - -:'SRC_CC': contains the list of '.cc' source files. The default search location - for source codes is the directory, where the _target.mk_ file resides. - -:'SRC_C': contains the list of '.c' source files. - -:'SRC_S': contains the list of assembly '.s' source files. - -:'SRC_BIN': contains binary data files to be linked to the target. - -:'INC_DIR': is the list of include search locations. Directories should - always be appended by using +=. Never use an assignment! - -:'EXT_OBJECTS': is a list of Genode-external objects or libraries. This - variable is mostly used for interfacing Genode with legacy software - components. - - -Rarely used variables ---------------------- - -:'CC_OPT': contains additional compiler options to be used for '.c' as - well as for '.cc' files. - -:'CC_CXX_OPT': contains additional compiler options to be used for the - C++ compiler only. - -:'CC_C_OPT': contains additional compiler options to be used for the - C compiler only. - - -Specifying search locations -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -When specifying search locations for header files via the 'INC_DIR' variable or -for source files via 'vpath', relative pathnames are illegal to use. Instead, -you can use the following variables to reference locations within the -source-code repository, where your target lives: - -:'REP_DIR': is the base directory of the current source-code repository. - Normally, specifying locations relative to the base of the repository is - never used by _target.mk_ files but needed by library descriptions. - -:'PRG_DIR': is the directory, where your _target.mk_ file resides. This - variable is always to be used when specifying a relative path. - - -Library descriptions -==================== - -In contrast to target descriptions that are scattered across the whole source -tree, library descriptions are located at the central place _lib/mk_. Each -library corresponds to a _.mk_ file. The base of the description file -is the name of the library. Therefore, no 'TARGET' variable needs to be set. -The source-code locations are expressed as '$(REP_DIR)'-relative 'vpath' -commands. - -Library-description files support the following additional declarations: - -:'SHARED_LIB = yes': declares that the library should be built as a shared - object rather than a static library. The resulting object will be called - _.lib.so_. - - -Specializations -=============== - -Building components for different platforms likely implicates portions of code -that are tied to certain aspects of the target platform. For example, a target -platform may be characterized by - -* A kernel API such as L4v2, Linux, L4.sec, -* A hardware architecture such as x86, ARM, Coldfire, -* A certain hardware facility such as a custom device, or -* Other properties such as software license requirements. - -Each of these attributes express a specialization of the build process. The -build system provides a generic mechanism to handle such specializations. - -The _programmer_ of a software component knows the properties on which his -software relies and thus, specifies these requirements in his build description -file. - -The _user/customer/builder_ decides to build software for a specific platform -and defines the platform specifics via the 'SPECS' variable per build -directory in _etc/specs.conf_. In addition to an (optional) _etc/specs.conf_ -file within the build directory, the build system incorporates the first -_etc/specs.conf_ file found in the repositories as configured for the -build directory. For example, for a 'linux_x86' build directory, the -_base-linux/etc/specs.conf_ file is used by default. The build directory's -'specs.conf' file can still be used to extend the 'SPECS' declarations, for -example to enable special features. - -Each '' in the 'SPECS' variable instructs the build system to - -* Include the 'make'-rules of a corresponding _base/mk/spec-.mk_ - file. This enables the customization of the build process for each platform. - -* Search for _.mk_ files in the _lib/mk//_ subdirectory. - This way, we can provide alternative implementations of one and the same - library interface for different platforms. - -Before a target or library gets built, the build system checks if the 'REQUIRES' -entries of the build description file are satisfied by entries of the 'SPECS' -variable. The compilation is executed only if each entry in the 'REQUIRES' -variable is present in the 'SPECS' variable as supplied by the build directory -configuration. - - -Building tools to be executed on the host platform -=================================================== - -Sometimes, software requires custom tools that are used to generate source -code or other ingredients for the build process, for example IDL compilers. -Such tools won't be executed on top of Genode but on the host platform -during the build process. Hence, they must be compiled with the tool chain -installed on the host, not the Genode tool chain. - -The Genode build system accommodates the building of such host tools as a side -effect of building a library or a target. Even though it is possible to add -the tool compilation step to a regular build description file, it is -recommended to introduce a dedicated pseudo library for building such tools. -This way, the rules for building host tools are kept separate from rules that -refer to Genode programs. By convention, the pseudo library should be named -__host_tools_ and the host tools should be built at -_/tool//_. With __, we refer to the name of the -software package the tool belongs to, e.g., qt5 or mupdf. To build a tool -named __, the pseudo library contains a custom make rule like the -following: - -! $(BUILD_BASE_DIR)/tool//: -! $(MSG_BUILD)$(notdir $@) -! $(VERBOSE)mkdir -p $(dir $@) -! $(VERBOSE)...build commands... - -To let the build system trigger the rule, add the custom target to the -'HOST_TOOLS' variable: - -! HOST_TOOLS += $(BUILD_BASE_DIR)/tool// - -Once the pseudo library for building the host tools is in place, it can be -referenced by each target or library that relies on the respective tools via -the 'LIBS' declaration. The tool can be invoked by referring to -'$(BUILD_BASE_DIR)/tool//tool'. - -For an example of using custom host tools, please refer to the mupdf package -found within the libports repository. During the build of the mupdf library, -two custom tools fontdump and cmapdump are invoked. The tools are built via -the _lib/mk/mupdf_host_tools.mk_ library description file. The actual mupdf -library (_lib/mk/mupdf.mk_) has the pseudo library 'mupdf_host_tools' listed -in its 'LIBS' declaration and refers to the tools relative to -'$(BUILD_BASE_DIR)'. - - -Building additional custom targets accompanying library or program -================================================================== - -There are cases when it is important to build additional targets -besides standard files built for library or program. Of course there -is no problem with writing specific make rules for commands that -generate those target files but for them to be built a proper -dependency must be specified. To achieve it those additional targets -should be added to 'CUSTOM_TARGET_DEPS' variable like e.g. in -iwl_firmware library from dde_linux repository: - -! CUSTOM_TARGET_DEPS += $(addprefix $(BIN_DIR)/,$(IMAGES)) - - -Automated integration and testing -################################# - -Genode's cross-kernel portability is one of the prime features of the -framework. However, each kernel takes a different route when it comes to -configuring, integrating, and booting the system. Hence, for using a particular -kernel, profound knowledge about the boot concept and the kernel-specific tools -is required. To streamline the testing of Genode-based systems across the many -different supported kernels, the framework comes equipped with tools that -relieve you from these peculiarities. - -Run scripts -=========== - -Using so-called run scripts, complete Genode systems can be described in a -concise and kernel-independent way. Once created, a run script can be used -to integrate and test-drive a system scenario directly from the build directory. -The best way to get acquainted with the concept is reviewing the run script -for the 'hello_tutorial' located at _hello_tutorial/run/hello.run_. -Let's revisit each step expressed in the _hello.run_ script: - -* Building the components needed for the system using the 'build' command. - This command instructs the build system to compile the targets listed in - the brace block. It has the same effect as manually invoking 'make' with - the specified argument from within the build directory. - -* Creating a new boot directory using the 'create_boot_directory' command. - The integration of the scenario is performed in a dedicated directory at - _/var/run//_. When the run script is finished, - this directory will contain all components of the final system. In the - following, we will refer to this directory as run directory. - -* Installing the Genode 'config' file into the run directory using the - 'install_config' command. The argument to this command will be written - to a file called 'config' at the run directory picked up by - Genode's init process. - -* Creating a bootable system image using the 'build_boot_image' command. - This command copies the specified list of files from the _/bin/_ - directory to the run directory and executes the platform-specific steps - needed to transform the content of the run directory into a bootable - form. This form depends on the actual base platform and may be an ISO - image or a bootable ELF image. - -* Executing the system image using the 'run_genode_until' command. Depending - on the base platform, the system image will be executed using an emulator. - For most platforms, Qemu is the tool of choice used by default. On Linux, - the scenario is executed by starting 'core' directly from the run - directory. The 'run_genode_until' command takes a regular expression - as argument. If the log output of the scenario matches the specified - pattern, the 'run_genode_until' command returns. If specifying 'forever' - as argument (as done in 'hello.run'), this command will never return. - If a regular expression is specified, an additional argument determines - a timeout in seconds. If the regular expression does not match until - the timeout is reached, the run script will abort. - -Please note that the _hello.run_ script does not contain kernel-specific -information. Therefore it can be executed from the build directory of any base -platform by using: - -! make run/hello - -When invoking 'make' with an argument of the form 'run/*', the build system -will look in all repositories for a run script with the specified name. The run -script must be located in one of the repositories 'run/' subdirectories and -have the file extension '.run'. - -For a more comprehensive run script, _os/run/demo.run_ serves as a good -example. This run script describes Genode's default demo scenario. As seen in -'demo.run', parts of init's configuration can be made dependent on the -platform's properties expressed as spec values. For example, the PCI driver -gets included in init's configuration only on platforms with a PCI bus. For -appending conditional snippets to the _config_ file, there exists the 'append_if' -command, which takes a condition as first and the snippet as second argument. -To test for a SPEC value, the command '[have_spec ]' is used as -condition. Analogously to how 'append_if' appends strings, there exists -'lappend_if' to append list items. The latter command is used to conditionally -include binaries to the list of boot modules passed to the 'build_boot_image' -command. - - -The run mechanism explained -=========================== - -Under the hood, run scripts are executed by an expect interpreter. When the -user invokes a run script via _make run/_, the build system invokes -the run tool at _/tool/run_ with the run script as argument. The -run tool is an expect script that has no other purpose than defining several -commands used by run scripts, including a platform-specific script snippet -called run environment ('env'), and finally including the actual run script. -Whereas _tool/run_ provides the implementations of generic and largely -platform-independent commands, the _env_ snippet included from the platform's -respective _base-/run/env_ file contains all platform-specific -commands. For reference, the most simplistic run environment is the one at -_base-linux/run/env_, which implements the 'create_boot_directory', -'install_config', 'build_boot_image', and 'run_genode_until' commands for Linux -as base platform. For the other platforms, the run environments are far more -elaborative and document precisely how the integration and boot concept works -on each platform. Hence, the _base-/run/env_ files are not only -necessary parts of Genode's tooling support but serve as resource for -peculiarities of using each kernel. - - -Using run script to implement test cases -======================================== - -Because run scripts are actually expect scripts, the whole arsenal of -language features of the Tcl scripting language is available to them. This -turns run scripts into powerful tools for the automated execution of test -cases. A good example is the run script at _libports/run/lwip.run_, which tests -the lwIP stack by running a simple Genode-based HTTP server on Qemu. It fetches -and validates a HTML page from this server. The run script makes use of a -regular expression as argument to the 'run_genode_until' command to detect the -state when the web server becomes ready, subsequently executes the 'lynx' shell -command to fetch the web site, and employs Tcl's support for regular -expressions to validate the result. The run script works across base platforms -that use Qemu as execution environment. - -To get the most out of the run mechanism, a basic understanding of the Tcl -scripting language is required. Furthermore the functions provided by -_tool/run_ and _base-/run/env_ should be studied. - - -Automated testing across base platforms -======================================= - -To execute one or multiple test cases on more than one base platform, there -exists a dedicated tool at _tool/autopilot_. Its primary purpose is the -nightly execution of test cases. The tool takes a list of platforms and of -run scripts as arguments and executes each run script on each platform. The -build directory for each platform is created at -_/tmp/autopilot./_ and the output of each run script is -written to a file called _..log_. On stderr, autopilot -prints the statistics about whether or not each run script executed -successfully on each platform. If at least one run script failed, autopilot -returns a non-zero exit code, which makes it straight forward to include -autopilot into an automated build-and-test environment. - - diff --git a/doc/coding_style.txt b/doc/coding_style.txt deleted file mode 100644 index 007b77b15c..0000000000 --- a/doc/coding_style.txt +++ /dev/null @@ -1,299 +0,0 @@ -Coding style guidelines for Genode -################################## - -Things to avoid -=============== - -Please avoid using pre-processor macros. C++ provides language -features for almost any case, for which a C programmer uses -macros. - -:Defining constants: - - Use 'enum' instead of '#define' - ! enum { MAX_COLORS = 3 }; - ! enum { - ! COLOR_RED = 1, - ! COLOR_BLUE = 2, - ! COLOR_GREEN = 3 - ! }; - -:Meta programming: - - Use templates instead of pre-processor macros. In contrast to macros, - templates are type-safe and fit well with the implementation syntax. - -:Conditional-code inclusion: - - Please avoid C-hacker style '#ifdef CONFIG_PLATFROM' - '#endif' - constructs. Instead, factor-out the encapsulated code into a - separate file and introduce a proper function interface. - The build process should then be used to select the appropriate - platform-specific files at compile time. Keep platform dependent - code as small as possible. Never pollute existing generic code - with platform-specific code. - - -Header of each file -=================== - -! /* -! * \brief Short description of the file -! * \author Original author -! * \date Creation date -! * -! * Some more detailed description. This is optional. -! */ - - -Identifiers -=========== - -* The first character of class names are uppercase, any other characters are - lowercase. -* Function and variable names are lower case. -* 'Multi_word_identifiers' use underline to separate words. -* 'CONSTANTS' and template arguments are upper case. -* Private and protected members of a class begin with an '_'-character. -* Accessor methods are named after their corresponding attributes: - - ! /** - ! * Request private member variable - ! */ - ! int value() const { return _value; } - ! - ! /** - ! * Set the private member variable - ! */ - ! void value(int value) { _value = value; } - -* Accessors that return a boolean value do not carry an 'is_' prefix. E.g., - a method for requesting the validity of an object should be named - 'valid()', not 'is_valid()'. - - -Indentation -=========== - -* Use one tab per indentation step. *Do not mix tabs and spaces!* -* Use no tabs except at the beginning of a line. -* Use spaces for the alignment of continuation lines such as function - arguments that span multiple lines. The alignment spaces of such lines - should start after the (tab-indented) indentation level. For example: - ! { - ! function_with_many_arguments(arg1, - ! <--- spaces for aligment --->arg2, - ! ... - ! } -* Remove trailing spaces at the end of lines - -This way, each developer can set his preferred tab size in his editor -and the source code always looks good. - -_Hint:_ In VIM, use the 'set list' and 'set listchars' commands to make tabs -and spaces visible. - -* If class initializers span multiple lines, put the colon on a separate - line and indent the initializers using one tab. For example: - ! Complicated_machinery(Material &material, Deadline deadline) - ! : - ! _material(material), - ! _deadline(deadline), - ! ... - ! { - ! ... - ! } - -* Preferably place statements that alter the control flow - such as - 'break', 'continue', or 'return' - at the beginning of a separate line, - followed by vertical space (a blank line or the closing brace of the - surrounding scope). - ! if (early_return_possible) - ! return; - - -Switch statements -~~~~~~~~~~~~~~~~~ - -Switch-statement blocks should be indented as follows: - -! switch (color) { -! -! case BLUE: -! break; -! -! case GREEN: -! { -! int declaration_required; -! ... -! } -! -! default: -! } - -Please note that the case labels have the same indentation -level as the switch statement. This avoids a two-level -indentation-change at the end of the switch block that -would occur otherwise. - - -Vertical whitespaces -==================== - -In header files: - -* Leave two empty lines between classes. -* Leave one empty line between member functions. - -In implementation files: - -* Leave two empty lines between functions. - - -Braces -====== - -* Braces after class, struct and function names are placed at a new line: - ! class Foo - ! { - ! public: - ! - ! void method(void) - ! { - ! ... - ! } - ! }; - - except for one-line functions. - -* All other occurrences of open braces (for 'if', 'while', 'do', 'for', - 'namespace', 'enum' etc.) are at the end of a line: - - ! if (flag) { - ! .. - ! } else { - ! .. - ! } - -* One-line functions should be written on a single line as long as the line - length does not exceed approximately 80 characters. - Typically, this applies for accessor functions. - If slightly more space than one line is needed, indent as follows: - - ! int heavy_computation(int a, int lot, int of, int args) { - ! return a + lot + of + args; } - - -Comments -======== - -Function/method header -~~~~~~~~~~~~~~~~~~~~~~ - -Each public or protected (but no private) method in a header-file should be -prepended by a header as follows: - -! /** -! * Short description -! * -! * \param a meaning of parameter a -! * \param b meaning of parameter b -! * \param c,d meaning of parameters c and d -! * -! * \throw Exception_type meaning of the exception -! * -! * \return meaning of return value -! * -! * More detailed information about the function. This is optional. -! */ - -Descriptions of parameters and return values should be lower-case and brief. -More elaborative descriptions can be documented in the text area below. - -In implementation files, only local and private functions should feature -function headers. - - -Single-line comments -~~~~~~~~~~~~~~~~~~~~ - -! /* use this syntax for single line comments */ - -A single-line comment should be prepended by an empty line. -Single-line comments should be short - no complete sentences. Use lower-case. - -C++-style comments ('//') should only be used for temporarily commenting-out -code. Such commented-out garbage is easy to 'grep' and there are handy -'vim'-macros available for creating and removing such comments. - - -Variable descriptions -~~~~~~~~~~~~~~~~~~~~~ - -Use the same syntax as for single-line comments. Insert two or more -spaces before your comment starts. - -! int size; /* in kilobytes */ - - -Multi-line comments -~~~~~~~~~~~~~~~~~~~ - -Multi-line comments are more detailed descriptions in the form of -sentences. -A multi-line comment should be enclosed by empty lines. - -! /* -! * This is some tricky -! * algorithm that works -! * as follows: -! * ... -! */ - -The first and last line of a multi-line comment contain no words. - - -Source-code blocks -~~~~~~~~~~~~~~~~~~ - -For structuring your source code, you can entitle the different -parts of a file like this: - -! <- two empty lines -! -! /******************** -! ** Event handlers ** -! ********************/ -! <- one empty line - -Note the two stars at the left and right. There are two of them to -make the visible width of the border match its height (typically, -characters are ca. twice as high as wide). - -A source-code block header represents a headline for the following -code. To couple this headline with the following code closer than -with previous code, leave two empty lines above and one empty line -below the source-code block header. - - -Order of public, protected, and private blocks -============================================== - -For consistency reasons, use the following class layout: - -! class Sandstein -! { -! private: -! ... -! protected: -! ... -! public: -! }; - -Typically, the private section contains member variables that are used -by public accessor functions below. In this common case, we only reference -symbols that are defined above as it is done when programming plain C. - -Leave one empty line (or a line that contains only a brace) above and below -a 'private', 'protected', or 'public' label. This also applies when the -label is followed by a source-code block header. diff --git a/doc/conventions.txt b/doc/conventions.txt index 50b3130ed0..124211dc3d 100644 --- a/doc/conventions.txt +++ b/doc/conventions.txt @@ -1,70 +1,333 @@ - Conventions for the Genode development - - Norman Feske + ================================================== + Conventions and coding-style guidelines for Genode + ================================================== -Documentation -############# + +Documentation and naming of files +################################# We use the GOSH syntax [https://github.com/nfeske/gosh] for documentation and README files. +We encourage that each directory contains a file called 'README' that briefly +explains what the directory is about. -README files -############ +File names +---------- -Each directory should contain a file called 'README' that briefly explains -what the directory is about. In 'doc/Makefile' is a rule for -generating a directory overview from the 'README' files automatically. - -You can structure your 'README' file by using the GOSH style for subsections: -! Subsection -! ~~~~~~~~~~ -Do not use chapters or sections in your 'README' files. - - -Filenames -######### - -All normal filenames are lowercase. Filenames should be chosen to be -expressive. Someone who explores your files for the first time might not +All normal file names are lowercase. Filenames should be chosen to be +expressive. Someone who explores your files for the first time might not understand what 'mbi.cc' means but 'multiboot_info.cc' would ring a bell. If a -filename contains multiple words, use the '_' to separate them (instead of +file name contains multiple words, use the '_' to separate them (instead of 'miscmath.h', use 'misc_math.h'). Coding style ############ -A common coding style helps a lot to ease collaboration. The official coding -style of the Genode base components is described in 'doc/coding_style.txt'. -If you consider working closely together with the Genode main developers, -your adherence to this style is greatly appreciated. +Things to avoid +=============== + +Please avoid using pre-processor macros. C++ provides language +features for almost any case, for which a C programmer uses +macros. + +:Defining constants: + + Use 'enum' instead of '#define' + ! enum { MAX_COLORS = 3 }; + ! enum { + ! COLOR_RED = 1, + ! COLOR_BLUE = 2, + ! COLOR_GREEN = 3 + ! }; + +:Meta programming: + + Use templates instead of pre-processor macros. In contrast to macros, + templates are type-safe and fit well with the implementation syntax. + +:Conditional-code inclusion: + + Please avoid C-hacker style '#ifdef CONFIG_PLATFROM' - '#endif' + constructs. Instead, factor-out the encapsulated code into a + separate file and introduce a proper function interface. + The build process should then be used to select the appropriate + platform-specific files at compile time. Keep platform dependent + code as small as possible. Never pollute existing generic code + with platform-specific code. -Include files and RPC interfaces -################################ +Header of each file +=================== -Never place include files directly into the '/include/' directory -but use a meaningful subdirectory that corresponds to the component that -provides the interfaces. - -Each RPC interface is represented by a separate include subdirectory. For -an example, see 'base/include/ram_session/'. The header file that defines -the RPC function interface has the same base name as the directory. The RPC -stubs are called 'client.h' and 'server.h'. If your interface uses a custom -capability type, it is defined in 'capability.h'. Furthermore, if your -interface is a session interface of a service, it is good practice to -provide a connection class in a 'connection.h' file for managing session- -construction arguments and the creation and destruction of sessions. - -Specialization-dependent include directories are placed in 'include//'. +! /* +! * \brief Short description of the file +! * \author Original author +! * \date Creation date +! * +! * Some more detailed description. This is optional. +! */ -Service Names -############# +Identifiers +=========== + +* The first character of class names are uppercase, any other characters are + lowercase. +* Function and variable names are lower case. +* 'Multi_word_identifiers' use underline to separate words. +* 'CONSTANTS' and template arguments are upper case. +* Private and protected members of a class begin with an '_'-character. +* Accessor methods are named after their corresponding attributes: + + ! /** + ! * Request private member variable + ! */ + ! int value() const { return _value; } + ! + ! /** + ! * Set the private member variable + ! */ + ! void value(int value) { _value = value; } + +* Accessors that return a boolean value do not carry an 'is_' prefix. E.g., + a method for requesting the validity of an object should be named + 'valid()', not 'is_valid()'. + + +Indentation +=========== + +* Use one tab per indentation step. *Do not mix tabs and spaces!* +* Use no tabs except at the beginning of a line. +* Use spaces for the alignment of continuation lines such as function + arguments that span multiple lines. The alignment spaces of such lines + should start after the (tab-indented) indentation level. For example: + ! { + ! function_with_many_arguments(arg1, + ! <--- spaces for aligment --->arg2, + ! ... + ! } +* Remove trailing spaces at the end of lines + +This way, each developer can set his preferred tab size in his editor +and the source code always looks good. + +_Hint:_ In VIM, use the 'set list' and 'set listchars' commands to make tabs +and spaces visible. + +* If class initializers span multiple lines, put the colon on a separate + line and indent the initializers using one tab. For example: + ! Complicated_machinery(Material &material, Deadline deadline) + ! : + ! _material(material), + ! _deadline(deadline), + ! ... + ! { + ! ... + ! } + +* Preferably place statements that alter the control flow - such as + 'break', 'continue', or 'return' - at the beginning of a separate line, + followed by vertical space (a blank line or the closing brace of the + surrounding scope). + ! if (early_return_possible) + ! return; + + +Switch statements +~~~~~~~~~~~~~~~~~ + +Switch-statement blocks should be indented as follows: + +! switch (color) { +! +! case BLUE: +! break; +! +! case GREEN: +! { +! int declaration_required; +! ... +! } +! +! default: +! } + +Please note that the case labels have the same indentation +level as the switch statement. This avoids a two-level +indentation-change at the end of the switch block that +would occur otherwise. + + +Vertical whitespaces +==================== + +In header files: + +* Leave two empty lines between classes. +* Leave one empty line between member functions. + +In implementation files: + +* Leave two empty lines between functions. + + +Braces +====== + +* Braces after class, struct and function names are placed at a new line: + ! class Foo + ! { + ! public: + ! + ! void method(void) + ! { + ! ... + ! } + ! }; + + except for one-line functions. + +* All other occurrences of open braces (for 'if', 'while', 'do', 'for', + 'namespace', 'enum' etc.) are at the end of a line: + + ! if (flag) { + ! .. + ! } else { + ! .. + ! } + +* One-line functions should be written on a single line as long as the line + length does not exceed approximately 80 characters. + Typically, this applies for accessor functions. + If slightly more space than one line is needed, indent as follows: + + ! int heavy_computation(int a, int lot, int of, int args) { + ! return a + lot + of + args; } + + +Comments +======== + +Function/method header +~~~~~~~~~~~~~~~~~~~~~~ + +Each public or protected (but no private) method in a header-file should be +prepended by a header as follows: + +! /** +! * Short description +! * +! * \param a meaning of parameter a +! * \param b meaning of parameter b +! * \param c,d meaning of parameters c and d +! * +! * \throw Exception_type meaning of the exception +! * +! * \return meaning of return value +! * +! * More detailed information about the function. This is optional. +! */ + +Descriptions of parameters and return values should be lower-case and brief. +More elaborative descriptions can be documented in the text area below. + +In implementation files, only local and private functions should feature +function headers. + + +Single-line comments +~~~~~~~~~~~~~~~~~~~~ + +! /* use this syntax for single line comments */ + +A single-line comment should be prepended by an empty line. +Single-line comments should be short - no complete sentences. Use lower-case. + +C++-style comments ('//') should only be used for temporarily commenting-out +code. Such commented-out garbage is easy to 'grep' and there are handy +'vim'-macros available for creating and removing such comments. + + +Variable descriptions +~~~~~~~~~~~~~~~~~~~~~ + +Use the same syntax as for single-line comments. Insert two or more +spaces before your comment starts. + +! int size; /* in kilobytes */ + + +Multi-line comments +~~~~~~~~~~~~~~~~~~~ + +Multi-line comments are more detailed descriptions in the form of +sentences. +A multi-line comment should be enclosed by empty lines. + +! /* +! * This is some tricky +! * algorithm that works +! * as follows: +! * ... +! */ + +The first and last line of a multi-line comment contain no words. + + +Source-code blocks +~~~~~~~~~~~~~~~~~~ + +For structuring your source code, you can entitle the different +parts of a file like this: + +! <- two empty lines +! +! /******************** +! ** Event handlers ** +! ********************/ +! <- one empty line + +Note the two stars at the left and right. There are two of them to +make the visible width of the border match its height (typically, +characters are ca. twice as high as wide). + +A source-code block header represents a headline for the following +code. To couple this headline with the following code closer than +with previous code, leave two empty lines above and one empty line +below the source-code block header. + + +Order of public, protected, and private blocks +============================================== + +For consistency reasons, use the following class layout: + +! class Sandstein +! { +! private: +! ... +! protected: +! ... +! public: +! }; + +Typically, the private section contains member variables that are used +by public accessor functions below. In this common case, we only reference +symbols that are defined above as it is done when programming plain C. + +Leave one empty line (or a line that contains only a brace) above and below +a 'private', 'protected', or 'public' label. This also applies when the +label is followed by a source-code block header. + + +Naming of Genode services +========================= Service names as announced via the 'parent()->announce()' function follow the following convention: diff --git a/doc/depot.txt b/doc/depot.txt deleted file mode 100644 index abd9196a13..0000000000 --- a/doc/depot.txt +++ /dev/null @@ -1,514 +0,0 @@ - - - ============================ - Package management on Genode - ============================ - - - Norman Feske - - - -Motivation and inspiration -########################## - -The established system-integration work flow with Genode is based on -the 'run' tool, which automates the building, configuration, integration, -and testing of Genode-based systems. Whereas the run tool succeeds in -overcoming the challenges that come with Genode's diversity of kernels and -supported hardware platforms, its scalability is somewhat limited to -appliance-like system scenarios: The result of the integration process is -a system image with a certain feature set. Whenever requirements change, -the system image is replaced with a new created image that takes those -requirements into account. In practice, there are two limitations of this -system-integration approach: - -First, since the run tool implicitly builds all components required for a -system scenario, the system integrator has to compile all components from -source. E.g., if a system includes a component based on Qt5, one needs to -compile the entire Qt5 application framework, which induces significant -overhead to the actual system-integration tasks of composing and configuring -components. - -Second, general-purpose systems tend to become too complex and diverse to be -treated as system images. When looking at commodity OSes, each installation -differs with respect to the installed set of applications, user preferences, -used device drivers and system preferences. A system based on the run tool's -work flow would require the user to customize the run script of the system for -each tweak. To stay up to date, the user would need to re-create the -system image from time to time while manually maintaining any customizations. -In practice, this is a burden, very few end users are willing to endure. - -The primary goal of Genode's package management is to overcome these -scalability limitations, in particular: - -* Alleviating the need to build everything that goes into system scenarios - from scratch, -* Facilitating modular system compositions while abstracting from technical - details, -* On-target system update and system development, -* Assuring the user that system updates are safe to apply by providing the - ability to easily roll back the system or parts thereof to previous versions, -* Securing the integrity of the deployed software, -* Fostering a federalistic evolution of Genode systems, -* Low friction for existing developers. - -The design of Genode's package-management concept is largely influenced by Git -as well as the [https://nixos.org/nix/ - Nix] package manager. In particular -the latter opened our eyes to discover the potential that lies beyond the -package management employed in state-of-the art commodity systems. Even though -we considered adapting Nix for Genode and actually conducted intensive -experiments in this direction (thanks to Emery Hemingway who pushed forward -this line of work), we settled on a custom solution that leverages Genode's -holistic view on all levels of the operating system including the build system -and tooling, source structure, ABI design, framework API, system -configuration, inter-component interaction, and the components itself. Whereby -Nix is designed for being used on top of Linux, Genode's whole-systems view -led us to simplifications that eliminated the needs for Nix' powerful features -like its custom description language. - - -Nomenclature -############ - -When speaking about "package management", one has to clarify what a "package" -in the context of an operating system represents. Traditionally, a package -is the unit of delivery of a bunch of "dumb" files, usually wrapped up in -a compressed archive. A package may depend on the presence of other -packages. Thereby, a dependency graph is formed. To express how packages fit -with each other, a package is usually accompanied with meta data -(description). Depending on the package manager, package descriptions follow -certain formalisms (e.g., package-description language) and express -more-or-less complex concepts such as versioning schemes or the distinction -between hard and soft dependencies. - -Genode's package management does not follow this notion of a "package". -Instead of subsuming all deliverable content under one term, we distinguish -different kinds of content, each in a tailored and simple form. To avoid the -clash of the notions of the common meaning of a "package", we speak of -"archives" as the basic unit of delivery. The following subsections introduce -the different categories. -Archives are named with their version as suffix, appended via a slash. The -suffix is maintained by the author of the archive. The recommended naming -scheme is the use of the release date as version suffix, e.g., -'report_rom/2017-05-14'. - - -Raw-data archives -================= - -A raw-data archive contains arbitrary data that is - in contrast to executable -binaries - independent from the processor architecture. Examples are -configuration data, game assets, images, or fonts. The content of raw-data -archives is expected to be consumed by components at runtime. It is not -relevant for the build process for executable binaries. Each raw-data -archive contains merely a collection of data files. There is no meta data. - - -API archive -=========== - -An API archive has the structure of a Genode source-code repository. It may -contain all the typical content of such a source-code repository such as header -files (in the _include/_ subdirectory), source codes (in the _src/_ -subdirectory), library-description files (in the _lib/mk/_ subdirectory), or -ABI symbols (_lib/symbols/_ subdirectory). At the top level, a LICENSE file is -expected that clarifies the license of the contained source code. There is no -meta data contained in an API archive. - -An API archive is meant to provide _ingredients_ for building components. The -canonical example is the public programming interface of a library (header -files) and the library's binary interface in the form of an ABI-symbols file. -One API archive may contain the interfaces of multiple libraries. For example, -the interfaces of libc and libm may be contained in a single "libc" API -archive because they are closely related to each other. Conversely, an API -archive may contain a single header file only. The granularity of those -archives may vary. But they have in common that they are used at build time -only, not at runtime. - - -Source archive -============== - -Like an API archive, a source archive has the structure of a Genode -source-tree repository and is expected to contain all the typical content of -such a source repository along with a LICENSE file. But unlike an API archive, -it contains descriptions of actual build targets in the form of Genode's usual -'target.mk' files. - -In addition to the source code, a source archive contains a file -called 'used_apis', which contains a list of API-archive names with each -name on a separate line. For example, the 'used_apis' file of the 'report_rom' -source archive looks as follows: - -! base/2017-05-14 -! os/2017-05-13 -! report_session/2017-05-13 - -The 'used_apis' file declares the APIs needed to incorporate into the build -process when building the source archive. Hence, they represent _build-time_ -_dependencies_ on the specific API versions. - -A source archive may be equipped with a top-level file called 'api' containing -the name of exactly one API archive. If present, it declares that the source -archive _implements_ the specified API. For example, the 'libc/2017-05-14' -source archive contains the actual source code of the libc and libm as well as -an 'api' file with the content 'libc/2017-04-13'. The latter refers to the API -implemented by this version of the libc source package (note the differing -versions of the API and source archives) - - -Binary archive -============== - -A binary archive contains the build result of the equally-named source archive -when built for a particular architecture. That is, all files that would appear -at the _/bin/_ subdirectory when building all targets present in -the source archive. There is no meta data present in a binary archive. - -A binary archive is created out of the content of its corresponding source -archive and all API archives listed in the source archive's 'used_apis' file. -Note that since a binary archive depends on only one source archive, which -has no further dependencies, all binary archives can be built independently -from each other. -For example, a libc-using application needs the source code of the -application as well as the libc's API archive (the libc's header file and -ABI) but it does not need the actual libc library to be present. - - -Package archive -=============== - -A package archive contains an 'archives' file with a list of archive names -that belong together at runtime. Each listed archive appears on a separate line. -For example, the 'archives' file of the package archive for the window -manager 'wm/2018-02-26' looks as follows: - -! genodelabs/raw/wm/2018-02-14 -! genodelabs/src/wm/2018-02-26 -! genodelabs/src/report_rom/2018-02-26 -! genodelabs/src/decorator/2018-02-26 -! genodelabs/src/floating_window_layouter/2018-02-26 - -In contrast to the list of 'used_apis' of a source archive, the content of -the 'archives' file denotes the origin of the respective archives -("genodelabs"), the archive type, followed by the versioned name of the -archive. - -An 'archives' file may specify raw archives, source archives, or package -archives (as type 'pkg'). It thereby allows the expression of _runtime -dependencies_. If a package archive lists another package archive, it inherits -the content of the listed archive. This way, a new package archive may easily -customize an existing package archive. - -A package archive does not specify binary archives directly as they differ -between the architecture and are already referenced by the source archives. - -In addition to an 'archives' file, a package archive is expected to contain -a 'README' file explaining the purpose of the collection. - - -Depot structure -############### - -Archives are stored within a directory tree called _depot/_. The depot -is structured as follows: - -! /pubkey -! /download -! /src/// -! /api/// -! /raw/// -! /pkg/// -! /bin//// - -The stands for the origin of the contained archives. For example, the -official archives provided by Genode Labs reside in a _genodelabs/_ -subdirectory. Within this directory, there is a 'pubkey' file with the -user's public key that is used to verify the integrity of archives downloaded -from the user. The file 'download' specifies the download location as an URL. - -Subsuming archives in a subdirectory that correspond to their origin -(user) serves two purposes. First, it provides a user-local name space for -versioning archives. E.g., there might be two versions of a -'nitpicker/2017-04-15' source archive, one by "genodelabs" and one by -"nfeske". However, since each version resides under its origin's subdirectory, -version-naming conflicts between different origins cannot happen. Second, by -allowing multiple archive origins in the depot side-by-side, package archives -may incorporate archives of different origins, which fosters the goal of a -federalistic development, where contributions of different origins can be -easily combined. - -The actual archives are stored in the subdirectories named after the archive -types ('raw', 'api', 'src', 'bin', 'pkg'). Archives contained in the _bin/_ -subdirectories are further subdivided in the various architectures (like -'x86_64', or 'arm_v7'). - - -Depot management -################ - -The tools for managing the depot content reside under the _tool/depot/_ -directory. When invoked without arguments, each tool prints a brief -description of the tool and its arguments. - -Unless stated otherwise, the tools are able to consume any number of archives -as arguments. By default, they perform their work sequentially. This can be -changed by the '-j' argument, where denotes the desired level of -parallelization. For example, by specifying '-j4' to the _tool/depot/build_ -tool, four concurrent jobs are executed during the creation of binary archives. - - -Downloading archives -==================== - -The depot can be populated with archives in two ways, either by creating -the content from locally available source codes as explained by Section -[Automated extraction of archives from the source tree], or by downloading -ready-to-use archives from a web server. - -In order to download archives originating from a specific user, the depot's -corresponding user subdirectory must contain two files: - -:_pubkey_: contains the public key of the GPG key pair used by the creator - (aka "user") of the to-be-downloaded archives for signing the archives. The - file contains the ASCII-armored version of the public key. - -:_download_: contains the base URL of the web server where to fetch archives - from. The web server is expected to mirror the structure of the depot. - That is, the base URL is followed by a sub directory for the user, - which contains the archive-type-specific subdirectories. - -If both the public key and the download locations are defined, the download -tool can be used as follows: - -! ./tool/depot/download genodelabs/src/zlib/2018-01-10 - -The tool automatically downloads the specified archives and their -dependencies. For example, as the zlib depends on the libc API, the libc API -archive is downloaded as well. All archive types are accepted as arguments -including binary and package archives. Furthermore, it is possible to download -all binary archives referenced by a package archive. For example, the -following command downloads the window-manager (wm) package archive including -all binary archives for the 64-bit x86 architecture. Downloaded binary -archives are always accompanied with their corresponding source and used API -archives. - -! ./tool/depot/download genodelabs/pkg/x86_64/wm/2018-02-26 - -Archive content is not downloaded directly to the depot. Instead, the -individual archives and signature files are downloaded to a quarantine area in -the form of a _public/_ directory located in the root of Genode's source tree. -As its name suggests, the _public/_ directory contains data that is imported -from or to-be exported to the public. The download tool populates it with the -downloaded archives in their compressed form accompanied with their -signatures. - -The compressed archives are not extracted before their signature is checked -against the public key defined at _depot//pubkey_. If however the -signature is valid, the archive content is imported to the target destination -within the depot. This procedure ensures that depot content - whenever -downloaded - is blessed by a cryptographic signature of its creator. - - -Building binary archives from source archives -============================================= - -With the depot populated with source and API archives, one can use the -_tool/depot/build_ tool to produce binary archives. The arguments have the -form '/bin//' where '' stands for the targeted -CPU architecture. For example, the following command builds the 'zlib' -library for the 64-bit x86 architecture. It executes four concurrent jobs -during the build process. - -! ./tool/depot/build genodelabs/bin/x86_64/zlib/2018-01-10 -j4 - -Note that the command expects a specific version of the source archive as -argument. The depot may contain several versions. So the user has to decide, -which one to build. - -After the tool is finished, the freshly built binary archive can be found in -the depot within the _genodelabs/bin////_ subdirectory. -Only the final result of the built process is preserved. In the example above, -that would be the _zlib.lib.so_ library. - -For debugging purposes, it might be interesting to inspect the intermediate -state of the build. This is possible by adding 'KEEP_BUILD_DIR=1' as argument -to the build command. The binary's intermediate build directory can be -found besides the binary archive's location named with a '.build' suffix. - -By default, the build tool won't attempt to rebuild a binary archive that is -already present in the depot. However, it is possible to force a rebuild via -the 'REBUILD=1' argument. - - -Publishing archives -=================== - -Archives located in the depot can be conveniently made available to the public -using the _tool/depot/publish_ tool. Given an archive path, the tool takes -care of determining all archives that are implicitly needed by the specified -one, wrapping the archive's content into compressed tar archives, and signing -those. - -As a precondition, the tool requires you to possess the private key that -matches the _depot//pubkey_ file within your depot. The key pair should -be present in the key ring of your GNU privacy guard. - -To publish archives, one needs to specify the specific version to publish. -For example: - -! ./tool/depot/publish /pkg/x86_64/wm/2018-02-26 - -The command checks that the specified archive and all dependencies are present -in the depot. It then proceeds with the archiving and signing operations. For -the latter, the pass phrase for your private key will be requested. The -publish tool prints the information about the processed archives, e.g.: - -! publish /.../public//api/base/2018-02-26.tar.xz -! publish /.../public//api/framebuffer_session/2017-05-31.tar.xz -! publish /.../public//api/gems/2018-01-28.tar.xz -! publish /.../public//api/input_session/2018-01-05.tar.xz -! publish /.../public//api/nitpicker_gfx/2018-01-05.tar.xz -! publish /.../public//api/nitpicker_session/2018-01-05.tar.xz -! publish /.../public//api/os/2018-02-13.tar.xz -! publish /.../public//api/report_session/2018-01-05.tar.xz -! publish /.../public//api/scout_gfx/2018-01-05.tar.xz -! publish /.../public//bin/x86_64/decorator/2018-02-26.tar.xz -! publish /.../public//bin/x86_64/floating_window_layouter/2018-02-26.tar.xz -! publish /.../public//bin/x86_64/report_rom/2018-02-26.tar.xz -! publish /.../public//bin/x86_64/wm/2018-02-26.tar.xz -! publish /.../public//pkg/wm/2018-02-26.tar.xz -! publish /.../public//raw/wm/2018-02-14.tar.xz -! publish /.../public//src/decorator/2018-02-26.tar.xz -! publish /.../public//src/floating_window_layouter/2018-02-26.tar.xz -! publish /.../public//src/report_rom/2018-02-26.tar.xz -! publish /.../public//src/wm/2018-02-26.tar.xz - - -According to the output, the tool populates a directory called _public/_ -at the root of the Genode source tree with the to-be-published archives. -The content of the _public/_ directory is now ready to be copied to a -web server, e.g., by using rsync. - - -Automated extraction of archives from the source tree -##################################################### - -Genode users are expected to populate their local depot with content obtained -via the _tool/depot/download_ tool. However, Genode developers need a way to -create depot archives locally in order to make them available to users. Thanks -to the _tool/depot/extract_ tool, the assembly of archives does not need to be -a manual process. Instead, archives can be conveniently generated out of the -source codes present in the Genode source tree and the _contrib/_ directory. - -However, the granularity of splitting source code into archives, the -definition of what a particular API entails, and the relationship between -archives must be augmented by the archive creator as this kind of information -is not present in the source tree as is. This is where so-called "archive -recipes" enter the picture. An archive recipe defines the content of an -archive. Such recipes can be located at an _recipes/_ subdirectory of any -source-code repository, similar to how port descriptions and run scripts -are organized. Each _recipe/_ directory contains subdirectories for the -archive types, which, in turn, contain a directory for each archive. The -latter is called a _recipe directory_. - -Recipe directory ----------------- - -The recipe directory is named after the archive _omitting the archive version_ -and contains at least one file named _hash_. This file defines the version -of the archive along with a hash value of the archive's content -separated by a space character. By tying the version name to a particular hash -value, the _extract_ tool is able to detect the appropriate points in time -whenever the version should be increased due to a change of the archive's -content. - -API, source, and raw-data archive recipes ------------------------------------------ - -Recipe directories for API, source, or raw-data archives contain a -_content.mk_ file that defines the archive content in the form of make -rules. The content.mk file is executed from the archive's location within -the depot. Hence, the contained rules can refer to archive-relative files as targets. -The first (default) rule of the content.mk file is executed with a customized -make environment: - -:GENODE_DIR: A variable that holds the path to root of the Genode source tree, -:REP_DIR: A variable with the path to source code repository where the recipe - is located -:port_dir: A make function that returns the directory of a port within the - _contrib/_ directory. The function expects the location of the - corresponding port file as argument, for example, the 'zlib' recipe - residing in the _libports/_ repository may specify '$(REP_DIR)/ports/zlib' - to access the 3rd-party zlib source code. - -Source archive recipes contain simplified versions of the 'used_apis' and -(for libraries) 'api' files as found in the archives. In contrast to the -depot's counterparts of these files, which contain version-suffixed names, -the files contained in recipe directories omit the version suffix. This -is possible because the extract tool always extracts the _current_ version -of a given archive from the source tree. This current version is already -defined in the corresponding recipe directory. - -Package-archive recipes ------------------------ - -The recipe directory for a package archive contains the verbatim content of -the to-be-created package archive except for the _archives_ file. All other -files are copied verbatim to the archive. The content of the recipe's -_archives_ file may omit the version information from the listed ingredients. -Furthermore, the user part of each entry can be left blank by using '_' as a -wildcard. When generating the package archive from the recipe, the extract -tool will replace this wildcard with the user that creates the archive. - - -Convenience front-end to the extract, build tools -################################################# - -For developers, the work flow of interacting with the depot is most often the -combination of the _extract_ and _build_ tools whereas the latter expects -concrete version names as arguments. The _create_ tool accelerates this common -usage pattern by allowing the user to omit the version names. Operations -implicitly refer to the _current_ version of the archives as defined in -the recipes. - -Furthermore, the _create_ tool is able to manage version updates for the -developer. If invoked with the argument 'UPDATE_VERSIONS=1', it automatically -updates hash files of the involved recipes by taking the current date as -version name. This is a valuable assistance in situations where a commonly -used API changes. In this case, the versions of the API and all dependent -archives must be increased, which would be a labour-intensive task otherwise. -If the depot already contains an archive of the current version, the create -tools won't re-create the depot archive by default. Local modifications of -the source code in the repository do not automatically result in a new archive. -To ensure that the depot archive is current, one can specify 'FORCE=1' to -the create tool. With this argument, existing depot archives are replaced by -freshly extracted ones and version updates are detected. When specified for -creating binary archives, 'FORCE=1' normally implies 'REBUILD=1'. To prevent -the superfluous rebuild of binary archives whose source versions remain -unchanged, 'FORCE=1' can be combined with the argument 'REBUILD='. - - -Accessing depot content from run scripts -######################################## - -The depot tools are not meant to replace the run tool but rather to complement -it. When both tools are combined, the run tool implicitly refers to "current" -archive versions as defined for the archive's corresponding recipes. This way, -the regular run-tool work flow can be maintained while attaining a -productivity boost by fetching content from the depot instead of building it. - -Run scripts can use the 'import_from_depot' function to incorporate archive -content from the depot into a scenario. The function must be called after the -'create_boot_directory' function and takes any number of pkg, src, or raw -archives as arguments. An archive is specified as depot-relative path of the -form '//name'. Run scripts may call 'import_from_depot' -repeatedly. Each argument can refer to a specific version of an archive or -just the version-less archive name. In the latter case, the current version -(as defined by a corresponding archive recipe in the source tree) is used. - -If a 'src' archive is specified, the run tool integrates the content of -the corresponding binary archive into the scenario. The binary archives -are selected according the spec values as defined for the build directory. - diff --git a/doc/getting_started.txt b/doc/getting_started.txt deleted file mode 100644 index e9679cd351..0000000000 --- a/doc/getting_started.txt +++ /dev/null @@ -1,154 +0,0 @@ - - ============================= - How to start exploring Genode - ============================= - - Norman Feske - - -Abstract -######## - -This guide is meant to provide you a painless start with using the Genode OS -Framework. It explains the steps needed to get a simple demo system running -on Linux first, followed by the instructions on how to run the same scenario -on a microkernel. - - -Quick start to build Genode for Linux -##################################### - -The best starting point for exploring Genode is to run it on Linux. Make sure -that your system satisfies the following requirements: - -* GNU Make version 3.81 or newer -* 'libsdl2-dev', 'libdrm-dev', and 'libgbm-dev' (needed to run interactive - system scenarios directly on Linux) -* 'tclsh' and 'expect' -* 'byacc' (only needed for the L4/Fiasco kernel) -* 'qemu' and 'xorriso' (for testing non-Linux platforms via Qemu) - -For using the entire collection of ported 3rd-party software, the following -packages should be installed additionally: 'autoconf2.64', 'autogen', 'bison', -'flex', 'g++', 'git', 'gperf', 'libxml2-utils', 'subversion', and 'xsltproc'. - -Your exploration of Genode starts with obtaining the source code of the -[https://sourceforge.net/projects/genode/files/latest/download - latest version] -of the framework. For detailed instructions and alternatives to the -download from Sourceforge please refer to [https://genode.org/download]. -Furthermore, you will need to install the official Genode tool chain, which -you can download at [https://genode.org/download/tool-chain]. - -The Genode build system never touches the source tree but generates object -files, libraries, and programs in a dedicated build directory. We do not have a -build directory yet. For a quick start, let us create one for the Linux base -platform: - -! cd -! ./tool/create_builddir x86_64 - -This creates a new build directory for building x86_64 binaries in './build'. -The build system creates unified binaries that work on the given -architecture independent from the underlying base platform, in this case Linux. - -Now change into the fresh build directory: - -! cd build/x86_64 - -Please uncomment the following line in 'etc/build.conf' to make the -build process as smooth as possible. - -! RUN_OPT += --depot-auto-update - -To give Genode a try, build and execute a simple demo scenario via: - -! make KERNEL=linux BOARD=linux run/demo - -By invoking 'make' with the 'run/demo' argument, all components needed by the -demo scenario are built and the demo is executed. This includes all components -which are implicitly needed by the base platform. The base platform that the -components will be executed upon on is selected via the 'KERNEL' and 'BOARD' -variables. If you are interested in looking behind the scenes of the demo -scenario, please refer to 'doc/build_system.txt' and the run script at -'os/run/demo.run'. - - -Using platforms other than Linux -================================ - -Running Genode on Linux is the most convenient way to get acquainted with the -framework. However, the point where Genode starts to shine is when used as the -user land executed on a microkernel. The framework supports a variety of -different kernels such as L4/Fiasco, L4ka::Pistachio, OKL4, and NOVA. Those -kernels largely differ in terms of feature sets, build systems, tools, and boot -concepts. To relieve you from dealing with those peculiarities, Genode provides -you with an unified way of using them. For each kernel platform, there exists -a dedicated description file that enables the 'prepare_port' tool to fetch and -prepare the designated 3rd-party sources. Just issue the following command -within the toplevel directory of the Genode source tree: - -! ./tool/ports/prepare_port - -Note that each 'base-' directory comes with a 'README' file, which -you should revisit first when exploring the base platform. Additionally, most -'base-' directories provide more in-depth information within their -respective 'doc/' subdirectories. - -For the VESA driver on x86, the x86emu library is required and can be -downloaded and prepared by again invoking the 3rd-party sources preparation -tool: - -! ./tool/ports/prepare_port x86emu - -On x86 base platforms the GRUB2 boot loader is required and can be -downloaded and prepared by invoking: - -! ./tool/ports/prepare_port grub2 - -Now that the base platform is prepared, the 'create_builddir' tool can be used -to create a build directory for your architecture of choice by giving the -architecture as argument. To see the list of available architecture, execute -'create_builddir' with no arguments. Note, that not all kernels support all -architectures. - -For example, to give the demo scenario a spin on the OKL4 kernel, the following -steps are required: - -# Download the kernel: - ! cd - ! ./tool/ports/prepare_port okl4 -# Create a build directory - ! ./tool/create_builddir x86_32 -# Uncomment the following line in 'x86_32/etc/build.conf' - ! REPOSITORIES += $(GENODE_DIR)/repos/libports -# Build and execute the demo using Qemu - ! make -C build/x86_32 KERNEL=okl4 BOARD=pc run/demo - -The procedure works analogously for the other base platforms. You can, however, -reuse the already created build directory and skip its creation step if the -architecture matches. - - -How to proceed with exploring Genode -#################################### - -Now that you have taken the first steps into using Genode, you may seek to -get more in-depth knowledge and practical experience. The foundation for doing -so is a basic understanding of the build system. The documentation at -'build_system.txt' provides you with the information about the layout of the -source tree, how new components are integrated, and how complete system -scenarios can be expressed. Equipped with this knowledge, it is time to get -hands-on experience with creating custom Genode components. A good start is the -'hello_tutorial', which shows you how to implement a simple client-server -scenario. To compose complex scenarios out of many small components, the -documentation of the Genode's configuration concept at 'os/doc/init.txt' is an -essential reference. - -Certainly, you will have further questions on your way with exploring Genode. -The best place to get these questions answered is the Genode mailing list. -Please feel welcome to ask your questions and to join the discussions: - -:Genode Mailing Lists: - - [https://genode.org/community/mailing-lists] - diff --git a/doc/gsoc_2012.txt b/doc/gsoc_2012.txt deleted file mode 100644 index 0f11fa4229..0000000000 --- a/doc/gsoc_2012.txt +++ /dev/null @@ -1,236 +0,0 @@ - - - ========================== - Google Summer of Code 2012 - ========================== - - -Genode Labs has applied as mentoring organization for the Google Summer of Code -program in 2012. This document summarizes all information important to Genode's -participation in the program. - -:[http://www.google-melange.com/gsoc/homepage/google/gsoc2012]: - Visit the official homepage of the Google Summer of Code program. - -*Update* Genode Labs was not accepted as mentoring organization for GSoC 2012. - - -Application of Genode Labs as mentoring organization -#################################################### - -:Organization ID: genodelabs - -:Organization name: Genode Labs - -:Organization description: - - Genode Labs is a self-funded company founded by the original creators of the - Genode OS project. Its primary mission is to bring the Genode operating-system - technology, which started off as an academic research project, to the real - world. At present, Genode Labs is the driving force behind the Genode OS - project. - -:Organization home page url: - - http://www.genode-labs.com - -:Main organization license: - - GNU General Public License version 2 - -:Admins: - - nfeske, chelmuth - -:What is the URL for your Ideas page?: - - [http://genode.org/community/gsoc_2012] - -:What is the main IRC channel for your organization?: - - #genode - -:What is the main development mailing list for your organization?: - - genode-main@lists.sourceforge.net - -:Why is your organization applying to participate? What do you hope to gain?: - - During the past three months, our project underwent the transition from a - formerly company-internal development to a completely open and transparent - endeavour. By inviting a broad community for participation in shaping the - project, we hope to advance Genode to become a broadly used and recognised - technology. GSoC would help us to build our community. - - The project has its roots at the University of Technology Dresden where the - Genode founders were former members of the academic research staff. We have - a long and successful track record with regard to supervising students. GSoC - would provide us with the opportunity to establish and cultivate - relationships to new students and to spawn excitement about Genode OS - technology. - -:Does your organization have an application templateo?: - - GSoC student projects follow the same procedure as regular community - contributions, in particular the student is expected to sign the Genode - Contributor's Agreement. (see [http://genode.org/community/contributions]) - -:What criteria did you use to select your mentors?: - - We selected the mentors on the basis of their long-time involvement with the - project and their time-tested communication skills. For each proposed working - topic, there is least one stakeholder with profound technical background within - Genode Labs. This person will be the primary contact person for the student - working on the topic. However, we will encourgage the student to make his/her - development transparant to all community members (i.e., via GitHub). So - So any community member interested in the topic is able to bring in his/her - ideas at any stage of development. Consequently, in practive, there will be - multiple persons mentoring each students. - -:What is your plan for dealing with disappearing students?: - - Actively contact them using all channels of communication available to us, - find out the reason for disappearance, trying to resolve the problems. (if - they are related to GSoC or our project for that matter). - -:What is your plan for dealing with disappearing mentors?: - - All designated mentors are local to Genode Labs. So the chance for them to - disappear to very low. However, if a mentor disappears for any serious reason - (i.e., serious illness), our organization will provide a back-up mentor. - -:What steps will you take to encourage students to interact with your community?: - - First, we discussed GSoC on our mailing list where we received an overly - positive response. We checked back with other Open-Source projects related to - our topics, exchanged ideas, and tried to find synergies between our - respective projects. For most project ideas, we have created issues in our - issue tracker to collect technical information and discuss the topic. - For several topics, we already observed interests of students to participate. - - During the work on the topics, the mentors will try to encourage the - students to play an active role in discussions on our mailing list, also on - topics that are not strictly related to the student project. We regard an - active participation as key to to enable new community members to develop a - holistic view onto our project and gather a profound understanding of our - methodologies. - - Student projects will be carried out in a transparent fashion at GitHub. - This makes it easy for each community member to get involved, discuss - the rationale behind design decisions, and audit solutions. - - -Topics -###### - -While discussing GSoC participation on our mailing list, we identified the -following topics as being well suited for GSoC projects. However, if none of -those topics receives resonance from students, there is more comprehensive list -of topics available at our road map and our collection of future challenges: - -:[http://genode.org/about/road-map]: Road-map -:[http://genode.org/about/challenges]: Challenges - - -Combining Genode with the HelenOS/SPARTAN kernel -================================================ - -[http://www.helenos.org - HelenOS] is a microkernel-based multi-server OS -developed at the university of Prague. It is based on the SPARTAN microkernel, -which runs on a wide variety of CPU architectures including Sparc, MIPS, and -PowerPC. This broad platform support makes SPARTAN an interesting kernel to -look at alone. But a further motivation is the fact that SPARTAN does not -follow the classical L4 road, providing a kernel API that comes with an own -terminology and different kernel primitives. This makes the mapping of -SPARTAN's kernel API to Genode a challenging endeavour and would provide us -with feedback regarding the universality of Genode's internal interfaces. -Finally, this project has the potential to ignite a further collaboration -between the HelenOS and Genode communities. - - -Block-level encryption -====================== - -Protecting privacy is one of the strongest motivational factors for developing -Genode. One pivotal element with that respect is the persistence of information -via block-level encryption. For example, to use Genode every day at Genode -Labs, it's crucial to protect the confidentiality of some information that's -not part of the Genode code base, e.g., emails and reports. There are several -expansion stages imaginable to reach the goal and the basic building blocks -(block-device interface, ATA/SATA driver for Qemu) are already in place. - -:[https://github.com/genodelabs/genode/issues/55 - Discuss the issue...]: - - -Virtual NAT -=========== - -For sharing one physical network interface among multiple applications, Genode -comes with a component called nic_bridge, which implements proxy ARP. Through -this component, each application receives a distinct (virtual) network -interface that is visible to the real network. I.e., each application requests -an IP address via a DHCP request at the local network. An alternative approach -would be a component that implements NAT on Genode's NIC session interface. -This way, the whole Genode system would use only one IP address visible to the -local network. (by stacking multiple nat and nic_bridge components together, we -could even form complex virtual networks inside a single Genode system) - -The implementation of the virtual NAT could follow the lines of the existing -nic_bridge component. For parsing network packets, there are already some handy -utilities available (at os/include/net/). - -:[https://github.com/genodelabs/genode/issues/114 - Discuss the issue...]: - - -Runtime for the Go or D programming language -============================================ - -Genode is implemented in C++. However, we are repeatedly receiving requests -for offering more safe alternatives for implementing OS-level functionality -such as device drivers, file systems, and other protocol stacks. The goals -for this project are to investigate the Go and D programming languages with -respect to their use within Genode, port the runtime of of those languages -to Genode, and provide a useful level of integration with Genode. - - -Block cache -=========== - -Currently, there exists only the iso9660 server that is able to cache block -accesses. A generic solution for caching block-device accesses would be nice. -One suggestion is a component that requests a block session (routed to a block -device driver) as back end and also announces a block service (front end) -itself. Such a block-cache server waits for requests at the front end and -forwards them to the back end. But it uses its own memory to cache blocks. - -The first version could support only read-only block devices (such as CDROM) by -caching the results of read accesses. In this version, we already need an -eviction strategy that kicks in once the block cache gets saturated. For a -start this could be FIFO or LRU (least recently used). - -A more sophisticated version would support write accesses, too. Here we need a -way to sync blocks to the back end at regular intervals in order to guarantee -that all block-write accesses are becoming persistent after a certain time. We -would also need a way to explicitly flush the block cache (i.e., when the -front-end block session gets closed). - -:[https://github.com/genodelabs/genode/issues/113 - Discuss the issue...]: - - -; _Since Genode Labs was not accepted as GSoC mentoring organization, the_ -; _following section has become irrelevant. Hence, it is commented-out_ -; -; Student applications -; #################### -; -; The formal steps for applying to the GSoC program will be posted once Genode -; Labs is accepted as mentoring organization. If you are a student interested -; in working on a Genode-related GSoC project, now is a good time to get -; involved with the Genode community. The best way is joining the discussions -; at our mailing list and the issue tracker. This way, you will learn about -; the currently relevant topics, our discussion culture, and the people behind -; the project. -; -; :[http://genode.org/community/mailing-lists]: Join our mailing list -; :[https://github.com/genodelabs/genode/issues]: Discuss issues around Genode - diff --git a/doc/news.txt b/doc/news.txt index 69ca452c64..b18513a440 100644 --- a/doc/news.txt +++ b/doc/news.txt @@ -4,6 +4,78 @@ =========== +Genode OS Framework release 24.11 | 2024-11-22 +############################################## + +| With mirrored and panoramic multi-monitor setups, pointer grabbing, +| atomic blitting and panning, and panel-self-refresh support, Genode's GUI +| stack gets ready for the next decade. Hardware-wise, version 24.11 brings +| a massive driver update for the i.MX SoC family. As a special highlight, the +| release is accompanied by the first edition of the free book "Genode +| Applications" as a gateway for application developers into Genode. + +Closing up the Year of Sculpt OS usability as the theme of our road map +for 2024, we are excited to unveil the results of two intense lines of +usability-concerned work with the release of Genode 24.11. + +For the usability of the Genode-based Sculpt OS as day-to-day operating +system, the support of multi-monitor setups has been an unmet desire +for a long time. Genode 24.11 does not only deliver a solution as a +singular feature but improves the entire GUI stack in a holistic way, +addressing panel self-refresh, mechanisms needed to overcome tearing +artifacts, rigid resource partitioning between GUI applications, up to +pointer-grabbing support. + +The second line of work addresses the usability of application development for +Genode and Sculpt OS in particular. Over the course of the year, our Goa SDK +has seen a succession of improvements that make the development, porting, +debugging, and publishing of software a breeze. Still, given Genode's +novelties, the learning curve to get started has remained challenging. Our new +book "Genode Applications" is intended as a gateway into the world of Genode +for those of us who enjoy dwelling in architectural beauty but foremost want +to get things done. It features introductory material, explains fundamental +concepts and components, and invites the reader on to a ride through a series +of beginner-friendly as well as advanced tutorials. The book can be downloaded +for free at [https://genode.org]. + +Regarding hardware support, our work during the release cycle was hugely +motivated by the prospect of bringing Genode to the MNT Pocket Reform laptop, +which is based on the NXP i.MX8MP SoC. Along this way, we upgraded all +Linux-based i.MX drivers to kernel version 6.6 while consolidating a variety +of vendor kernels, equipped our platform driver with watchdog support, and +added board support for this platform to Sculpt OS. + +You can find these among more topics covered in the detailed +[https:/documentation/release-notes/24.11 - release documentation of version 24.11...] + + +Sculpt OS release 24.10 | 2024-10-30 +#################################### + +| Thanks to a largely revamped GUI stack, the Genode-based +| Sculpt OS 24.10 has gained profound support for multi-monitor setups. + +Among the many usability-related topics on our road map, multi-monitor +support is certainly the most anticipated feature. It motivated a holistic +modernization of Genode's GUI stack over several months, encompassing drivers, +the GUI multiplexer, inter-component interfaces, up to widget toolkits. Sculpt +OS 24.10 combines these new foundations with a convenient +[https:/documentation/articles/sculpt-24-10#Multi-monitor_support - user interface] +for controlling monitor modes, making brightness adjustments, and setting up +mirrored and panoramic monitor configurations. + +Besides this main theme, version 24.10 benefits from the advancements of the +Genode OS Framework over the past six months: compatibility with Qt6, +drivers ported from the Linux kernel version 6.6.47, and comprehensive +[https:/documentation/release-notes/24.08#Goa_SDK - debugging support] +for the Goa SDK. + +Sculpt OS 24.10 is available as ready-to-use system image for PC hardware, +the PinePhone, and the MNT Reform laptop at the +[https:/download/sculpt - Sculpt download page] accompanied +with updated [https:/documentation/articles/sculpt-24-10 - documentation]. + + Genode OS Framework release 24.08 | 2024-08-29 ############################################## diff --git a/doc/porting_guide.txt b/doc/porting_guide.txt deleted file mode 100644 index dd2fe85597..0000000000 --- a/doc/porting_guide.txt +++ /dev/null @@ -1,1451 +0,0 @@ - ==================== - Genode Porting Guide - ==================== - - Genode Labs GmbH - - -Overview -######## - -This document describes the basic workflows for porting applications, libraries, -and device drivers to the Genode framework. It consists of the following -sections: - -:[http:porting_applications - Porting third-party code to Genode]: - Overview of the general steps needed to use 3rd-party code on Genode. - -:[http:porting_dosbox - Porting a program to natively run on Genode]: - Step-by-step description of applying the steps described in the first - section to port an application, using DosBox as an example. - -:[http:porting_libraries - Native Genode port of a library]: - Many 3rd-party applications have library dependencies. This section shows - how to port a library using SDL_net (needed by DosBox) as an example. - -:[http:porting_noux_packages - Porting an application to Genode's Noux runtime]: - On Genode, there exists an environment specially tailored to execute - command-line based Unix software, the so-called Noux runtime. This section - demonstrates how to port and execute the tar program within Noux. - -:[http:porting_device_drivers - Porting devices drivers]: - This chapter describes the concepts of how to port a device driver to the - Genode framework. It requires the basic knowledge introduced in the previous - chapters and should be read last. - -Before reading this guide, it is strongly advised to read the "The Genode -Build System" documentation: - -:Build-system manual: - - [http://genode.org/documentation/developer-resources/build_system] - - -Porting third-party code to Genode -################################## - -Porting an existing program or library to Genode is for the most part a -straight-forward task and depends mainly on the complexity of the program -itself. Genode provides a fairly complete libc based on FreeBSD's libc whose -functionality can be extended by so-called libc plugins. If the program one -wants to port solely uses standard libc functions, porting becomes easy. Every -porting task involves usually the same steps which are outlined below. - - -Steps in porting applications to Genode -======================================= - -# Check requirements/dependencies (e.g. on Linux) - - The first step is gathering information about the application, - e.g. what functionality needs to be provided by the target system and - which libraries does it use. - -# Create a port file - - Prepare the source code of the application for the use within Genode. The - Genode build-system infrastructure uses fetch rules, so called port files, - which declare where the source is obtained from, what patches are applied - to the source code, and where the source code will be stored and - configured. - -# Check platform dependent code and create stub code - - This step may require changes to the original source code - of the application to be compilable for Genode. At this point, it - is not necessary to provide a working implementation for required - functions. Just creating stubs of the various functions is fine. - -# Create build-description file - - To compile the application we need build rules. Within these rules - we also declare all dependencies (e.g. libraries) that are needed - by it. The location of these rules depends on the type - of the application. Normal programs on one hand use a _target.mk_ file, - which is located in the program directory (e.g. _src/app/foobar_) - within a given Genode repository. Libraries on the other hand use - one or more _.mk_ files that are placed in the _lib/mk_ - directory of a Genode repository. In addition, libraries have to - provide _import-.mk_ files. Amongst other things, these - files are used by applications to find the associated header files - of a library. The import files are placed in the _lib/import_ - directory. - -# Create a run script to ease testing - - To ease the testing of applications, it is reasonable to write a run script - that creates a test scenario for the application. This run script is used - to automatically build all components of the Genode OS framework that are - needed to run the application as well as the application itself. Testing - the application on any of the kernels supported by Genode becomes just a - matter of executing the run script. - -# Compile the application - - The ported application is compiled from within the respective build - directory like any other application or component of Genode. The build - system of Genode uses the build rules created in the fourth step. - -# Run the application - - While porting an application, easy testing is crucial. By using the run script - that was written in the fifth step we reduce the effort. - -# Debug the application - - In most cases, a ported application does not work right away. We have to - debug misbehaviour and implement certain functionality in the platform-depending - parts of the application so that is can run on Genode. There are - several facilities available on Genode that help in the process. These are - different on each Genode platform but basically break down to using either a - kernel debugger (e.g., JDB on Fiasco.OC) or 'gdb(1)'. The reader of this guide - is advised to take a look at the "User-level debugging on Genode via GDB" - documentation. - -_The order of step 1-4 is not mandatory but is somewhat natural._ - - -Porting a program to natively run on Genode -########################################### - -As an example on how to create a native port of a program for Genode, we will -describe the porting of DosBox more closely. Hereby, each of the steps -outlined in the previous section will be discussed in detail. - - -Check requirements/dependencies -=============================== - -In the first step, we build DosBox for Linux/x86 to obtain needed information. -Nowadays, most applications use a build-tool like Autotools or something -similar that will generate certain files (e.g., _config.h_). These files are -needed to successfully compile the program. Naturally they are required on -Genode as well. Since Genode does not use the original build tool of the -program for native ports, it is appropriate to copy those generated files -and adjust them later on to match Genode's settings. - -We start by checking out the source code of DosBox from its subversion repository: - -! $ svn export http://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@3837 dosbox-svn-3837 -! $ cd dosbox-svn-3837 - -At this point, it is helpful to disable certain options that are not -available or used on Genode just to keep the noise down: - -! $ ./configure --disable-opengl -! $ make > build.log 2>&1 - -After the DosBox binary is successfully built, we have a log file -(build.log) of the whole build process at our disposal. This log file will -be helpful later on when the _target.mk_ file needs to be created. In -addition, we will inspect the DosBox binary: - -! $ readelf -d -t src/dosbox|grep NEEDED -! 0x0000000000000001 (NEEDED) Shared library: [libasound.so.2] -! 0x0000000000000001 (NEEDED) Shared library: [libdl.so.2] -! 0x0000000000000001 (NEEDED) Shared library: [libpthread.so.0] -! 0x0000000000000001 (NEEDED) Shared library: [libSDL-1.2.so.0] -! 0x0000000000000001 (NEEDED) Shared library: [libpng12.so.0] -! 0x0000000000000001 (NEEDED) Shared library: [libz.so.1] -! 0x0000000000000001 (NEEDED) Shared library: [libSDL_net-1.2.so.0] -! 0x0000000000000001 (NEEDED) Shared library: [libX11.so.6] -! 0x0000000000000001 (NEEDED) Shared library: [libstdc++.so.6] -! 0x0000000000000001 (NEEDED) Shared library: [libm.so.6] -! 0x0000000000000001 (NEEDED) Shared library: [libgcc_s.so.1] -! 0x0000000000000001 (NEEDED) Shared library: [libc.so.6] - -Using _readelf_ on the binary shows all direct dependencies. We now know -that at least libSDL, libSDL_net, libstdc++, libpng, libz, and -libm are required by DosBox. The remaining libraries are mostly -mandatory on Linux and do not matter on Genode. Luckily all of these -libraries are already available on Genode. For now all we have to do is to -keep them in mind. - - -Creating the port file -====================== - -Since DosBox is an application, which depends on several ported -libraries (e.g., libSDL), the _ports_ repository within the Genode -source tree is a natural fit. On that account, the port file -_ports/ports/dosbox.port_ is created. - -For DosBox the _dosbox.port_ looks as follows: - -! LICENSE := GPLv2 -! VERSION := svn -! DOWNLOADS := dosbox.svn -! -! URL(dosbox) := http://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk -! DIR(dosbox) := src/app/dosbox -! REV(dosbox) := 3837 - -First, we define the license, the version and the type of the source code -origin. In case of DosBox, we checkout the source code from a Subversion -repository. This is denoted by the '.svn' suffix of the item specified in -the 'DOWNLOADS' declaration. Other valid types are 'file' (a plain file), -'archive' (an archive of the types tar.gz, tar.xz, tgz, tar.bz2, or zip) -or 'git' (a Git repository). -To checkout the source code out from the Subversion repository, we also need -its URL, the revision we want to check out and the destination directory -that will contain the sources afterwards. These declarations are mandatory and -must always be specified. Otherwise the preparation of the port will fail. - -! PATCHES := $(addprefix src/app/dosbox/patches/,\ -! $(notdir $(wildcard $(REP_DIR)/src/app/dosbox/patches/*.patch))) -! -! PATCH_OPT := -p2 -d src/app/dosbox - -As next step, we declare all patches that are needed for the DosBox port. -Since in this case, the patches are using a different path format, we have -to override the default patch settings by defining the _PATCH_OPT_ variable. - -Each port file comes along with a hash file. This hash is generated by taking -several sources into account. For one, the port file, each patch and the -port preparation tool (_tool/ports/prepare_port_) are the ingredients for -the hash value. If any of these files is changed, a new hash will be generated, -For now, we just write "dummy" in the '_ports/ports/dosbox.hash_ file. - -The DosBox port can now be prepared by executing - -! $ /tool/ports/prepare_port dosbox - -However, we get the following error message: - -! Error: /ports/dosbox.port is out of date, expected - -We get this message because we had specified the "dummy" hash value in -the _dosbox.hash_ file. The prepare_port tool computes a fingerprint -of the actual version of the port and compares this fingerprint with the -hash value specified in _dosbox.hash_. The computed fingerprint can -be found at _/contrib/dosbox-dummy/dosbox.hash_. In the final -step of the port, we will replace the dummy fingerprint with the actual -fingerprint of the port. But before finalizing the porting work, it is -practical to keep using the dummy hash and suppress the fingerprint check. -This can be done by adding 'CHECK_HASH=no' as argument to the prepare_port tool: - -! $ /tool/ports/prepare-port dosbox CHECK_HASH=no - - -Check platform-dependent code -============================= - -At this point, it is important to spot platform-dependent source files or -rather certain functions that are not yet available on Genode. These source -files should be omitted. Of course they may be used as a guidance when -implementing the functionality for Genode later on, when creating the -_target.mk_ file. In particular the various 'cdrom_ioctl_*.cpp' files are such -candidates in this example. - - -Creating the build Makefile -=========================== - -Now it is time to write the build rules into the _target.mk_, which will be -placed in _ports/src/app/dosbox_. - -Armed with the _build.log_ that we created while building DosBox on Linux, -we assemble a list of needed source files. If an application just -uses a simple Makefile and not a build tool, it might be easier to just -reuse the contents of this Makefile instead. - -First of all, we create a shortcut for the source directory of DosBox by calling -the 'select_from_ports' function: - -! DOSBOX_DIR := $(call select_from_ports,dosbox)/src/app/dosbox - -Under the hood, the 'select_from_ports' function looks up the -fingerprint of the specified port by reading the corresponding -.hash file. It then uses this hash value to construct the -directory path within the _contrib/_ directory that belongs to -the matching version of the port. If there is no hash file that matches the -port name, or if the port directory does not exist, the build system -will back out with an error message. - -Examining the log file leaves us with the following list of source files: - -! SRC_CC_cpu = $(notdir $(wildcard $(DOSBOX_DIR)/src/cpu/*.cpp)) -! SRC_CC_debug = $(notdir $(wildcard $(DOSBOX_DIR)/src/debug/*.cpp)) -! FILTER_OUT_dos = cdrom_aspi_win32.cpp cdrom_ioctl_linux.cpp cdrom_ioctl_os2.cpp \ -! cdrom_ioctl_win32.cpp -! SRC_CC_dos = $(filter-out $(FILTER_OUT_dos), \ -! $(notdir $(wildcard $(DOSBOX_DIR)/src/dos/*.cpp))) -! […] -! SRC_CC = $(notdir $(DOSBOX_DIR)/src/dosbox.cpp) -! SRC_CC += $(SRC_CC_cpu) $(SRC_CC_debug) $(SRC_CC_dos) $(SRC_CC_fpu) \ -! $(SRC_CC_gui) $(SRC_CC_hw) $(SRC_CC_hw_ser) $(SRC_CC_ints) \ -! $(SRC_CC_ints) $(SRC_CC_misc) $(SRC_CC_shell) -! -! vpath %.cpp $(DOSBOX_DIR)/src -! vpath %.cpp $(DOSBOX_DIR)/src/cpu -! […] - -_The only variable here that is actually evaluated by Genode's build-system is_ -'SRC_CC'. _The rest of the variables are little helpers that make our_ -_life more comfortable._ - -In this case, it is mandatory to use GNUMake's 'notdir' file name function -because otherwise the compiled object files would be stored within -the _contrib_ directories. Genode runs on multiple platforms with varying -architectures and mixing object files is considered harmful, which can happen -easily if the application is build from the original source directory. That's -why you have to use a build directory for each platform. The Genode build -system will create the needed directory hierarchy within the build directory -automatically. By combining GNUMake's 'notdir' and 'wildcard' function, we -can assemble a list of all needed source files without much effort. We then -use 'vpath' to point GNUMake to the right source file within the dosbox -directory. - -The remaining thing to do now is setting the right include directories and proper -compiler flags: - -! INC_DIR += $(PRG_DIR) -! INC_DIR += $(DOSBOX_DIR)/include -! INC_DIR += $(addprefix $(DOSBOX_DIR)/src, cpu debug dos fpu gui hardware \ -! hardware/serialport ints misc shell) - -'PRG_DIR' _is a special variable of Genode's build-system_ -_and its value is always the absolute path to the directory containing_ -_the 'target.mk' file._ - -We copy the _config.h_ file, which was generated in the first step to this -directory and change certain parts of it to better match Genode's -environment. Below is a skimmed diff of these changes: - -! --- config.h.orig 2013-10-21 15:27:45.185719517 +0200 -! +++ config.h 2013-10-21 15:36:48.525727975 +0200 -! @@ -25,7 +25,8 @@ -! /* #undef AC_APPLE_UNIVERSAL_BUILD */ -! -! /* Compiling on BSD */ -! -/* #undef BSD */ -! +/* Genode's libc is based on FreeBSD 8.2 */ -! +#define BSD 1 -! -! […] -! -! /* The type of cpu this target has */ -! -#define C_TARGETCPU X86_64 -! +/* we define it ourself */ -! +/* #undef C_TARGETCPU */ -! -! […] - -Thereafter, we specify the compiler flags: - -! CC_OPT = -DHAVE_CONFIG_H -D_GNU_SOURCE=1 -D_REENTRANT -! ifeq ($(filter-out $(SPECS),x86_32),) -! INC_DIR += $(PRG_DIR)/x86_32 -! CC_OPT += -DC_TARGETCPU=X86 -! else ifeq ($(filter-out $(SPECS),x86_64),) -! INC_DIR += $(PRG_DIR)/x86_64 -! CC_OPT += -DC_TARGETCPU=X86_64 -! endif -! -! CC_WARN = -Wall -! #CC_WARN += -Wno-unused-variable -Wno-unused-function -Wno-switch \ -! -Wunused-value -Wno-unused-but-set-variable - -As noted in the commentary seen in the diff we define 'C_TARGETCPU' -and adjust the include directories ourselves according to the target -architecture. - -While debugging, compiler warnings for 3rd-party code are really helpful but -tend to be annoying after the porting work is finished, we can -remove the hashmark to keep the compiler from complaining too -much. - -Lastly, we need to add the required libraries, which we acquired in step 1: - -! LIBS += libc libm libpng sdl stdcxx zlib -! LIBS += libc_lwip_nic_dhcp config_args - -In addition to the required libraries, a few Genode specific -libraries are also needed. These libraries implement certain -functions in the libc via the libc's plugin mechanism. -libc_lwip_nic_dhcp, for example, is used to connect the BSD socket interface -to a NIC service such as a network device driver. - - -Creating the run script -======================= - -To ease compiling, running and debugging DosBox, we create a run script -at _ports/run/dosbox.run_. - -First, we specify the components that need to be built - -! set build_components { -! core init drivers/audio drivers/framebuffer drivers/input -! drivers/pci drivers/timer app/dosbox -! } -! build $build_components - -and instruct _tool/run_ to create the boot directory that hosts -all binaries and files which belong to the DosBox scenario. - -As the name 'build_components' suggests, you only have to declare -the components of Genode, which are needed in this scenario. All -dependencies of DosBox (e.g. libSDL) will be built before DosBox -itself. - -Nextm we provide the scenario's configuration 'config': - -! append config { -! -! -! -! -! -! -! -! -! -! -! -! -! -! -! -! -! -! -! } -! -! -! -! -! -! -! -! -! -! -! -! -! -! -! -! -! -! -! -! -! -! -! -! -! -! -! } -! install_config $config - -The _config_ file will be used by the init program to start all -components and application of the scenario, including DosBox. - -Thereafter we declare all boot modules: - -! set boot_modules { -! core init timer audio_drv fb_drv ps2_drv ld.lib.so -! libc.lib.so libm.lib.so -! lwip.lib.so libpng.lib.so stdcxx.lib.so sdl.lib.so -! pthread.lib.so zlib.lib.so dosbox dosbox.tar -! } -! build_boot_image $boot_modules - -The boot modules comprise all binaries and other files like -the tar archive that contains DosBox' configuration file _dosbox.conf_ -that are needed for this scenario to run sucessfully. - -Finally, we set certain options, which are used when Genode is executed -in Qemu and instruct _tool/run_ to keep the scenario executing as long -as it is not manually stopped: - -! append qemu_args " -m 256 -soundhw ac97 " -! run_genode_until forever - -_It is reasonable to write the run script in a way that makes it possible_ -_to use it for multiple Genode platforms. Debugging is often done on_ -_Genode/Linux or on another Genode platform running in Qemu but testing_ -_is normally done using actual hardware._ - - -Compiling the program -===================== - -To compile DosBox and all libraries it depends on, we execute - -! $ make app/dosbox - -from within Genode's build directory. - -_We could also use the run script that we created in the previous step but_ -_that would build all components that are needed to actually run_ DosBox -_and at this point our goal is just to get_ DosBox _compiled._ - -At the first attempt, the compilation stopped because g++ could not find -the header file _sys/timeb.h_: - -! /src/genode/ports/contrib/dosbox-svn-3837/src/ints/bios.cpp:35:23: fatal error: -! sys/timeb.h: No such file or directory - -This header is part of the libc but until now there was no program, which -actually used this header. So nobody noticed that it was missing. This -can happen all time when porting a new application to Genode because most -functionality is enabled or rather added on demand. Someone who is -porting applications to Genode has to be aware of the fact that it might be -necessary to extend Genode functionality by enabling so far disabled -bits or implementing certain functionality needed by the -application that is ported. - -Since 'ftime(3)' is a deprecated function anyway we change the code of -DosBox to use 'gettimeofday(2)'. - -After this was fixed, we face another problem: - -! /src/genode/ports/contrib/dosbox-svn-3837/src/ints/int10_vesa.cpp:48:33: error: -! unable to find string literal operator ‘operator"" VERSION’ - -The fix is quite simple and the compile error was due to the fact -that Genode uses C++11 by now. It often happens that 3rd party code -is not well tested with a C++11 enabled compiler. In any case, a patch file -should be created which will be applied when preparing the port. - -Furthermore it would be reasonable to report the bug to the DosBox -developers so it can be fixed upstream. We can then get rid of our -local patch. - -The next show stoppers are missing symbols in Genode's SDL library port. -As it turns out, we never actually compiled and linked in the cdrom dummy -code which is provided by SDL. - - -Running the application -======================= - -DosBox was compiled successfully. Now it is time to execute the binary -on Genode. Hence we use the run script we created in step 5: - -! $ make run/dosbox - -This may take some time because all other components of the Genode OS -Framework that are needed for this scenario have to be built. - - -Debugging the application -========================= - -DosBox was successfully compiled but unfortunately it did not run. -To be honest that was expected and here the fun begins. - -At this point, there are several options to chose from. By running -Genode/Fiasco.OC within Qemu, we can use the kernel debugger (JDB) -to take a deeper look at what went wrong (e.g., backtraces of the -running processes, memory dumps of the faulted DosBox process etc.). -Doing this can be quite taxing but fortunately Genode runs on multiple -kernels and often problems on one kernel can be reproduced on another -kernel. For this reason, we choose Genode/Linux where we can use all -the normal debugging tools like 'gdb(1)', 'valgrind(1)' and so on. Luckily -for us, DosBox also fails to run on Genode/Linux. The debugging steps -are naturally dependent on the ported software. In the case of DosBox, -the remaining stumbling blocks were a few places where DosBox assumed -Linux as a host platform. - -For the sake of completeness here is a list of all files that were created by -porting DosBox to Genode: - -! ports/ports/dosbox.hash -! ports/ports/dosbox.port -! ports/run/dosbox.run -! ports/src/app/dosbox/config.h -! ports/src/app/dosbox/patches/bios.patch -! ports/src/app/dosbox/patches/int10_vesa.patch -! ports/src/app/dosbox/target.mk -! ports/src/app/dosbox/x86_32/size_defs.h -! ports/src/app/dosbox/x86_64/size_defs.h - -[image dosbox] - DosBox ported to Genode - -Finally, after having tested that both the preparation-step and the -build of DosBox work as expected, it is time to -finalize the fingerprint stored in the _/ports/ports/dosbox.hash_ -file. This can be done by copying the content of the -_/contrib/dosbox-dummy/dosbox.hash file_. -Alternatively, you may invoke the _tool/ports/update_hash_ tool with the -port name "dosbox" as argument. The next time, you -invoke the prepare_port tool, do not specify the 'CHECK_HASH=no' argument. -So the fingerprint check will validate that the _dosbox.hash_ file -corresponds to your _dosbox.port_ file. From now on, the -_/contrib/dosbox-dummy_ directory will no longer be used because -the _dosbox.hash_ file points to the port directory named after the real -fingerprint. - - -Native Genode port of a library -############################### - -Porting a library to be used natively on Genode is similar to porting -an application to run natively on Genode. The source codes have to be -obtained and, if needed, patched to run on Genode. -As an example on how to port a library to natively run on Genode, we -will describe the porting of SDL_net in more detail. Ported libraries -are placed in the _libports_ repository of Genode. But this is just a -convention. Feel free to host your library port in a custom repository -of your's. - - -Checking requirements/dependencies -================================== - -We will proceed as we did when we ported DosBox to run natively on Genode. -First we build SDL_net on Linux to obtain a log file of the whole build -process: - -! $ wget http://www.libsdl.org/projects/SDL_net/release/SDL_net-1.2.8.tar.gz -! $ tar xvzf SDL_net-1.2.8.tar.gz -! $ cd SDL_net-1.2.8 -! $ ./configure -! $ make > build.log 2>&1 - - -Creating the port file -====================== - -We start by creating _/libports/ports/sdl_net.port: - -! LICENSE := BSD -! VERSION := 1.2.8 -! DOWNLOADS := sdl_net.archive -! -! URL(sdl_net) := http://www.libsdl.org/projects/SDL_net/release/SDL_net-$(VERSION).tar.gz -! SHA(sdl_net) := fd393059fef8d9925dc20662baa3b25e02b8405d -! DIR(sdl_net) := src/lib/sdl_net -! -! PATCHES := src/lib/sdl_net/SDLnet.patch src/lib/sdl_net/SDL_net.h.patch - -In addition to the URL the SHA1 checksum of the SDL_net archive needs to -specified because _tool/prepare_port_ validates the downloaded archive -by using this hash. - -Applications that want to use SDL_net have to include the 'SDL_net.h' header -file. Hence it is necessary to make this file visible to applications. This is -done by populating the _/contrib/sdl-/include_ directory: - -! DIRS := include/SDL -! DIR_CONTENT(include/SDL) := src/lib/sdl_net/SDL_net.h - -For now, we also use a dummy hash in the _sdl_net.hash_ file like it was done -while porting DosBox. We will replace the dummy hash with the proper one at -the end. - - -Creating the build Makefile -=========================== - -We create the build rules in _libports/lib/mk/sdl_net.mk_: - -! SDL_NET_DIR := $(call select_from_ports,sdl_net)/src/lib/sdl_net -! -! SRC_C = $(notdir $(wildcard $(SDL_NET_DIR)/SDLnet*.c)) -! -! vpath %.c $(SDL_NET_DIR) -! -! INC_DIR += $(SDL_NET_DIR) -! -! LIBS += libc sdl - -'SDL_net' should be used as shared library. To achieve this, we -have to add the following statement to the 'mk' file: - -! SHARED_LIB = yes - -_If we omit this statement, Genode's build system will automatically_ -_build SDL_net as a static library called_ 'sdl_net.lib.a' _that_ -_is linked directly into the application._ - -It is reasonable to create a dummy application that uses the -library because it is only possible to build libraries automatically -as a dependency of an application. - -Therefore we create -_libports/src/test/libports/sdl_net/target.mk_ with the following content: - -! TARGET = test-sdl_net -! LIBS = libc sdl_net -! SRC_CC = main.cc - -! vpath main.cc $(PRG_DIR)/.. - -At this point we also create _lib/import/import-sdl_net.mk_ -with the following content: - -! SDL_NET_PORT_DIR := $(call select_from_ports,sdl_net) -! INC_DIR += $(SDL_NET_PORT_DIR)/include $(SDL_NET_PORT_DIR)/include/SDL - -Each port that depends on SDL_net and has added it to its LIBS variable -will automatically include the _import-sdl_net.mk_ file and therefore -will use the specified include directory to find the _SDL_net.h_ header. - - -Compiling the library -===================== - -We compile the SDL_net library as a side effect of building our dummy test -program by executing - -! $ make test/libports/sdl_net - -All source files are compiled fine but unfortunately the linking of the -library does not succeed: - -! /src/genodebuild/foc_x86_32/var/libcache/sdl_net/sdl_net.lib.so: -! undefined reference to `gethostbyaddr' - -The symbol 'gethostbyaddr' is missing, which is often a clear sign -of a missing dependency. In this case however 'gethostbyaddr(3)' is -missing because this function does not exist in Genode's libc _(*)_. -But 'getaddrinfo(3)' exists. We are now facing the choice of implementing -'gethostbyaddr(3)' or changing the code of SDL_net to use 'getaddrinfo(3)'. -Porting applications or libraries to Genode always may involve this kind of -choice. Which way is the best has to be decided by closely examining the -matter at hand. Sometimes it is better to implement the missing functions -and sometimes it is more beneficial to change the contributed code. -In this case, we opt for changing SDL_net because the former function is -obsolete anyway and implementing 'gethostbyaddr(3)' involves changes to -several libraries in Genode, namely libc and the network related -libc plugin. Although we have to keep in mind that it is likely to encounter -another application or library that also uses this function in the future. - -With this change in place, SDL_net compiles fine. - -_(*) Actually this function is implemented in the Genode's_ libc _but is_ -_only available by using libc_resolv which we did not do for the sake of_ -_this example._ - - -Testing the library -=================== - -The freshly ported library is best tested with the application, which was the -reason the library was ported in the first place, since it is unlikely that -we port a library just for fun and no profit. Therefore, it is not necessary to -write a run script for a library alone. - -For the records, here is a list of all files that were created by -porting SDL_net to Genode: - -! libports/lib/mk/sdl_net.mk -! libports/lib/mk/import/import-sdl_net.mk -! libports/ports/sdl_net.hash -! libports/ports/sdl_net.port -! libports/src/lib/sdl_net/SDLnet.patch -! libports/test/libports/sdl_net/target.mk - - -Porting an application to Genode's Noux runtime -############################################### - -Porting an application to Genode's Noux runtime is basically the same as -porting a program to natively run on Genode. The source code has to be -prepared and, if needed, patched to run in Noux. However in contrast to -this, there are Noux build rules (_ports/mk/noux.mk_) that enable us to use -the original build-tool if it is based upon Autotools. Building the -application is done within a cross-compile environment. In this environment -all needed variables like 'CC', 'LD', 'CFLAGS' and so on are set to their -proper values. In addition to these precautions, using _noux.mk_ simplifies certain things. -The system-call handling/functions is/are implemented in the libc plugin -_libc_noux_ (the source code is found in _ports/src/lib/libc_noux_). All -applications running in Noux have to be linked against this library which is -done implicitly by using the build rules of Noux. - -As an example on how to port an application to Genode's Noux runtime, we -will describe the porting of GNU's 'tar' tool in more detail. A ported -application is normally referred to as a Noux package. - -Checking requirements/dependencies -================================== - -As usual, we first build GNU tar on Linux/x86 and capture the build -process: - -! $ wget http://ftp.gnu.org/gnu/tar/tar-1.27.tar.xz -! $ tar xJf tar-1.27.tar.xz -! $ cd tar-1.27 -! $ ./configure -! $ make > build.log 2>&1 - - -Creating the port file -====================== - -We start by creating the port Makefile _ports/ports/tar.mk_: - -! LICENSE := GPLv3 -! VERSION := 1.27 -! DOWNLOADS := tar.archive -! -! URL(tar) := http://ftp.gnu.org/gnu/tar/tar-$(VERSION).tar.xz -! SHA(tar) := 790cf784589a9fcc1ced33517e71051e3642642f -! SIG(tar) := ${URL(tar)}.sig -! KEY(tar) := GNU -! DIR(tar) := src/noux-pkg/tar - -_As of version 14.05, Genode does not check the signature specified via_ -_the SIG and KEY declaration but relies the SHA checksum only. However,_ -_as signature checks are planned in the future, we use to include the_ -_respective declarations if signature files are available._ - -While porting GNU tar we will use a dummy hash as well. - - -Creating the build rule -======================= - -Build rules for Noux packages are located in _/ports/src/noux-pkgs_. - -The _tar/target.mk_ corresponding to GNU tar looks like this: - -! CONFIGURE_ARGS = --bindir=/bin \ -! --libexecdir=/libexec -! -! include $(REP_DIR)/mk/noux.mk - -The variable 'CONFIGURE_ARGS' contains the options that are -passed on to Autoconf's configure script. The Noux specific build -rules in _noux.mk_ always have to be included last. - -The build rules for GNU tar are quite short and therefore at the end -of this chapter we take a look at a much more extensive example. - - -Creating a run script -===================== - -Creating a run script to test Noux packages is the same as it is -with running natively ported applications. Therefore we will only focus -on the Noux-specific parts of the run script and omit the rest. - -First, we add the desired Noux packages to 'build_components': - -! set noux_pkgs "bash coreutils tar" -! -! foreach pkg $noux_pkgs { -! lappend_if [expr ![file exists bin/$pkg]] build_components noux-pkg/$pkg } -! -! build $build_components - -Since each Noux package is, like every other Genode binary, installed to the -_/bin_ directory, we create a tar archive of each package from -each directory: - -! foreach pkg $noux_pkgs { -! exec tar cfv bin/$pkg.tar -h -C bin/$pkg . } - -_Using noux.mk makes sure that each package is always installed to_ -_/bin/._ - -Later on, we will use these tar archives to assemble the file system -hierarchy within Noux. - -Most applications ported to Noux want to read and write files. On that -matter, it is reasonable to provide a file-system service and the easiest -way to do this is to use the ram_fs server. This server provides a RAM-backed -file system, which is perfect for testing Noux applications. With -the help of the session label we can route multiple directories to the -file system in Noux: - -! append config { -! -! […] -! -! -! -! -! -! -! -! -! -! -! -! -! -! […] - -The file system Noux presents to the running applications is constructed -out of several stacked file systems. These file systems have to be -registered in the 'fstab' node in the configuration node of Noux: - -! -! -! -! } - -Each Noux package is added - -! foreach pkg $noux_pkgs { -! append config { -! " }} - -and the routes to the ram_fs file system are configured: - -! append config { -! -! -! -! -! -! -! -! -! } - -In this example we save the run script as _ports/run/noux_tar.run_. - - -Compiling the Noux package -========================== - -Now we can trigger the compilation of tar by executing - -! $ make VERBOSE= noux-pkg/tar - -_At least on the first compilation attempt, it is wise to unset_ 'VERBOSE' -_because it enables us to see the whole output of the_ 'configure' _process._ - -By now, Genode provides almost all libc header files that are used by -typical POSIX programs. In most cases, it is rather a matter of enabling -the right definitions and compilation flags. It might be worth to take a -look at FreeBSD's ports tree because Genode's libc is based upon the one -of FreeBSD 8.2.0 and if certain changes to the contributed code are needed, -they are normally already done in the ports tree. - -The script _noux_env.sh_ that is used to create the cross-compile -environment as well as the famous _config.log_ are found -in _/noux-pkg/_. - - -Running the Noux package -======================== - -We use the previously written run script to start the scenario, in which we -can execute and test the Noux package by issuing: - -! $ make run/noux_tar - -After the system has booted and Noux is running, we first create some test -files from within the running bash process: - -! bash-4.1$ mkdir /tmp/foo -! bash-4.1$ echo 'foobar' > /tmp/foo/bar - -Following this we try to create a ".tar" archive of the directory _/tmp/foo_ - -! bash-4.1$ cd /tmp -! bash-4.1$ tar cvf foo.tar foo/ -! tar: /tmp/foo: Cannot stat: Function not implemented -! tar: Exiting with failure status due to previous errors -! bash-4.1$ - -Well, this does not look too good but at least we have a useful error message -that leads (hopefully) us into the right direction. - - -Debugging an application that uses the Noux runtime -=================================================== - -Since the Noux service is basically the kernel part of our POSIX runtime -environment, we can ask Noux to show us the system calls executed by tar. -We change its configuration in the run script to trace all system calls: - -! […] -! -! -! […] - -We start the runscript again, create the test files and try to create a -".tar" archive. It still fails but now we have a trace of all system calls -and know at least what is going in Noux itself: - -! […] -! [init -> noux] PID 0 -> SYSCALL FORK -! [init -> noux] PID 0 -> SYSCALL WAIT4 -! [init -> noux] PID 5 -> SYSCALL STAT -! [init -> noux] PID 5 -> SYSCALL EXECVE -! [init -> noux] PID 5 -> SYSCALL STAT -! [init -> noux] PID 5 -> SYSCALL GETTIMEOFDAY -! [init -> noux] PID 5 -> SYSCALL STAT -! [init -> noux] PID 5 -> SYSCALL OPEN -! [init -> noux] PID 5 -> SYSCALL FTRUNCATE -! [init -> noux] PID 5 -> SYSCALL FSTAT -! [init -> noux] PID 5 -> SYSCALL GETTIMEOFDAY -! [init -> noux] PID 5 -> SYSCALL FCNTL -! [init -> noux] PID 5 -> SYSCALL WRITE -! [init -> noux -> /bin/tar] DUMMY fstatat(): fstatat called, not implemented -! [init -> noux] PID 5 -> SYSCALL FCNTL -! [init -> noux] PID 5 -> SYSCALL FCNTL -! [init -> noux] PID 5 -> SYSCALL WRITE -! [init -> noux] PID 5 -> SYSCALL FCNTL -! [init -> noux] PID 5 -> SYSCALL WRITE -! [init -> noux] PID 5 -> SYSCALL GETTIMEOFDAY -! [init -> noux] PID 5 -> SYSCALL CLOSE -! [init -> noux] PID 5 -> SYSCALL FCNTL -! [init -> noux] PID 5 -> SYSCALL WRITE -! [init -> noux] PID 5 -> SYSCALL CLOSE -! [init -> noux] child /bin/tar exited with exit value 2 -! […] - -_The trace log was shortened to only contain the important information._ - -We now see at which point something went wrong. To be honest, we see the -'DUMMY' message even without enabling the tracing of system calls. But -there are situations where a application is actually stuck in a (blocking) -system call and it is difficult to see in which. - -Anyhow, 'fstatat' is not properly implemented. At this point, we either have -to add this function to the Genode's libc or rather add it to libc_noux. -If we add it to the libc, not only applications running in Noux will -benefit but all applications using the libc. Implementing it in -libc_noux is the preferred way if there are special circumstances because -we have to treat the function differently when used in Noux (e.g. 'fork'). - -For the sake of completeness here is a list of all files that were created by -porting GNU tar to Genode's Noux runtime: - -! ports/ports/tar.hash -! ports/ports/tar.port -! ports/run/noux_tar.run -! ports/src/noux-pkg/tar/target.mk - - -Extensive build rules example -============================= - -The build rules for OpenSSH are much more extensive than the ones in -the previous example. Let us take a quick look at those build rules to -get a better understanding of possible challenges one may encounter while -porting a program to Noux: - -! # This prefix 'magic' is needed because OpenSSH uses $exec_prefix -! # while compiling (e.g. -DSSH_PATH) and in the end the $prefix and -! # $exec_prefix path differ. -! -! CONFIGURE_ARGS += --disable-ip6 \ -! […] -! --exec-prefix= \ -! --bindir=/bin \ -! --sbindir=/bin \ -! --libexecdir=/bin - -In addition to the normal configure options, we have to also define the -path prefixes. The OpenSSH build system embeds certain paths in the -ssh binary, which need to be changed for Noux. - -! INSTALL_TARGET = install - -Normally the Noux build rules (_noux.mk_) execute 'make install-strip' to -explicitly install binaries that are stripped of their debug symbols. The -generated Makefile of OpenSSH does not use this target. It automatically -strips the binaries when executing 'make install'. Therefore, we set the -variable 'INSTALL_TARGET' to override the default behaviour of the -Noux build rules. - -! LIBS += libcrypto libssl zlib libc_resolv - -As OpenSSH depends on several libraries, we need to include these in the -build Makefile. These libraries are runtime dependencies and need to be -present when running OpenSSH in Noux. - -Sometimes it is needed to patch the original build system. One way to do -this is by applying a patch while preparing the source code. The other -way is to do it before building the Noux package: - -! noux_built.tag: Makefile Makefile_patch -! -! Makefile_patch: Makefile -! @# -! @# Our $(LDFLAGS) contain options which are usable by gcc(1) -! @# only. So instead of using ld(1) to link the binary, we have -! @# to use gcc(1). -! @# -! $(VERBOSE)sed -i 's|^LD=.*|LD=$(CC)|' Makefile -! @# -! @# We do not want to generate host-keys because we are crosscompiling -! @# and we can not run Genode binaries on the build system. -! @# -! $(VERBOSE)sed -i 's|^install:.*||' Makefile -! $(VERBOSE)sed -i 's|^install-nokeys:|install:|' Makefile -! @# -! @# The path of ssh(1) is hardcoded to $(bindir)/ssh which in our -! @# case is insufficient. -! @# -! $(VERBOSE)sed -i 's|^SSH_PROGRAM=.*|SSH_PROGRAM=/bin/ssh|' Makefile - -The target _noux_built.tag_ is a special target defined by the Noux build -rules. It will be used by the build rules when building the Noux package. -We add the 'Makefile_patch' target as a dependency to it. So after configure -is executed, the generated Makefile will be patched. - -Autoconf's configure script checks if all requirements are fulfilled and -therefore, tests if all required libraries are installed on the host system. -This is done by linking a small test program against the particular library. -Since these libraries are only build-time dependencies, we fool the configure -script by providing dummy libraries: - -! # -! # Make the zlib linking test succeed -! # -! Makefile: dummy_libs -! -! LDFLAGS += -L$(PWD) -! -! dummy_libs: libz.a libcrypto.a libssl.a -! -! libcrypto.a: -! $(VERBOSE)$(AR) -rc $@ -! libssl.a: -! $(VERBOSE)$(AR) -rc $@ -! libz.a: -! $(VERBOSE)$(AR) -rc $@ - - -Porting devices drivers -####################### - -Even though Genode encourages writing native device drivers, this task sometimes -becomes infeasible. Especially if there is no documentation available for a -certain device or if there are not enough programming resources at hand to -implement a fully fledged driver. Examples of ported drivers can be found in -the 'dde_linux', 'dde_bsd', and 'dde_ipxe' repositories. - -In this chapter we will exemplary discuss how to port a Linux driver for an ARM -based SoC to Genode. The goal is to execute driver code in user land directly on -Genode while making the driver believe it is running within the Linux kernel. -Traditionally there have been two approaches to reach this goal in Genode. In -the past, Genode provided a Linux environment, called 'dde_linux26', with the -purpose to offer just enough infrastructure to easily port drivers. However, -after adding more drivers it became clear that this repository grew extensively, -making it hard to maintain. Also updating the environment to support newer -Linux-kernel versions became a huge effort which let the repository to be neglected -over time. - -Therefore we choose the path to write a customized environment for each driver, -which provides a specially tailored infrastructure. We found that the -support code usually is not larger than a couple of thousand lines of code, -while upgrading to newer driver versions, as we did with the USB drivers, is -feasible. - - -Basic driver structure -====================== - -The first step in porting a driver is to identify the driver code that has to be -ported. Once the code is located, we usually create a new Genode repository and -write a port file to download and extract the code. It is good practice to name -the port and the hash file like the new repository, e.g. _dde_linux.port_ if -the repository directory is called _/repos/dde_linux_. -Having the source code ready, there are three main tasks the environment must -implement. The first is the driver back end, which is responsible for raw device -access using Genode primitives, the actual environment that emulates Linux -function calls the driver code is using, and the front end, which exposes for -example some Genode-session interface (like NIC or block session) that client -applications can connect to. - - -Further preparations -==================== - -Having the code ready, the next step is to create an _*.mk_ file that actually -compiles the code. For a driver library _lib/mk/.mk_ has to be -created and for a stand-alone program _src//target.mk_ is created -within the repository. With the _*.mk_ file in place, we can now start the -actual compilation. Of course this will cause a whole lot of errors and -warnings. Most of the messages will deal with implicit declarations of functions -and unknown data types. What we have to do now is to go through each warning and -error message and either add the header file containing the desired function or -data type to the list of files that will be extracted to the _contrib_ directory -or create our own prototype or data definition. - -When creating our own prototypes, we put them in a file called _lx_emul.h_. To -actually get this file included in all driver files we use the following code in -the _*.mk_ file: - -! CC_C_OPT += -include $(INC_DIR)/lx_emul.h - -where 'INC_DIR' points to the include path of _lx_emul.h_. - -The hard part is to decide which of the two ways to go for a specific function -or data type, since adding header files also adds more dependencies and often -more errors and warnings. As a rule of thumb, try adding as few headers as -possible. - -The compiler will also complain about a lot of missing header files. Since we do -not want to create all these header files, we use a trick in our _*.mk_ file that -extracts all header file includes from the driver code and creates symbolic -links that correspond to the file name and links to _lx_emul.h_. You can put the -following code snippet in your _*.mk_ file which does the trick: - -!# -!# Determine the header files included by the contrib code. For each -!# of these header files we create a symlink to _lx_emul.h_. -!# -!GEN_INCLUDES := $(shell grep -rh "^\#include .*\/" $(DRIVER_CONTRIB_DIR) |\ -! sed "s/^\#include [^<\"]*[<\"]\([^>\"]*\)[>\"].*/\1/" | \ -! sort | uniq) -! -!# -!# Filter out original Linux headers that exist in the contrib directory -!# -!NO_GEN_INCLUDES := $(shell cd $(DRIVER_CONTRIB_DIR); find -name "*.h" | sed "s/.\///" | \ -! sed "s/.*include\///") -!GEN_INCLUDES := $(filter-out $(NO_GEN_INCLUDES),$(GEN_INCLUDES)) -! -!# -!# Put Linux headers in 'GEN_INC' dir, since some include use "../../" paths use -!# three level include hierarchy -!# -!GEN_INC := $(shell pwd)/include/include/include -! -!$(shell mkdir -p $(GEN_INC)) -! -!GEN_INCLUDES := $(addprefix $(GEN_INC)/,$(GEN_INCLUDES)) -!INC_DIR += $(GEN_INC) -! -!# -!# Make sure to create the header symlinks prior building -!# -!$(SRC_C:.c=.o) $(SRC_CC:.cc=.o): $(GEN_INCLUDES) -! -!$(GEN_INCLUDES): -! $(VERBOSE)mkdir -p $(dir $@) -! $(VERBOSE)ln -s $(LX_INC_DIR)/lx_emul.h $@ - -Make sure 'LX_INC_DIR' is the directory containing the _lx_emul.h_ file. Note -that 'GEN_INC' is added to your 'INC_DIR' variable. - -The 'DRIVER_CONTRIB_DIR' variable is defined by calling the _select_from_port_ -function at the beginning of a Makefile or a include file, which is used by -all other Makefiles: - -! DRIVER_CONTRIB_DIR := $(call select_from_ports,driver_repo)/src/lib/driver_repo - -The process of function definition and type declaration continues until the code -compiles. This process can be quite tiresome. When the driver code finally compiles, the -next stage is linking. This will of course lead to another whole set of errors -that complain about undefined references. To actually obtain a linked binary we -create a _dummies.cc_ file. To ease things up we suggest to create a macro called -'DUMMY' and implement functions as in the example below: - -! /* -! * Do not include 'lx_emul.h', since the implementation will most likely clash -! * with the prototype -! */ -! -!#define DUMMY(retval, name) \ -! DUMMY name(void) { \ -! PDBG( #name " called (from %p) not implemented", __builtin_return_address(0)); \ -! return retval; \ -!} -! -! DUMMY(-1, kmalloc) -! DUMMY(-1, memcpy) -! ... - -Create a 'DUMMY' for each undefined reference until the binary links. We now -have a linked binary with a dummy environment. - - -Debugging -========= - -From here on, we will actually start executing code, but before we do that, let us -have a look at the debugging options for device drivers. Since drivers have to -be tested on the target platform, there are not as many debugging options -available as for higher level applications, like running applications on the -Linux version of Genode while using GDB for debugging. Having these -restrictions, debugging is almost completely performed over the serial line and -on rare occasions with an hardware debugger using JTAG. - -For basic Linux driver debugging it is useful to implement the 'printk' -function (use 'dde_kit_printf' or something similar) first. This way, the driver -code can output something and additions for debugging can be made. The -'__builtin_return_address' function is also useful in order to determine where a -specific function was called from. 'printk' may become a problem with devices -that require certain time constrains because serial line output is very slow. This is -why we port most drivers by running them on top of the Fiasco.OC version of -Genode. There you can take advantage of Fiasco's debugger (JDB) and trace buffer -facility. - -The trace buffer can be used to log data and is much faster than 'printk' over -serial line. Please inspect the 'ktrace.h' file (at -_base-foc/contrib/l4/pkg/l4sys/include/ARCH-*/ktrace.h_) -that describes the complete interface. A very handy function there is - -!fiasco_tbuf_log_3val("My message", variable1, variable2, variable3); - -which stores a message and three variables in the trace buffer. The trace buffer -can be inspected from within JDB by pressing 'T'. - -JDB can be accessed at any time by pressing the 'ESC' key. It can be used to -inspect the state of all running threads and address spaces on the system. There -is no recent JDB documentation available, but - -:Fiasco kernel debugger manual: - - [http://os.inf.tu-dresden.de/fiasco/doc/jdb.pdf] - -should be a good starting point. It is also possible to enter the debugger at -any time from your program calling the 'enter_kdebug("My breakpoint")' function -from within your code. The complete JDB interface can be found in -_base-foc/contrib/l4/pkg/l4sys/include/ARCH-*/kdebug.h_. - -Note that the backtrace ('bt') command does not work out of the box on ARM -platforms. We have a small patch for that in our Fiasco.OC development branch -located at GitHub: [http://github.com/ssumpf/foc/tree/dev] - - -The back end -============ - -To ease up the porting of drivers and interfacing Genode from C code, Genode offers a -library called DDE kit. DDE kit provides access to common functions required -by drivers like device memory, virtual memory with physical-address lookup, -interrupt handling, timers, etc. Please inspect _os/include/dde_kit_ to see the -complete interface description. You can also use 'grep -r dde_kit_ *' to see -usage of the interface in Genode. - -As an example for using DDE kit we implement the 'kmalloc' call: - -!void *kmalloc(size_t size, gfp_t flags) -!{ -! return dde_kit_simple_malloc(size); -!} - -It is also possible to directly use Genode primitives from C++ files, the -functions only have to be declared as 'extern "C"' so they can be called from C -code. - - -The environment -=============== - -Having a dummy environment we may now begin to actually execute driver code. - -Driver initialization -~~~~~~~~~~~~~~~~~~~~~ - -Most Linux drivers will have an initialization routine to register itself within -the Linux kernel and do other initializations if necessary. In order to be -initialized, the driver will register a function using the 'module_init' call. -This registered function must be called before the driver is actually used. To -be able to call the registered function from Genode, we define the 'module_init' -macro in _lx_emul.h_ as follows: - -! #define module_init(fn) void module_##fn(void) { fn(); } - -when a driver now registers a function like - -! module_init(ehci_hcd_init); - -we would have to call - -! module_ehci_hcd_init(); - -during driver startup. Having implemented the above, it is now time to start our -ported driver on the target platform and check if the initialization function is -successful. Any important dummy functions that are called must be implemented -now. A dummy function that does not do device related things, like Linux book -keeping, may not be implemented. Sometimes Linux checks the return values of -functions we might not want to implement, in this case it is sufficient to simply -adjust the return value of the affected function. - -Device probing -~~~~~~~~~~~~~~ -Having the driver initialized, we will give the driver access to the device -resources. This is performed in two steps. In the case of ARM SoC's we have to -check in which state the boot loader (usually U-Boot) left the device. Sometimes -devices are already setup by the boot loader and only a simple device reset is -necessary to proceed. If the boot loader did not touch the device, we most -likely have to check and setup all the necessary clocks on the platform and may -have to perform other low level initializations like PHY setup. - -If the device is successfully (low level) initialized, we can hand it over to -the driver by calling the 'probe' function of the driver. For ARM platforms the -'probe' function takes a 'struct platform_device' as an argument and all -important fields, like device resources and interrupt numbers, should be set to -the correct values before calling 'probe'. During 'probe' the driver will most -likely map and access device memory, request interrupts, and reset the device. -All dummy functions that are related to these tasks should be implemented or -ported at this point. - -When 'probe' returns successful, you may either test other driver functions by -hand or start building the front-end. - - -The front end -============= - -An important design question is how the front end is attached to the driver. In -some cases the front end may not use the driver directly, but other Linux -subsystems that are ported or emulated by the environment. For example, the USB -storage driver implements parts of the SCSI subsystem, which in turn is used -by the front end. The whole decision depends on the kind of driver that is -ported and on how much additional infrastructure is needed to actually make use -of the data. Again an USB example: For USB HID, we needed to port the USB controller -driver, the hub driver, the USB HID driver, and the generic HID driver in order -to retrieve keyboard and mouse events from the HID driver. - -The last step in porting a device driver is to make it accessible to other -Genode applications. Typically this is achieved by implementing one of Genode's -session interfaces, like a NIC session for network adapters or a block session for -block devices. You may also define your own session interfaces. The -implementation of the session interface will most likely trigger driver calls, -so you have to have to keep an eye on the dummy functions. Also make sure that calls to the -driver actually do what they are supposed to, for example, some wrong return value -of a dummy function may cause a function to return without performing any work. - - -Notes on synchronization -======================== - -After some experiences with Linux drivers and multi-threading, we lately -choose to have all Linux driver code executed by a single thread only. This way no Linux -synchronization primitives have to be implemented and we simply don't have to -worry about subtle pre- and postconditions of many functions (like "this -function has to be called with lock 'x' being held"). - -Unfortunately we cannot get rid of all threads within a device-driver server, -there is at least one waiting for interrupts and one for the entry point that -waits for client session requests. In order to synchronize these threads, we use -Genode's signalling framework. So when, for example, the IRQ thread receives an -interrupt it will send a signal. The Linux driver thread will at certain points -wait for these signals (e.g., functions like 'schedule_timeout' or -'wait_for_completion') and execute the right code depending on the kind of -signal delivered or firmly speaking the signal context. For this to work, we use -a class called 'Signal_dispatcher' (_base/include/base/signal.h_) which inherits -from 'Signal_context'. More than one dispatcher can be bound to a signal -receiver, while each dispatcher might do different work, like calling the -Linux interrupt handler in the IRQ example. - - diff --git a/doc/release_notes/24-11.txt b/doc/release_notes/24-11.txt new file mode 100644 index 0000000000..6a9b77d72b --- /dev/null +++ b/doc/release_notes/24-11.txt @@ -0,0 +1,579 @@ + + + =============================================== + Release notes for the Genode OS Framework 24.11 + =============================================== + + Genode Labs + + + +During the discussion of this year's road-map roughly one year ago, the +usability concerns of Sculpt OS stood out. +Besides suspend/resume, which we addressed +[https://genode.org/documentation/release-notes/24.05#Suspend_resume_infrastructure - earlier this year], +multi-monitor support ranked highest on the list of desires. We are more than +happy to wrap up the year with the realization of this feature. +Section [Multi-monitor support] presents the many facets and outcomes of this +intensive line of work. + +Over the course of 2024, our Goa SDK has received tremendous advances, which +make the development, porting, debugging, and publishing of software for +Genode - and Sculpt OS in particular - a breeze. +So far however, the learning curve for getting started remained rather steep +because the underlying concepts largely deviate from the beaten tracks known +from traditional operating systems. Even though there is plenty of +documentation, it is rather scattered and overwhelming. +All the more happy we are to announce that the current release is accompanied +by a new book "Genode Applications" that can be downloaded for free and +provides a smooth gateway for application developers into the world of Genode +(Section [New "Genode Applications" book]). + +Regarding hardware-related technical topics, the release focuses on the +ARM-based i.MX SoC family, taking our ambition to run Sculpt OS on the MNT +Pocket Reform laptop as guiding theme. Section [Device drivers and platforms] +covers our driver and platform-related work in detail. + + +New "Genode Applications" book +############################## + +Complementary to our _Genode Foundations_ and _Genode Platforms_ books, we have +been working on a new book that concentrates on application development. +_Genode Applications_ centers on the Goa SDK that we introduced with +[https://genode.org/documentation/release-notes/19.11#New_tooling_for_bridging_existing_build_systems_with_Genode - Genode 19.11] +and which has seen significant improvements over the past year +([https://genode.org/documentation/release-notes/23.08#Goa_tool_gets_usability_improvements_and_depot-index_publishing_support - 23.08], +[https://genode.org/documentation/release-notes/24.02#Sculpt_OS_as_remote_test_target_for_the_Goa_SDK - 24.02], +[https://genode.org/documentation/release-notes/24.08#Goa_SDK - 24.08]). + +:
+:

+:

+: +: +: +:
+:

+ +The book intends to provide a beginner-friendly starting point for application +development and porting for Genode and Sculpt OS in particular. It starts off +with a getting-started tutorial for the Goa tool, and further recapitulates +Genode's architecture and a subset of its libraries, components, and +conventions such as the C runtime, VFS, NIC router, and package management. +With these essentials in place, the book is topped off with instructions for +application debugging and a collection of advanced tutorials. + +Aligned with the release of Sculpt 24.10, we updated the Goa tool with the +corresponding depot archive versions. Furthermore, the Sculpt-integrated and +updated _Goa testbed_ preset is now prepared for remote debugging. + +:
+ +:First revision of the Genode Applications document: + + [https://genode.org/documentation/genode-applications-24-11.pdf] + + +Multi-monitor support +##################### + +Among the users of the Genode-based Sculpt OS, the flexible use of multiple +monitors was certainly the most longed-after desire raised during our public +road-map discussion roughly one year ago. We quickly identified that a +profound solution cannot focus on piecemeal extensions of individual +components but must embrace an architectural step forward. The step turned +out being quite a leap. +In fact, besides reconsidering the roles of display and input drivers in +[https://genode.org/documentation/release-notes/20.08#The_GUI_stack__restacked - version 20.08], +the GUI stack has remained largely unchanged since +[https://genode.org/documentation/release-notes/14.08#New_GUI_architecture - version 14.08]. +So we took our multi-monitor ambitions as welcome opportunity to incorporate +our experiences of the past ten years into a new design for the next ten +years. + + +Tickless GUI server and display drivers +======================================= + +Up to now, the nitpicker GUI server as well as the display drivers used to +operate in a strictly periodic fashion. At a rate of 10 milliseconds, the GUI +server would route input events to the designated GUI clients and flush +graphical changes of the GUI clients to the display driver. +This simple mode of execution has benefits such as the natural ability of +batching input events and the robustness of the GUI server against overload +situations. However, in Sculpt OS, we observed that the fixed rate induces +little but constant load into an otherwise idle system, rendering +energy-saving regimes of modern CPUs less effective than they could be. +This problem would become amplified in the presence of multiple output channels +operating at independent frame rates. Moreover, with panel self-refresh +support of recent Intel graphics devices, the notion of a fixed continuous +frame rate has become antiquated. + +Hence, it was time to move to a tickless GUI-server design where the GUI +server acts as a mere broker between events triggered by applications (e.g., +pushing pixels) and drivers (e.g., occurrence of input, scanout to a display). +Depending on the behavior of its clients (GUI applications and drivers alike), +the GUI server notifies the affected parties about events of interest but +does not assert an active role. + +For example, if a display driver does not observe any changed pixels for 50 +ms, it goes to sleep. Once an application updates pixels affecting a display, +the GUI server wakes up the respective display driver, which then polls the +pixels at a driver-defined frame rate until observing when the pixels remain +static for 50 ms. Vice versa, the point in time when a display driver requests +updated pixels is reflected as a sync event to GUI applications visible on +that display, enabling such applications to synchronize their output to the +frame rate of the driver. The GUI server thereby asserts the role of steering +the sleep cycles of drivers and applications. Unless anything happens on +screen, neither the GUI server nor the display driver are active. When two +applications are visible on distinct monitors, the change of one application +does not induce any activity regarding the unrelated display. This allows for +scaling up the number of monitors without increasing the idle CPU load. + +This change implies that the former practice of using sync signals as a +time source for application-side animation timing is no longer viable. +Sync signals occur only when a driver is active after all. GUI applications +may best use sync signals for redraw scheduling but need to use a real time +source as basis for calculating the progress of animations. + + +Paving the ground for tearing-free motion +========================================= + +Tearing artifacts during animations are rightfully frowned upon. It goes +without saying that we strive to attain tearing-free motion in Genode. Two +preconditions must be met. First, the GUI server must be able to get hold +of a _consistent_ picture at any time. Second, the flushing of the picture +to the display hardware must be timed with _vsync_ of the physical display. + +Up to now, the GUI stack was unable to meet the first precondition by design. +If the picture is composed of multiple clients, the visual representation of +each client must be present in a consistent state. +The textures used as input of the compositing of the final picture are buffers +shared between server and client. Even though clients traditionally employ +double-buffering to hide intermediate drawing states, the final back-to-front +copy into the shared buffer violated the consistency of the buffer during +the client-side copy operation - when looking at the buffer from the server +side. To overcome this deficiency, we have now equipped the GUI server with +atomic blitting and panning operations, which support atomic updates in two +fashions. + +_Atomic back-to-front blitting_ allows GUI clients that partially update their +user interface - like regular application dialogs - to implement double +buffering by placing both the back buffer and front buffer within the GUI +session's shared buffer and configuring a view that shows only the front +buffer. The new blit operation ('Framebuffer::Session::blit') allows the client +to atomically flush pixels from the back buffer to the front buffer. + +_Atomic buffer flipping_ allows GUI clients that always update all pixels - +like a media player or a game - to leverage panning +('Framebuffer::Session::panning') to atomically redirect the displayed pixels to +a different portion of the GUI session's shared buffer without any copy +operation needed. The buffer contains two frames, the displayed one and the +next one. Once the next frame is complete, the client changes the panning +position to the portion containing the next frame. + +Almost all GUI clients of the Genode OS framework have been updated to use +these new facilities. + +The vsync timing as the second precondition for tearing-free motion lies in +the hands of the display driver, which can in principle capture pixel updates +from the GUI server driven by vsync interrupts. In the presence of multiple +monitors with different vsync rates, a GUI client may deliberately select +a synchronization source ('Framebuffer::Session::sync_source'). That said, +even though the interfaces are in place, vsync timing is not yet provided by +the current display drivers. + + +Mirrored and panoramic monitor setups +===================================== + +A display driver interacts with the nitpicker GUI server as a capture client. +One can think of a display driver as a screen-capturing application. +Up until now, the nitpicker GUI server handed out the same picture to each +capture client. So each client obtained a mirror of the same picture. By +subjecting each client to a policy defining a window within a larger panorama, +a driver creating one capture session per monitor becomes able to display the +larger panorama spanning the connected displays. The assignment of capture +clients to different parts of the panorama follows Genode's established +label-based policy-selection approach as explained in the +[https://github.com/genodelabs/genode/blob/master/repos/os/src/server/nitpicker/README - documentation] +of the nitpicker GUI server. + +Special care has been taken to ensure that the pointer is always visible. It +cannot be moved to any area that is not captured. Should the only capture +client displaying the pointer disappear, the pointer is warped to the center +of (any) remaining capture client. + +A mirrored monitor setup can in principle be attained by placing multiple +capture clients at the same part of nitpicker's panorama. However, there is +a better way: Our Intel display-driver component supports both discrete and +merged output channels. The driver's configuration subsumes all connectors +listed within a '' node as a single encompassing capture session at the +GUI server. The mirroring of the picture is done by the hardware. Each +connector declared outside the '' node is handled as a discrete capture +session labeled after the corresponding connector. The driver's +[https://github.com/genodelabs/genode/blob/master/repos/pc/src/driver/framebuffer/intel/pc/README - documentation] +describes the configuration in detail. + + +Sculpt OS integration +===================== + +All the changes described above are featured in the recently released +Sculpt OS version 24.10, which gives the user the ability to attain mirrored +or panoramic monitor setups or a combination thereof by the means of manual +configuration or by using interactive controls. + +[image sculpt_24_10_intel_fb] + +You can find the multi-monitor use of Sculpt OS covered by the +[https://genode.org/documentation/articles/sculpt-24-10#Multi-monitor_support - documentation]. + + +Revised inter-component interfaces +================================== + +Strict resource partitioning between GUI clients +------------------------------------------------ + +Even though Genode gives server components the opportunity to strictly operate +on client-provided resources only, the two prominent GUI servers - nitpicker +and the window manager (wm) - did not leverage these mechanisms to full +extent. In particular the wm eschewed strict resource accounting by paying out +of its own pocket. This deficiency has been rectified by the current release, +thereby making the GUI stack much more robust against potential resource +denial-of-service issues. Both the nitpicker GUI server and the window manager +now account all allocations to the resource budgets of the respective clients. +This change has the effect that GUI clients must now be equipped with the +actual cap and RAM quotas needed. + +Note that not all central parts of the GUI stack operate on client-provided +resources. In particular, a window decorator is a mere client of the window +manager despite playing a role transcending multiple applications. As the +costs needed for the decorations depend on the number of applications present +on screen, the resources of the decorator must be dimensioned with a sensible +upper bound. Fortunately, however, as the decorator is a plain client of the +window manager, it can be restarted, replaced, and upgraded without affecting +any application. + + +Structured mode information for applications +-------------------------------------------- + +Up to now, GUI clients were able to request mode information via a plain +RPC call that returned the dimensions and color depth of the display. +Multi-monitor setups call for more flexibility, which prompted us to +replace the mode information by XML-structured information delivered as +an 'info' dataspace. This is in line with how meta information is handled +in other modern session interfaces like the platform or USB sessions. +The new representation gives us room to annotate information that could +previously not be exposed to GUI clients, in particular: + +* The total panorama dimensions. +* Captured areas within the panorama, which can be used by multi-monitor + aware GUI clients as intelligence for placing GUI views. +* DPI information carried by 'width_mm' and 'height_mm' attributes. + This information is defined by the display driver and passed to the GUI + server as 'Capture::Connection::buffer' argument. +* The closed state of a window interactively closed by the user. + +Note that the window manager (wm) virtualizes the information of the nitpicker +GUI server. Instead of exposing nitpicker's panorama to its clients, the wm +reports the logical screen hosting the client's window as panorama and the +window size as a single captured rectangle within the panorama. + + +Mouse grabbing +-------------- + +Since the inception of the nitpicker GUI server, its clients observed absolute +pointer positions only. The GUI server unconditionally translated relative +mouse-motion events to absolute motion events. +To accommodate applications like games or a VM emulating a relative pointer +device, we have now extended the GUI server(s) with the ability to selectively +expose relative motion events while locking the absolute pointer position. +This is usually called pointer grabbing. It goes without saying that the user +must always retain a way to forcefully reassert control over the pointer +without the cooperation of the application. + +The solution is the enhancement of the 'Input::Session' interface by a new RPC +function that allows a client to request exclusive input. The nitpicker GUI +server grants this request if the application owns the focus. In scenarios +using the window manager (wm), the focus is always defined by the wm, which +happens to intercept all input sessions of GUI applications. Hence, the wm is +in the natural position of arbitrating the grabbing/ungrabbing of the pointer. +For each GUI client, the wm records whether the client is interested in +exclusive input but does not forward this request to nitpicker. Only if a GUI +client receives the focus and has requested exclusive input, the wm enables +exclusive input for this client at nitpicker when observing a mouse click on +the application window. Whenever the user presses the global wm key (super), +the wm forcefully releases the exclusive input at nitpicker until the user +clicks into the client window the next time. + +Furthermore, an application may enable exclusive input transiently during a +key sequence, e.g., when dragging the mouse while holding the mouse button. +Transient exclusive input is revoked as soon as the last button/key is +released. It thereby would in principle allow for GUI controls like knobs to +lock the pointer position while the user adjusts the value by moving the mouse +while the mouse button is held. So the pointer retains its original position +at the knob. + +While operating in exclusive input mode, there is no useful notion of an +absolute pointer position at the nitpicker GUI server. Hence, nitpicker hides +GUI domains that use the pointer position as coordinate origin. Thereby, the +mouse cursor automatically disappears while the pointer is grabbed. + + +Current state and ongoing work +============================== + +All the advances described above are in full effect in the recently released +version 24.10 of [https://genode.org/download/sculpt - Sculpt OS]. All +components hosted in Genode's main and world repositories have been updated +accordingly, including Genode-specific components like the widget toolkit +used by the administrative user interface of Sculpt OS, window decorators, +over Qt5 and Qt6, to SDL and SDL2. + +[image multiple_monitors] + +Current work is underway to implement multi-monitor window management and to +make multiple monitors seamlessly available to guest OSes hosted in VirtualBox. +Furthermore, the Intel display driver is currently getting equipped with the +ability to use vsync interrupts for driving the interaction with the GUI +server, taking the final step to attain tearing-free motion. + + +Device drivers and platforms +############################ + +Linux device-driver environment (DDE) +===================================== + +With our +[https://genode.org/documentation/release-notes/24.08#Linux_device-driver_environment__DDE_ - recent] +update of the DDE Linux kernel to version 6.6 for PC platforms and as a +prerequisite to support the MNT Pocket Reform, we have adapted all drivers for +the i.MX5/6/7/8 platforms to Linux kernel version 6.6.47. The list of drivers +includes Wifi, NIC, display, GPU, USB and SD-card. + + +MNT Pocket Reform +~~~~~~~~~~~~~~~~~ + +The [https://shop.mntre.com/products/mnt-pocket-reform - MNT Pocket Reform] is +a Mini Laptop by MNT aiming to be modular, upgradable, and repairable while +being assembled completely using open-source hardware. Being modular implies +that a range of CPU modules is available for the MNT Pocket. Some of these +chips, like the Rockchip based modules, are not officially supported by +Genode, yet. But there is a choice of an i.MX8MP based module available which +fits nicely into Genode's i.MX infrastructure. + +Genode already supports the MNT Reform 2 i.MX8MQ based +[https://genodians.org/skalk/2020-06-29-mnt-reform - laptop]. So an update from +MQ to MP doesn't sound like a big issue because only one letter changed, +right? It turns out that there are more changes to the platform than mere +adjustments of I/O resources and interrupt numbers. Additionally, the MNT +Reform team offers quite a large patch set for each supported Linux kernel +version. Luckily there is +[https://source.mnt.re/reform/reform-debian-packages/-/tree/main/linux/patches6.6?ref_type=heads - one] +for our just updated Linux 6.6 kernel. With this patch set, we were able to +produce a Linux source tree (imx_linux) that we now take as basis for driver +development on Genode. Note that these Linux kernel sources are shared by all +supported i.MX platforms. Of course, additional patch series were necessary to +include device-tree sources from other vendor kernels, for instance from +Compulab. + +With the development environment in place and after putting lots of effort in, +we ultimately achieved initial Genode support for the MNT Pocket Reform with +Genode 24.11. + +On the device-driver side of things, we did not have to port lots of new +drivers but were able to extend drivers already available for the i.MX8MQ +platform. In particular these drivers are for the wired network card, USB host +controller, display, and SD card. + +For the wireless network device that is found on the i.MX8MP SoM in the MNT +Pocket Reform, we needed to port a new driver. It has a Qualcomm QCA9377 +chipset and is attached via SDIO. Unfortunately the available _ath10k_ driver +in the vanilla kernel does not work properly with such a device and therefore +is also not used in the regular Linux kernel for the MNT Pocket Reform. A +slightly adapted external QCACLD2 reference driver is used instead. So we +followed suit by incorporating this particular driver in our _imx_linux_ +source tree as well. + +[image sculpt_mnt_pocket] + Sculpt OS running on the MNT Pocket Reform + +Being the initial enablement, there are still some limitations. +For example, the display of the MNT Pocket is physically +[https://mntre.com/documentation/pocket-reform-handbook.pdf - rotated] by 90 +degrees. So, we had to find a way to accommodate for that. Unfortunately, +there seems to be no hardware support other than using the GPU to perform +a fast rotation. With GPU support still missing on this system, we had to +resort to perform the rotation in software on the CPU, which is obviously +far from optimal. +Those early inefficiencies notwithstanding, Sculpt OS has become able to run +on the MNT Pocket Reform. We will provide a preview image that exercises the +available features soon. + + +Platform driver for i.MX 8M Plus +================================ + +While enabling support for the MNT Pocket Reform (Section [MNT Pocket Reform]), +it was necessary to adjust the i.MX8MP specific platform driver, which was +originally introduced in the previous +[https://genode.org/documentation/release-notes/24.08#Improvements_for_NXP_s_i.MX_family - release 24.08] +to drive the Compulab i.MX 8M Plus IOT Gateway. + +Some of the I/O pin configurations necessary to set up the SoC properly are +statically compiled into this driver because they do not change at runtime. +However, the pin configuration is specific to the actual board. Therefore, the +i.MX8MP platform driver now needs to distinguish between different boards (IOT +Gateway and MNT Pocket) by evaluating the 'platform_info' ROM provided by +core. + +Moreover, while working on different drivers, we detected a few missing clocks +that were added to the platform driver. It turned out that some clocks that we +initially turned off to save energy, have to be enabled to ensure the +liveliness of the ARM Trusted Firmware (ATF) and thereby the platform. Also, +we had to adapt the communication in between ATF and our platform driver to +control power-domains. The first version of the i.MX8MP platform driver shared +the ATF power-domains protocol with the i.MX8MQ version. However, the +power-domain enumerations of the different firmwares varies also and we +adapted that. + +Finally, the watchdog hardware is now served by the platform driver in a +recurrent way. Originally our driver used the watchdog only to implement reset +functionality. But in case of the MNT Pocket Reform, the watchdog hardware is +already armed by the bootloader. Therefore, it needs to get served in time, to +prevent the system from rebooting. As a consequence, the platform driver is +mandatory on this platform if it needs to run longer than a minute. + + +Wifi management rework +====================== + +Our management interface in the wifi driver served us well over the years +and concealed the underlying complexity of the wireless stack. At the same +time it gained some complexity itself to satisfy a variety of use-cases. +Thus, we took the past release cycle as opportunity to rework the management +layer to reduce its complexity by streamlining the interaction between +various parts, like the manager layer itself, 'wpa_supplicant' as well as +the device driver in order to provide a sound foundation for future +adaptions. +Included is also an update of the 'wpa_supplicant' to version 2.11. + +The following segments detail the changes made to the configuration options as +they were altered quite a bit to no longer mix different tasks (e.g. joining a +network and scanning for hidden networks) while removing obsolete options. + +At the top-level '' node, the following alterations were made: + +* The 'log_level' attribute was added and configures the supplicant's + verbosity. Valid values correspond to levels used by the supplicant + and are as follows: 'excessive', 'msgdump', 'debug', 'info', 'warning', + and 'error'. The default value is 'error' and configures the least + amount of verbosity. This option was introduced to ease the investigation + of connectivity issues. + +* The 'bgscan' attribute may be used to configure the way the + supplicant performs background-scanning to steer or rather optimize + roaming decision within the same network. The default value is set + to 'simple:30:-70:600'. The attribute is forwarded unmodified to the WPA + supplicant and thus provides the syntax supported by the supplicant + implementation. It can be disabled by specifying an empty value, e.g. + 'bgscan=""'. + +* The 'connected_scan_interval' attribute was removed as this functionality + is now covered by background scanning. + +* The 'verbose_state' attribute was removed altogether and similar + functionality is now covered by the 'verbose' attribute. + +The network management received the following changes: + +* Every configured network, denoted by a '' node, is now implicitly + considered an option for joining. The 'auto_connect' attribute was + removed and a '' node must be renamed or removed to deactivate + automatic connection establishment. + +* The intent to scan for a hidden network is now managed by the newly + introduced '' node that like the '' node has + an 'ssid' attribute. If the specified SSID is valid, it is incorporated + into the scan request to actively probe for this network. As the node + requests explicit scanning only, a corresponding '' node is + required to actually connect to the hidden network. + The 'explicit_scan' attribute of the '' node has been removed. + +The following exemplary configuration shows how to configure the driver +for attempting to join two different networks where one of them is hidden. +The initial scan interval is set 10 seconds and the signal quality will be +updated every 30 seconds while connected to a network. + +! +! +! +! +! + +For more information please consult the driver's +[https://github.com/genodelabs/genode/blob/master/repos/dde_linux/src/driver/wifi/README - documentation] +that now features a best-practices section explaining how the driver should be +operated at best, and highlights the difference between a managed (as used in +Sculpt OS) and a user-generated configuration. + + +Audio driver updated to OpenBSD 7.6 +=================================== + +With this release, we updated our OpenBSD-based audio driver to a more recent +revision that correlates to version 7.6. It supports newer devices, e.g. Alder +Lake-N, and includes a fix for using message-signaled interrupts (MSI) with +HDA devices as found in AMD-based systems. + + +AVX and hardware-based AES in virtual machines +============================================== + +The current release adds support for requesting and transferring the AVX FPU +state via Genode's VM-session interface. With this prerequisite fulfilled, we +enabled the announcement of the AVX feature to guest VMs in our port of +VirtualBox6. + +Additionally, we enabled the announcement of AES and RDRAND CPU features to +guest VMs to further improve the utilization of the hardware. + + +Build system and tools +###################### + +Extended depot-tool safeguards +------------------------------ + +When using the run tool's '--depot-auto-update' feature while switching +between different git topic branches with committed recipe hashes, a binary +archive present in the depot may accidentally not match its ingredients +because the depot/build tool's 'REBUILD=' mode - as used by the depot +auto-update mechanism - merely looks at the archive versions. This situation +is arguably rare. But when it occurs, its reach and effects are hard to +predict. To rule out this corner case early, the depot/build tool has now been +extended by recording the hashes of the ingredients of binary archives. When +skipping a rebuild because the desired version presumably already exists as a +binary archive, the recorded hashes are compared to the current state of the +ingredients (src and api archives). Thereby inconsistencies are promptly +reported to the user. + +Users of the depot tool will notice .hash files appearing alongside src and +api archives. Those files contain the hash value of the content of the +respective archive. Each binary archive built is now also accompanied by +a .hash file, which contains a list of hash values of the ingredients that went +into the binary archive. Thanks to these .hash files, the consistency between +binaries and their ingredients can be checked quickly. + +_As a note of caution, when switching to the Genode 24.11 with existing depot,_ +_one will possibly need to remove existing depot archives (as listed by the_ +_diagnostic messages) because the existing archives are not accompanied by_ +_.hash files yet._ diff --git a/repos/base-fiasco/recipes/src/base-fiasco/hash b/repos/base-fiasco/recipes/src/base-fiasco/hash index f8029e84b9..7b847c95e6 100644 --- a/repos/base-fiasco/recipes/src/base-fiasco/hash +++ b/repos/base-fiasco/recipes/src/base-fiasco/hash @@ -1 +1 @@ -2024-08-28 8f1db0e604a283f5d3aafea61d38d6852ee91911 +2024-12-10 408b474f632eefaaa19db35812a9aa94a48e6bdb diff --git a/repos/base-fiasco/src/core/include/platform_thread.h b/repos/base-fiasco/src/core/include/platform_thread.h index 0d753a7fe0..aabf222984 100644 --- a/repos/base-fiasco/src/core/include/platform_thread.h +++ b/repos/base-fiasco/src/core/include/platform_thread.h @@ -61,8 +61,9 @@ class Core::Platform_thread : Interface /** * Constructor */ - Platform_thread(Platform_pd &pd, size_t, const char *name, - unsigned, Affinity::Location, addr_t) + Platform_thread(Platform_pd &pd, Rpc_entrypoint &, Ram_allocator &, + Region_map &, size_t, const char *name, unsigned, + Affinity::Location, addr_t) : _name(name), _pd(pd) { } /** diff --git a/repos/base-fiasco/src/core/io_mem_session_support.cc b/repos/base-fiasco/src/core/io_mem_session_support.cc index 55bcfab142..e55aa04ae3 100644 --- a/repos/base-fiasco/src/core/io_mem_session_support.cc +++ b/repos/base-fiasco/src/core/io_mem_session_support.cc @@ -38,8 +38,11 @@ static inline bool can_use_super_page(addr_t, size_t) } -addr_t Io_mem_session_component::_map_local(addr_t phys_base, size_t size) +Io_mem_session_component::Map_local_result Io_mem_session_component::_map_local(addr_t const phys_base, + size_t const size_in) { + size_t const size = size_in; + auto map_io_region = [] (addr_t phys_base, addr_t local_base, size_t size) { using namespace Fiasco; @@ -91,14 +94,16 @@ addr_t Io_mem_session_component::_map_local(addr_t phys_base, size_t size) size_t align = (size >= get_super_page_size()) ? get_super_page_size_log2() : get_page_size_log2(); - return platform().region_alloc().alloc_aligned(size, align).convert( + return platform().region_alloc().alloc_aligned(size, align).convert( [&] (void *ptr) { addr_t const core_local_base = (addr_t)ptr; map_io_region(phys_base, core_local_base, size); - return core_local_base; }, + return Map_local_result { .core_local_addr = core_local_base, .success = true }; + }, - [&] (Range_allocator::Alloc_error) -> addr_t { + [&] (Range_allocator::Alloc_error) { error("core-local mapping of memory-mapped I/O range failed"); - return 0; }); + return Map_local_result(); + }); } diff --git a/repos/base-fiasco/src/core/pager.cc b/repos/base-fiasco/src/core/pager.cc index e6c1d9257f..cba6f257af 100644 --- a/repos/base-fiasco/src/core/pager.cc +++ b/repos/base-fiasco/src/core/pager.cc @@ -103,3 +103,6 @@ Untyped_capability Pager_entrypoint::_pager_object_cap(unsigned long badge) { return Capability_space::import(native_thread().l4id, Rpc_obj_key(badge)); } + + +void Core::init_page_fault_handling(Rpc_entrypoint &) { } diff --git a/repos/base-fiasco/src/core/thread_start.cc b/repos/base-fiasco/src/core/thread_start.cc index 48871704ac..53b4302d94 100644 --- a/repos/base-fiasco/src/core/thread_start.cc +++ b/repos/base-fiasco/src/core/thread_start.cc @@ -20,7 +20,6 @@ /* core includes */ #include -#include using namespace Core; diff --git a/repos/base-foc/include/foc/thread_state.h b/repos/base-foc/include/foc/thread_state.h index 19d25d1723..b1b7a7be25 100644 --- a/repos/base-foc/include/foc/thread_state.h +++ b/repos/base-foc/include/foc/thread_state.h @@ -26,7 +26,7 @@ namespace Genode { struct Foc_thread_state; } struct Genode::Foc_thread_state : Thread_state { Foc::l4_cap_idx_t kcap { Foc::L4_INVALID_CAP }; /* thread's gate cap in its PD */ - uint16_t id { }; /* ID of gate capability */ + uint32_t id { }; /* ID of gate capability */ addr_t utcb { }; /* thread's UTCB in its PD */ }; diff --git a/repos/base-foc/recipes/src/base-foc-imx6q_sabrelite/hash b/repos/base-foc/recipes/src/base-foc-imx6q_sabrelite/hash index 9c6fbc231c..ef89a5e1a5 100644 --- a/repos/base-foc/recipes/src/base-foc-imx6q_sabrelite/hash +++ b/repos/base-foc/recipes/src/base-foc-imx6q_sabrelite/hash @@ -1 +1 @@ -2024-08-28 deb70ebec813a19ba26a28cd94fa7d25bbe52e78 +2024-12-10 4247239f4d3ce9a840be368ac9e054e8064c01c6 diff --git a/repos/base-foc/recipes/src/base-foc-imx7d_sabre/hash b/repos/base-foc/recipes/src/base-foc-imx7d_sabre/hash index 121f52746c..fba642577e 100644 --- a/repos/base-foc/recipes/src/base-foc-imx7d_sabre/hash +++ b/repos/base-foc/recipes/src/base-foc-imx7d_sabre/hash @@ -1 +1 @@ -2024-08-28 a4ae12d703c38248ac22905163479000020e0bb0 +2024-12-10 39609d3553422b8c7c6acff2db845c67c5f8912b diff --git a/repos/base-foc/recipes/src/base-foc-pbxa9/hash b/repos/base-foc/recipes/src/base-foc-pbxa9/hash index cb9030ecd7..3e12c37bf0 100644 --- a/repos/base-foc/recipes/src/base-foc-pbxa9/hash +++ b/repos/base-foc/recipes/src/base-foc-pbxa9/hash @@ -1 +1 @@ -2024-08-28 4c4d4d5d96bc345947e90c42559e45fec4dcc4c0 +2024-12-10 7867db59531dc9086e76b74800125ee61ccc310e diff --git a/repos/base-foc/recipes/src/base-foc-pc/hash b/repos/base-foc/recipes/src/base-foc-pc/hash index 837cb151a0..1cbe570570 100644 --- a/repos/base-foc/recipes/src/base-foc-pc/hash +++ b/repos/base-foc/recipes/src/base-foc-pc/hash @@ -1 +1 @@ -2024-08-28 b0160be55c422f860753dbd375f04ff8f7ffc7e9 +2024-12-10 3fc7c1b2cae2b9af835c97bf384b10411ec9c511 diff --git a/repos/base-foc/recipes/src/base-foc-rpi3/hash b/repos/base-foc/recipes/src/base-foc-rpi3/hash index 0843a59f28..ae24ab1091 100644 --- a/repos/base-foc/recipes/src/base-foc-rpi3/hash +++ b/repos/base-foc/recipes/src/base-foc-rpi3/hash @@ -1 +1 @@ -2024-08-28 3e92e9cf1ec41d5de0bfa754ff48c63476e60d67 +2024-12-10 68ee5bc5640e1d32c33f46072256d5b1c71bef9b diff --git a/repos/base-foc/src/core/include/cap_id_alloc.h b/repos/base-foc/src/core/include/cap_id_alloc.h index 39c34ca571..6cbeaed546 100644 --- a/repos/base-foc/src/core/include/cap_id_alloc.h +++ b/repos/base-foc/src/core/include/cap_id_alloc.h @@ -30,17 +30,15 @@ class Core::Cap_id_allocator { public: - using id_t = uint16_t; - - enum { ID_MASK = 0xffff }; + using id_t = unsigned; private: enum { - CAP_ID_RANGE = ~0UL, - CAP_ID_MASK = ~3UL, - CAP_ID_NUM_MAX = CAP_ID_MASK >> 2, - CAP_ID_OFFSET = 1 << 2 + CAP_ID_OFFSET = 1 << 2, + CAP_ID_MASK = CAP_ID_OFFSET - 1, + CAP_ID_RANGE = 1u << 28, + ID_MASK = CAP_ID_RANGE - 1, }; Synced_range_allocator _id_alloc; diff --git a/repos/base-foc/src/core/include/platform_thread.h b/repos/base-foc/src/core/include/platform_thread.h index 4d2d94dfd6..e2b2d681e5 100644 --- a/repos/base-foc/src/core/include/platform_thread.h +++ b/repos/base-foc/src/core/include/platform_thread.h @@ -75,8 +75,8 @@ class Core::Platform_thread : Interface /** * Constructor for non-core threads */ - Platform_thread(Platform_pd &, size_t, const char *name, unsigned priority, - Affinity::Location, addr_t); + Platform_thread(Platform_pd &, Rpc_entrypoint &, Ram_allocator &, Region_map &, + size_t, const char *name, unsigned priority, Affinity::Location, addr_t); /** * Constructor for core main-thread diff --git a/repos/base-foc/src/core/include/vm_session_component.h b/repos/base-foc/src/core/include/vm_session_component.h index 17c3a1f01e..15c8de65c8 100644 --- a/repos/base-foc/src/core/include/vm_session_component.h +++ b/repos/base-foc/src/core/include/vm_session_component.h @@ -125,7 +125,7 @@ class Core::Vm_session_component ** Vm session interface ** **************************/ - Capability create_vcpu(Thread_capability); + Capability create_vcpu(Thread_capability) override; void attach_pic(addr_t) override { /* unused on Fiasco.OC */ } void attach(Dataspace_capability, addr_t, Attach_attr) override; /* vm_session_common.cc */ diff --git a/repos/base-foc/src/core/io_mem_session_support.cc b/repos/base-foc/src/core/io_mem_session_support.cc index b7fdaea88d..778ffb7e69 100644 --- a/repos/base-foc/src/core/io_mem_session_support.cc +++ b/repos/base-foc/src/core/io_mem_session_support.cc @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2006-2017 Genode Labs GmbH + * Copyright (C) 2006-2024 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -21,31 +21,37 @@ using namespace Core; -void Io_mem_session_component::_unmap_local(addr_t base, size_t, addr_t) +void Io_mem_session_component::_unmap_local(addr_t base, size_t size, addr_t) { + if (!base) + return; + + unmap_local(base, size >> 12); platform().region_alloc().free(reinterpret_cast(base)); } -addr_t Io_mem_session_component::_map_local(addr_t base, size_t size) +Io_mem_session_component::Map_local_result Io_mem_session_component::_map_local(addr_t const base, + size_t const size) { /* align large I/O dataspaces on a super-page boundary within core */ size_t alignment = (size >= get_super_page_size()) ? get_super_page_size_log2() : get_page_size_log2(); - /* find appropriate region for mapping */ - return platform().region_alloc().alloc_aligned(size, (unsigned)alignment).convert( + /* find appropriate region and map it locally */ + return platform().region_alloc().alloc_aligned(size, (unsigned)alignment).convert( [&] (void *local_base) { if (!map_local_io(base, (addr_t)local_base, size >> get_page_size_log2())) { - error("map_local_io failed"); + error("map_local_io failed ", Hex_range(base, size)); platform().region_alloc().free(local_base, base); - return 0UL; + return Map_local_result(); } - return (addr_t)local_base; + return Map_local_result { .core_local_addr = addr_t(local_base), + .success = true }; }, [&] (Range_allocator::Alloc_error) { error("allocation of virtual memory for local I/O mapping failed"); - return 0UL; }); + return Map_local_result(); }); } diff --git a/repos/base-foc/src/core/pager.cc b/repos/base-foc/src/core/pager.cc index 891967266d..102df00cb3 100644 --- a/repos/base-foc/src/core/pager.cc +++ b/repos/base-foc/src/core/pager.cc @@ -153,3 +153,6 @@ Pager_capability Pager_entrypoint::manage(Pager_object &obj) }, [&] (Cpu_session::Create_thread_error) { return Pager_capability(); }); } + + +void Core::init_page_fault_handling(Rpc_entrypoint &) { } diff --git a/repos/base-foc/src/core/platform.cc b/repos/base-foc/src/core/platform.cc index 15f4ed5779..e56a0135e9 100644 --- a/repos/base-foc/src/core/platform.cc +++ b/repos/base-foc/src/core/platform.cc @@ -18,6 +18,7 @@ #include #include #include +#include #include /* base-internal includes */ @@ -342,6 +343,76 @@ void Core::Platform::_setup_irq_alloc() } +struct Acpi_rsdp : public Genode::Mmio<32> +{ + using Mmio<32>::Mmio; + + struct Signature : Register< 0, 64> { }; + struct Revision : Register<15, 8> { }; + struct Rsdt : Register<16, 32> { }; + struct Length : Register<20, 32> { }; + struct Xsdt : Register<24, 64> { }; + + bool valid() const + { + const char sign[] = "RSD PTR "; + return read() == *(Genode::uint64_t *)sign; + } + +} __attribute__((packed)); + + +static void add_acpi_rsdp(auto ®ion_alloc, auto &xml) +{ + using namespace Foc; + using Foc::L4::Kip::Mem_desc; + + l4_kernel_info_t const &kip = sigma0_map_kip(); + Mem_desc const * const desc = Mem_desc::first(&kip); + + if (!desc) + return; + + for (unsigned i = 0; i < Mem_desc::count(&kip); ++i) { + if (desc[i].type() != Mem_desc::Mem_type::Info || + desc[i].sub_type() != Mem_desc::Info_sub_type::Info_acpi_rsdp) + continue; + + auto offset = desc[i].start() & 0xffful; + auto pages = align_addr(offset + desc[i].size(), 12) >> 12; + + region_alloc.alloc_aligned(pages * 4096, 12).with_result([&] (void *core_local_ptr) { + + if (!map_local_io(desc[i].start(), (addr_t)core_local_ptr, pages)) + return; + + Byte_range_ptr const ptr((char *)(addr_t(core_local_ptr) + offset), + pages * 4096 - offset); + auto const rsdp = Acpi_rsdp(ptr); + + if (!rsdp.valid()) + return; + + xml.node("acpi", [&] { + xml.attribute("revision", rsdp.read()); + if (rsdp.read()) + xml.attribute("rsdt", String<32>(Hex(rsdp.read()))); + if (rsdp.read()) + xml.attribute("xsdt", String<32>(Hex(rsdp.read()))); + }); + + unmap_local(addr_t(core_local_ptr), pages); + region_alloc.free(core_local_ptr); + + pages = 0; + }, [&] (Range_allocator::Alloc_error) { }); + + if (!pages) + return; + } +} + + void Core::Platform::_setup_basics() { using namespace Foc; @@ -412,6 +483,10 @@ void Core::Platform::_setup_basics() /* image is accessible by core */ add_region(Region(img_start, img_end), _core_address_ranges()); + + /* requested as I/O memory by the VESA driver and ACPI (rsdp search) */ + _io_mem_alloc.add_range (0, 0x2000); + ram_alloc() .remove_range(0, 0x2000); } @@ -517,7 +592,10 @@ Core::Platform::Platform() xml.node("affinity-space", [&] { xml.attribute("width", affinity_space().width()); - xml.attribute("height", affinity_space().height()); }); + xml.attribute("height", affinity_space().height()); + }); + + add_acpi_rsdp(region_alloc(), xml); }); } ); diff --git a/repos/base-foc/src/core/platform_thread.cc b/repos/base-foc/src/core/platform_thread.cc index d24ace8782..378f232671 100644 --- a/repos/base-foc/src/core/platform_thread.cc +++ b/repos/base-foc/src/core/platform_thread.cc @@ -18,7 +18,6 @@ /* core includes */ #include #include -#include /* Fiasco.OC includes */ #include @@ -210,7 +209,7 @@ Foc_thread_state Platform_thread::state() s = _pager_obj->state.state; s.kcap = _gate.remote; - s.id = (uint16_t)_gate.local.local_name(); + s.id = Cap_index::id_t(_gate.local.local_name()); s.utcb = _utcb; return s; @@ -278,7 +277,8 @@ void Platform_thread::_finalize_construction() } -Platform_thread::Platform_thread(Platform_pd &pd, size_t, const char *name, unsigned prio, +Platform_thread::Platform_thread(Platform_pd &pd, Rpc_entrypoint &, Ram_allocator &, + Region_map &, size_t, const char *name, unsigned prio, Affinity::Location location, addr_t) : _name(name), diff --git a/repos/base-foc/src/core/rpc_cap_factory.cc b/repos/base-foc/src/core/rpc_cap_factory.cc index fa0c2ea5a0..caf7a226a9 100644 --- a/repos/base-foc/src/core/rpc_cap_factory.cc +++ b/repos/base-foc/src/core/rpc_cap_factory.cc @@ -38,7 +38,7 @@ using namespace Core; Cap_index_allocator &Genode::cap_idx_alloc() { - static Cap_index_allocator_tpl alloc; + static Cap_index_allocator_tpl alloc; return alloc; } @@ -190,7 +190,7 @@ Cap_id_allocator::Cap_id_allocator(Allocator &alloc) : _id_alloc(&alloc) { - _id_alloc.add_range(CAP_ID_OFFSET, CAP_ID_RANGE); + _id_alloc.add_range(CAP_ID_OFFSET, unsigned(CAP_ID_RANGE) - unsigned(CAP_ID_OFFSET)); } @@ -213,7 +213,7 @@ void Cap_id_allocator::free(id_t id) Mutex::Guard lock_guard(_mutex); if (id < CAP_ID_RANGE) - _id_alloc.free((void*)(id & CAP_ID_MASK), CAP_ID_OFFSET); + _id_alloc.free((void*)(addr_t(id & CAP_ID_MASK)), CAP_ID_OFFSET); } diff --git a/repos/base-foc/src/core/spec/x86/platform_services.cc b/repos/base-foc/src/core/spec/x86/platform_services.cc index 8e4888c65a..051c42bc31 100644 --- a/repos/base-foc/src/core/spec/x86/platform_services.cc +++ b/repos/base-foc/src/core/spec/x86/platform_services.cc @@ -12,7 +12,6 @@ */ /* core includes */ -#include #include #include #include @@ -23,15 +22,16 @@ void Core::platform_add_local_services(Rpc_entrypoint &ep, Sliced_heap &heap, Registry &services, - Trace::Source_registry &trace_sources) + Trace::Source_registry &trace_sources, + Ram_allocator &core_ram, + Region_map &core_rm, + Range_allocator &io_port_ranges) { - static Vm_root vm_root(ep, heap, core_env().ram_allocator(), - core_env().local_rm(), trace_sources); + static Vm_root vm_root(ep, heap, core_ram, core_rm, trace_sources); static Core_service vm(services, vm_root); - static Io_port_root io_root(*core_env().pd_session(), - platform().io_port_alloc(), heap); + static Io_port_root io_root(io_port_ranges, heap); static Core_service io_port(services, io_root); } diff --git a/repos/base-foc/src/core/thread_start.cc b/repos/base-foc/src/core/thread_start.cc index 98f731f670..48a8d7afa5 100644 --- a/repos/base-foc/src/core/thread_start.cc +++ b/repos/base-foc/src/core/thread_start.cc @@ -22,7 +22,6 @@ /* core includes */ #include -#include /* Fiasco.OC includes */ #include diff --git a/repos/base-foc/src/include/base/internal/capability_data.h b/repos/base-foc/src/include/base/internal/capability_data.h index 2f083cf190..8c8481192a 100644 --- a/repos/base-foc/src/include/base/internal/capability_data.h +++ b/repos/base-foc/src/include/base/internal/capability_data.h @@ -30,12 +30,13 @@ class Genode::Native_capability::Data : public Avl_node { public: - using id_t = uint16_t; + using id_t = unsigned; + + constexpr static id_t INVALID_ID = ~0u; private: - constexpr static uint16_t INVALID_ID = ~0; - constexpr static uint16_t UNUSED = 0; + constexpr static id_t UNUSED = 0; uint8_t _ref_cnt; /* reference counter */ id_t _id; /* global capability id */ @@ -46,8 +47,8 @@ class Genode::Native_capability::Data : public Avl_node bool valid() const { return _id != INVALID_ID; } bool used() const { return _id != UNUSED; } - uint16_t id() const { return _id; } - void id(uint16_t id) { _id = id; } + id_t id() const { return _id; } + void id(id_t id) { _id = id; } uint8_t inc(); uint8_t dec(); addr_t kcap() const; diff --git a/repos/base-foc/src/lib/base/cap_map.cc b/repos/base-foc/src/lib/base/cap_map.cc index f97b45766a..f076a9d5c5 100644 --- a/repos/base-foc/src/lib/base/cap_map.cc +++ b/repos/base-foc/src/lib/base/cap_map.cc @@ -3,11 +3,11 @@ * \author Stefan Kalkowski * \date 2010-12-06 * - * This is a Fiasco.OC-specific addition to the process enviroment. + * This is a Fiasco.OC-specific addition to the process environment. */ /* - * Copyright (C) 2010-2017 Genode Labs GmbH + * Copyright (C) 2010-2025 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. @@ -59,7 +59,7 @@ static volatile int _cap_index_spinlock = SPINLOCK_UNLOCKED; bool Cap_index::higher(Cap_index *n) { return n->_id > _id; } -Cap_index* Cap_index::find_by_id(uint16_t id) +Cap_index* Cap_index::find_by_id(id_t id) { if (_id == id) return this; @@ -116,8 +116,8 @@ Cap_index* Capability_map::insert(Cap_index::id_t id) { Spin_lock::Guard guard(_lock); - ASSERT(!_tree.first() || !_tree.first()->find_by_id(id), - "Double insertion in cap_map()!"); + if (_tree.first() && _tree.first()->find_by_id(id)) + return { }; Cap_index * const i = cap_idx_alloc().alloc_range(1); if (i) { @@ -184,9 +184,16 @@ Cap_index* Capability_map::insert_map(Cap_index::id_t id, addr_t kcap) _tree.insert(i); /* map the given cap to our registry entry */ - l4_task_map(L4_BASE_TASK_CAP, L4_BASE_TASK_CAP, - l4_obj_fpage(kcap, 0, L4_FPAGE_RWX), - i->kcap() | L4_ITEM_MAP | L4_MAP_ITEM_GRANT); + auto const msg = l4_task_map(L4_BASE_TASK_CAP, L4_BASE_TASK_CAP, + l4_obj_fpage(kcap, 0, L4_FPAGE_RWX), + i->kcap() | L4_ITEM_MAP | L4_MAP_ITEM_GRANT); + + if (l4_error(msg)) { + _tree.remove(i); + cap_idx_alloc().free(i, 1); + return 0; + } + return i; } diff --git a/repos/base-foc/src/lib/base/ipc.cc b/repos/base-foc/src/lib/base/ipc.cc index 1b6985d9c6..f096586385 100644 --- a/repos/base-foc/src/lib/base/ipc.cc +++ b/repos/base-foc/src/lib/base/ipc.cc @@ -55,9 +55,6 @@ static inline bool ipc_error(l4_msgtag_t tag, bool print) } -static constexpr Cap_index::id_t INVALID_BADGE = 0xffff; - - /** * Representation of a capability during UTCB marshalling/unmarshalling */ @@ -116,7 +113,7 @@ static int extract_msg_from_utcb(l4_msgtag_t tag, Cap_index::id_t const badge = (Cap_index::id_t)(*msg_words++); - if (badge == INVALID_BADGE) + if (badge == Cap_index::INVALID_ID) continue; /* received a delegated capability */ @@ -227,7 +224,7 @@ static l4_msgtag_t copy_msgbuf_to_utcb(Msgbuf_base &snd_msg, for (unsigned i = 0; i < num_caps; i++) { /* store badge as normal message word */ - *msg_words++ = caps[i].valid ? caps[i].badge : INVALID_BADGE; + *msg_words++ = caps[i].valid ? caps[i].badge : Cap_index::INVALID_ID; /* setup flexpage for valid capability to delegate */ if (caps[i].valid) { diff --git a/repos/base-foc/src/lib/base/x86/vm.cc b/repos/base-foc/src/lib/base/x86/vm.cc index 58f3d94c86..9d9685a94d 100644 --- a/repos/base-foc/src/lib/base/x86/vm.cc +++ b/repos/base-foc/src/lib/base/x86/vm.cc @@ -42,7 +42,6 @@ namespace Foc { using namespace Genode; using Exit_config = Vm_connection::Exit_config; -using Call_with_state = Vm_connection::Call_with_state; enum Virt { VMX, SVM, UNKNOWN }; @@ -72,8 +71,7 @@ struct Foc_native_vcpu_rpc : Rpc_client, Noncopyable Capability _create_vcpu(Vm_connection &vm, Thread_capability &cap) { - return vm.with_upgrade([&] { - return vm.call(cap); }); + return vm.create_vcpu(cap); } public: @@ -400,6 +398,7 @@ struct Foc_vcpu : Thread, Noncopyable if (state.fpu.charged()) { state.fpu.charge([&] (Vcpu_state::Fpu::State &fpu) { asm volatile ("fxrstor %0" : : "m" (fpu) : "memory"); + return 512; }); } else asm volatile ("fxrstor %0" : : "m" (_fpu_vcpu) : "memory"); @@ -412,6 +411,7 @@ struct Foc_vcpu : Thread, Noncopyable state.fpu.charge([&] (Vcpu_state::Fpu::State &fpu) { asm volatile ("fxsave %0" : "=m" (fpu) :: "memory"); asm volatile ("fxsave %0" : "=m" (_fpu_vcpu) :: "memory"); + return 512; }); asm volatile ("fxrstor %0" : : "m" (_fpu_ep) : "memory"); @@ -1340,7 +1340,7 @@ struct Foc_vcpu : Thread, Noncopyable _wake_up.up(); } - void with_state(Call_with_state &cw) + void with_state(auto const &fn) { if (!_dispatching) { if (Thread::myself() != _ep_handler) { @@ -1373,7 +1373,7 @@ struct Foc_vcpu : Thread, Noncopyable _state_ready.down(); } - if (cw.call_with_state(_vcpu_state) + if (fn(_vcpu_state) || _extra_dispatch_up) resume(); @@ -1415,7 +1415,10 @@ static enum Virt virt_type(Env &env) ** vCPU API ** **************/ -void Vm_connection::Vcpu::_with_state(Call_with_state &cw) { static_cast(_native_vcpu).vcpu.with_state(cw); } +void Vm_connection::Vcpu::_with_state(With_state::Ft const &fn) +{ + static_cast(_native_vcpu).vcpu.with_state(fn); +} Vm_connection::Vcpu::Vcpu(Vm_connection &vm, Allocator &alloc, diff --git a/repos/base-hw/include/kernel/interface.h b/repos/base-hw/include/kernel/interface.h index 0925f0c6dc..0bef5bffa8 100644 --- a/repos/base-hw/include/kernel/interface.h +++ b/repos/base-hw/include/kernel/interface.h @@ -382,13 +382,10 @@ namespace Kernel { * Halt processing of a signal context synchronously * * \param context capability ID of the targeted signal context - * - * \retval 0 suceeded - * \retval -1 failed */ - inline int kill_signal_context(capid_t const context) + inline void kill_signal_context(capid_t const context) { - return (int)call(call_id_kill_signal_context(), context); + call(call_id_kill_signal_context(), context); } /** diff --git a/repos/base-hw/src/core/spec/x86_64/port_io.h b/repos/base-hw/include/spec/x86_64/port_io.h similarity index 72% rename from repos/base-hw/src/core/spec/x86_64/port_io.h rename to repos/base-hw/include/spec/x86_64/port_io.h index ebfcf2095c..5075448a14 100644 --- a/repos/base-hw/src/core/spec/x86_64/port_io.h +++ b/repos/base-hw/include/spec/x86_64/port_io.h @@ -11,13 +11,15 @@ * under the terms of the GNU Affero General Public License version 3. */ -#ifndef _CORE__SPEC__X86_64__PORT_IO_H_ -#define _CORE__SPEC__X86_64__PORT_IO_H_ +#ifndef _INCLUDE__SPEC__X86_64__PORT_IO_H_ +#define _INCLUDE__SPEC__X86_64__PORT_IO_H_ -/* core includes */ -#include +#include -namespace Core { +namespace Hw { + + using Genode::uint8_t; + using Genode::uint16_t; /** * Read byte from I/O port @@ -38,4 +40,4 @@ namespace Core { } } -#endif /* _CORE__SPEC__X86_64__PORT_IO_H_ */ +#endif /* _INCLUDE__SPEC__X86_64__PORT_IO_H_ */ diff --git a/repos/base-hw/lib/mk/core-hw.inc b/repos/base-hw/lib/mk/core-hw.inc index 5ff6634311..832c4de40d 100644 --- a/repos/base-hw/lib/mk/core-hw.inc +++ b/repos/base-hw/lib/mk/core-hw.inc @@ -46,7 +46,6 @@ SRC_CC += ram_dataspace_factory.cc SRC_CC += signal_transmitter_noinit.cc SRC_CC += thread_start.cc SRC_CC += env.cc -SRC_CC += region_map_support.cc SRC_CC += pager.cc SRC_CC += _main.cc SRC_CC += kernel/cpu.cc @@ -55,13 +54,16 @@ SRC_CC += kernel/ipc_node.cc SRC_CC += kernel/irq.cc SRC_CC += kernel/main.cc SRC_CC += kernel/object.cc -SRC_CC += kernel/signal_receiver.cc +SRC_CC += kernel/signal.cc SRC_CC += kernel/thread.cc SRC_CC += kernel/timer.cc SRC_CC += capability.cc SRC_CC += stack_area_addr.cc SRC_CC += heartbeat.cc +BOARD ?= unknown +CC_OPT_platform += -DBOARD_NAME="\"$(BOARD)\"" + # provide Genode version information include $(BASE_DIR)/src/core/version.inc diff --git a/repos/base-hw/lib/mk/spec/x86_64/core-hw-pc.mk b/repos/base-hw/lib/mk/spec/x86_64/core-hw-pc.mk index 872990a6c4..ab6f733f84 100644 --- a/repos/base-hw/lib/mk/spec/x86_64/core-hw-pc.mk +++ b/repos/base-hw/lib/mk/spec/x86_64/core-hw-pc.mk @@ -22,12 +22,9 @@ SRC_CC += kernel/vm_thread_on.cc SRC_CC += spec/x86_64/virtualization/kernel/vm.cc SRC_CC += spec/x86_64/virtualization/kernel/svm.cc SRC_CC += spec/x86_64/virtualization/kernel/vmx.cc -SRC_CC += spec/x86_64/virtualization/vm_session_component.cc -SRC_CC += vm_session_common.cc -SRC_CC += vm_session_component.cc SRC_CC += kernel/lock.cc SRC_CC += spec/x86_64/pic.cc -SRC_CC += spec/x86_64/pit.cc +SRC_CC += spec/x86_64/timer.cc SRC_CC += spec/x86_64/kernel/thread_exception.cc SRC_CC += spec/x86_64/platform_support.cc SRC_CC += spec/x86_64/virtualization/platform_services.cc diff --git a/repos/base-hw/recipes/src/base-hw-pbxa9/hash b/repos/base-hw/recipes/src/base-hw-pbxa9/hash index b5ccec7f13..42afb46388 100644 --- a/repos/base-hw/recipes/src/base-hw-pbxa9/hash +++ b/repos/base-hw/recipes/src/base-hw-pbxa9/hash @@ -1 +1 @@ -2024-08-28 de31628804f8541b6c0cf5a43ed621432befd5cb +2024-12-10 ca4eabba0cf0313545712015ae6e9ebb4d968b2a diff --git a/repos/base-hw/recipes/src/base-hw-pc/hash b/repos/base-hw/recipes/src/base-hw-pc/hash index 8f549a54cd..0e8a145703 100644 --- a/repos/base-hw/recipes/src/base-hw-pc/hash +++ b/repos/base-hw/recipes/src/base-hw-pc/hash @@ -1 +1 @@ -2024-11-08-j 84d5a44cde007081915979748933030b05113be5 +2024-12-10 dad50ef2ab70aa5a7bd316ad116bfb1d59c5df5c diff --git a/repos/base-hw/recipes/src/base-hw-virt_qemu_arm_v7a/hash b/repos/base-hw/recipes/src/base-hw-virt_qemu_arm_v7a/hash index bcd440379c..5c22b9792a 100644 --- a/repos/base-hw/recipes/src/base-hw-virt_qemu_arm_v7a/hash +++ b/repos/base-hw/recipes/src/base-hw-virt_qemu_arm_v7a/hash @@ -1 +1 @@ -2024-08-28 73ea0cda27023fee8a56c5c104f85875e0ce2597 +2024-12-10 58d8cb90d04a52f53a9797d964568dc0d1e7c45d diff --git a/repos/base-hw/recipes/src/base-hw-virt_qemu_arm_v8a/hash b/repos/base-hw/recipes/src/base-hw-virt_qemu_arm_v8a/hash index 36f1d2dd44..5968b234b6 100644 --- a/repos/base-hw/recipes/src/base-hw-virt_qemu_arm_v8a/hash +++ b/repos/base-hw/recipes/src/base-hw-virt_qemu_arm_v8a/hash @@ -1 +1 @@ -2024-08-28 268365a21014538c4524a43c86f1e4b1b9709a96 +2024-12-10 1a5d21d207bb12797d285e1c3173cdaec7559afe diff --git a/repos/base-hw/recipes/src/base-hw_content.inc b/repos/base-hw/recipes/src/base-hw_content.inc index 17240b4489..74b6f28336 100644 --- a/repos/base-hw/recipes/src/base-hw_content.inc +++ b/repos/base-hw/recipes/src/base-hw_content.inc @@ -200,6 +200,7 @@ generalize_target_names: $(CONTENT) # 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/bootstrap/hw/target.mk + sed -i "s/\?= unknown/:= $(BOARD)/" lib/mk/core-hw.inc # discharge targets when building for mismatching architecture sed -i "1aREQUIRES := $(ARCH)" src/core/hw/target.mk sed -i "1aREQUIRES := $(ARCH)" src/bootstrap/hw/target.mk diff --git a/repos/base-hw/src/bootstrap/init.cc b/repos/base-hw/src/bootstrap/init.cc index 9fcda2fec3..e29fe4b91b 100644 --- a/repos/base-hw/src/bootstrap/init.cc +++ b/repos/base-hw/src/bootstrap/init.cc @@ -16,7 +16,6 @@ /* base includes */ #include -#include using namespace Genode; @@ -26,13 +25,23 @@ size_t bootstrap_stack_size = STACK_SIZE; uint8_t bootstrap_stack[Board::NR_OF_CPUS][STACK_SIZE] __attribute__((aligned(get_page_size()))); -Bootstrap::Platform & Bootstrap::platform() { - return *unmanaged_singleton(); } + +Bootstrap::Platform & Bootstrap::platform() +{ + /* + * Don't use static local variable because cmpxchg cannot be executed + * w/o MMU on ARMv6. + */ + static long _obj[(sizeof(Bootstrap::Platform)+sizeof(long))/sizeof(long)]; + static Bootstrap::Platform *ptr; + if (!ptr) + ptr = construct_at(_obj); + + return *ptr; +} extern "C" void init() __attribute__ ((noreturn)); - - extern "C" void init() { Bootstrap::Platform & p = Bootstrap::platform(); diff --git a/repos/base-hw/src/bootstrap/log.cc b/repos/base-hw/src/bootstrap/log.cc index fedee7e2cd..4877c33e1b 100644 --- a/repos/base-hw/src/bootstrap/log.cc +++ b/repos/base-hw/src/bootstrap/log.cc @@ -20,7 +20,6 @@ #include #include #include -#include #include @@ -55,7 +54,11 @@ struct Buffer }; -Genode::Log &Genode::Log::log() { return unmanaged_singleton()->log; } +Genode::Log &Genode::Log::log() +{ + static Buffer buffer { }; + return buffer.log; +} void Genode::raw_write_string(char const *str) { log(str); } diff --git a/repos/base-hw/src/bootstrap/platform.h b/repos/base-hw/src/bootstrap/platform.h index f9aa11657b..8fb1b5743f 100644 --- a/repos/base-hw/src/bootstrap/platform.h +++ b/repos/base-hw/src/bootstrap/platform.h @@ -27,6 +27,7 @@ namespace Bootstrap { using Genode::addr_t; using Genode::size_t; + using Genode::uint32_t; using Boot_info = Hw::Boot_info<::Board::Boot_info>; using Hw::Mmio_space; using Hw::Mapping; diff --git a/repos/base-hw/src/bootstrap/spec/x86_64/multiboot2.h b/repos/base-hw/src/bootstrap/spec/x86_64/multiboot2.h index 3fb5fdf4ad..0f1fc8bd60 100644 --- a/repos/base-hw/src/bootstrap/spec/x86_64/multiboot2.h +++ b/repos/base-hw/src/bootstrap/spec/x86_64/multiboot2.h @@ -73,7 +73,8 @@ class Genode::Multiboot2_info : Mmio<0x8> Multiboot2_info(addr_t mbi) : Mmio({(char *)mbi, Mmio::SIZE}) { } void for_each_tag(auto const &mem_fn, - auto const &acpi_fn, + auto const &acpi_rsdp_v1_fn, + auto const &acpi_rsdp_v2_fn, auto const &fb_fn, auto const &systab64_fn) { @@ -103,6 +104,7 @@ class Genode::Multiboot2_info : Mmio<0x8> if (tag.read() == Tag::Type::ACPI_RSDP_V1 || tag.read() == Tag::Type::ACPI_RSDP_V2) { + size_t const sizeof_tag = 1UL << Tag::LOG2_SIZE; addr_t const rsdp_addr = tag_addr + sizeof_tag; @@ -113,10 +115,12 @@ class Genode::Multiboot2_info : Mmio<0x8> Hw::Acpi_rsdp rsdp_v1; memset (&rsdp_v1, 0, sizeof(rsdp_v1)); memcpy (&rsdp_v1, rsdp, 20); - acpi_fn(rsdp_v1); + acpi_rsdp_v1_fn(rsdp_v1); + } else + if (sizeof(*rsdp) <= tag.read() - sizeof_tag) { + /* ACPI RSDP v2 */ + acpi_rsdp_v2_fn(*rsdp); } - if (sizeof(*rsdp) <= tag.read() - sizeof_tag) - acpi_fn(*rsdp); } if (tag.read() == Tag::Type::FRAMEBUFFER) { diff --git a/repos/base-hw/src/bootstrap/spec/x86_64/platform.cc b/repos/base-hw/src/bootstrap/spec/x86_64/platform.cc index ed38b1d5e5..8ec2e444ac 100644 --- a/repos/base-hw/src/bootstrap/spec/x86_64/platform.cc +++ b/repos/base-hw/src/bootstrap/spec/x86_64/platform.cc @@ -18,10 +18,12 @@ #include #include #include +#include #include #include #include +#include using namespace Genode; @@ -61,11 +63,113 @@ static Hw::Acpi_rsdp search_rsdp(addr_t area, addr_t area_size) } } - Hw::Acpi_rsdp invalid; + Hw::Acpi_rsdp invalid { }; return invalid; } +static uint32_t calibrate_tsc_frequency(addr_t fadt_addr) +{ + uint32_t const default_freq = 2'400'000; + + if (!fadt_addr) { + warning("FADT not found, returning fixed TSC frequency of ", default_freq, "kHz"); + return default_freq; + } + + uint32_t const sleep_ms = 10; + + Hw::Acpi_fadt fadt(reinterpret_cast(fadt_addr)); + + uint32_t const freq = fadt.calibrate_freq_khz(sleep_ms, []() { return Hw::Tsc::rdtsc(); }); + + if (!freq) { + warning("Unable to calibrate TSC, returning fixed TSC frequency of ", default_freq, "kHz"); + return default_freq; + } + + return freq; +} + + +static Hw::Local_apic::Calibration calibrate_lapic_frequency(addr_t fadt_addr) +{ + uint32_t const default_freq = TIMER_MIN_TICKS_PER_MS; + + if (!fadt_addr) { + warning("FADT not found, setting minimum Local APIC frequency of ", default_freq, "kHz"); + return { default_freq, 1 }; + } + + uint32_t const sleep_ms = 10; + + Hw::Acpi_fadt fadt(reinterpret_cast(fadt_addr)); + + Hw::Local_apic lapic(Hw::Cpu_memory_map::lapic_phys_base()); + + auto const result = + lapic.calibrate_divider([&] { + return fadt.calibrate_freq_khz(sleep_ms, [&] { + return lapic.read(); }, true); }); + + if (!result.freq_khz) { + warning("FADT not found, setting minimum Local APIC frequency of ", default_freq, "kHz"); + return { default_freq, 1 }; + } + + return result; +} + + +static void disable_pit() +{ + using Hw::outb; + + enum { + /* PIT constants */ + PIT_CH0_DATA = 0x40, + PIT_MODE = 0x43, + }; + + /* + * Disable PIT timer channel. This is necessary since BIOS sets up + * channel 0 to fire periodically. + */ + outb(PIT_MODE, 0x30); + outb(PIT_CH0_DATA, 0); + outb(PIT_CH0_DATA, 0); +} + + +/* + * Enable dispatch serializing lfence instruction on AMD processors + * + * See Software techniques for managing speculation on AMD processors + * Revision 5.09.23 + * Mitigation G-2 + */ +static void amd_enable_serializing_lfence() +{ + using Cpu = Hw::X86_64_cpu; + + if (Hw::Vendor::get_vendor_id() != Hw::Vendor::Vendor_id::AMD) + return; + + unsigned const family = Hw::Vendor::get_family(); + + /* + * In family 0Fh and 11h, lfence is always dispatch serializing and + * "AMD plans support for this MSR and access to this bit for all future + * processors." from family 14h on. + */ + if ((family == 0x10) || (family == 0x12) || (family >= 0x14)) { + Cpu::Amd_lfence::access_t amd_lfence = Cpu::Amd_lfence::read(); + Cpu::Amd_lfence::Enable_dispatch_serializing::set(amd_lfence); + Cpu::Amd_lfence::write(amd_lfence); + } +} + + Bootstrap::Platform::Board::Board() : core_mmio(Memory_region { 0, 0x1000 }, @@ -143,10 +247,14 @@ Bootstrap::Platform::Board::Board() lambda(base, size); }, - [&] (Hw::Acpi_rsdp const &rsdp) { - /* prefer higher acpi revisions */ - if (!acpi_rsdp.valid() || acpi_rsdp.revision < rsdp.revision) - acpi_rsdp = rsdp; + [&] (Hw::Acpi_rsdp const &rsdp_v1) { + /* only use ACPI RSDP v1 if nothing available/valid by now */ + if (!acpi_rsdp.valid()) + acpi_rsdp = rsdp_v1; + }, + [&] (Hw::Acpi_rsdp const &rsdp_v2) { + /* prefer v2 ever, override stored previous rsdp v1 potentially */ + acpi_rsdp = rsdp_v2; }, [&] (Hw::Framebuffer const &fb) { info.framebuffer = fb; @@ -246,6 +354,21 @@ Bootstrap::Platform::Board::Board() cpus = !cpus ? 1 : max_cpus; } + /* + * Enable serializing lfence on supported AMD processors + * + * For APs this will be set up later, but we need it already to obtain + * the most acurate results when calibrating the TSC frequency. + */ + amd_enable_serializing_lfence(); + + auto r = calibrate_lapic_frequency(info.acpi_fadt); + info.lapic_freq_khz = r.freq_khz; + info.lapic_div = r.div; + info.tsc_freq_khz = calibrate_tsc_frequency(info.acpi_fadt); + + disable_pit(); + /* copy 16 bit boot code for AP CPUs and for ACPI resume */ addr_t ap_code_size = (addr_t)&_start - (addr_t)&_ap; memcpy((void *)AP_BOOT_CODE_PAGE, &_ap, ap_code_size); @@ -315,9 +438,12 @@ unsigned Bootstrap::Platform::enable_mmu() if (board.cpus <= 1) return (unsigned)cpu_id; - if (!Cpu::IA32_apic_base::Bsp::get(lapic_msr)) + if (!Cpu::IA32_apic_base::Bsp::get(lapic_msr)) { /* AP - done */ + /* enable serializing lfence on supported AMD processors. */ + amd_enable_serializing_lfence(); return (unsigned)cpu_id; + } /* BSP - we're primary CPU - wake now all other CPUs */ diff --git a/repos/base-hw/src/core/board/pc/board.h b/repos/base-hw/src/core/board/pc/board.h index f07a971d08..1a9327fbfd 100644 --- a/repos/base-hw/src/core/board/pc/board.h +++ b/repos/base-hw/src/core/board/pc/board.h @@ -21,7 +21,7 @@ /* base-hw core includes */ #include -#include +#include #include namespace Board { diff --git a/repos/base-hw/src/core/core_region_map.cc b/repos/base-hw/src/core/core_region_map.cc index 8965688c8a..f56d302efb 100644 --- a/repos/base-hw/src/core/core_region_map.cc +++ b/repos/base-hw/src/core/core_region_map.cc @@ -82,4 +82,11 @@ Core_region_map::attach(Dataspace_capability ds_cap, Attr const &attr) } -void Core_region_map::detach(addr_t) { } +void Core_region_map::detach(addr_t core_local_addr) +{ + size_t size = platform_specific().region_alloc_size_at((void *)core_local_addr); + + unmap_local(core_local_addr, size >> get_page_size_log2()); + + platform().region_alloc().free((void *)core_local_addr); +} diff --git a/repos/base-hw/src/core/guest_memory.h b/repos/base-hw/src/core/guest_memory.h new file mode 100644 index 0000000000..5cfe658043 --- /dev/null +++ b/repos/base-hw/src/core/guest_memory.h @@ -0,0 +1,275 @@ +/* + * \brief Guest memory abstraction + * \author Stefan Kalkowski + * \author Benjamin Lamowski + * \date 2024-11-25 + */ + +/* + * Copyright (C) 2015-2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CORE__GUEST_MEMORY_H_ +#define _CORE__GUEST_MEMORY_H_ + +/* base includes */ +#include +#include +#include +#include + +/* core includes */ +#include +#include + +namespace Core { class Guest_memory; } + +using namespace Core; + + +class Core::Guest_memory +{ + private: + + using Avl_region = Allocator_avl_tpl; + + using Attach_attr = Genode::Vm_session::Attach_attr; + + Sliced_heap _sliced_heap; + Avl_region _map { &_sliced_heap }; + + uint8_t _remaining_print_count { 10 }; + + void _with_region(addr_t const addr, auto const &fn) + { + Rm_region *region = _map.metadata((void *)addr); + if (region) + fn(*region); + else + if (_remaining_print_count) { + error(__PRETTY_FUNCTION__, " unknown region"); + _remaining_print_count--; + } + } + + public: + + enum class Attach_result { + OK, + INVALID_DS, + OUT_OF_RAM, + OUT_OF_CAPS, + REGION_CONFLICT, + }; + + + Attach_result attach(Region_map_detach &rm_detach, + Dataspace_component &dsc, + addr_t const guest_phys, + Attach_attr attr, + auto const &map_fn) + { + /* + * unsupported - deny otherwise arbitrary physical + * memory can be mapped to a VM + */ + if (dsc.managed()) + return Attach_result::INVALID_DS; + + if (guest_phys & 0xffful || attr.offset & 0xffful || + attr.size & 0xffful) + return Attach_result::INVALID_DS; + + if (!attr.size) { + attr.size = dsc.size(); + + if (attr.offset < attr.size) + attr.size -= attr.offset; + } + + if (attr.size > dsc.size()) + attr.size = dsc.size(); + + if (attr.offset >= dsc.size() || + attr.offset > dsc.size() - attr.size) + return Attach_result::INVALID_DS; + + using Alloc_error = Range_allocator::Alloc_error; + + Attach_result const retval = _map.alloc_addr(attr.size, guest_phys).convert( + + [&] (void *) { + + Rm_region::Attr const region_attr + { + .base = guest_phys, + .size = attr.size, + .write = dsc.writeable() && attr.writeable, + .exec = attr.executable, + .off = attr.offset, + .dma = false, + }; + + /* store attachment info in meta data */ + try { + _map.construct_metadata((void *)guest_phys, + dsc, rm_detach, region_attr); + + } catch (Allocator_avl_tpl::Assign_metadata_failed) { + if (_remaining_print_count) { + error("failed to store attachment info"); + _remaining_print_count--; + } + return Attach_result::INVALID_DS; + } + + Rm_region ®ion = *_map.metadata((void *)guest_phys); + + /* inform dataspace about attachment */ + dsc.attached_to(region); + + return Attach_result::OK; + }, + + [&] (Alloc_error error) { + + switch (error) { + + case Alloc_error::OUT_OF_RAM: + return Attach_result::OUT_OF_RAM; + case Alloc_error::OUT_OF_CAPS: + return Attach_result::OUT_OF_CAPS; + case Alloc_error::DENIED: + { + /* + * Handle attach after partial detach + */ + Rm_region *region_ptr = _map.metadata((void *)guest_phys); + if (!region_ptr) + return Attach_result::REGION_CONFLICT; + + Rm_region ®ion = *region_ptr; + + bool conflict = false; + region.with_dataspace([&] (Dataspace_component &dataspace) { + (void)dataspace; + if (!(dsc.cap() == dataspace.cap())) + conflict = true; + }); + if (conflict) + return Attach_result::REGION_CONFLICT; + + if (guest_phys < region.base() || + guest_phys > region.base() + region.size() - 1) + return Attach_result::REGION_CONFLICT; + } + + }; + + return Attach_result::OK; + } + ); + + if (retval == Attach_result::OK) { + addr_t phys_addr = dsc.phys_addr() + attr.offset; + size_t size = attr.size; + + map_fn(guest_phys, phys_addr, size); + } + + return retval; + } + + + void detach(addr_t guest_phys, + size_t size, + auto const &unmap_fn) + { + if (!size || (guest_phys & 0xffful) || (size & 0xffful)) { + if (_remaining_print_count) { + warning("vm_session: skipping invalid memory detach addr=", + (void *)guest_phys, " size=", (void *)size); + _remaining_print_count--; + } + return; + } + + addr_t const guest_phys_end = guest_phys + (size - 1); + addr_t addr = guest_phys; + do { + Rm_region *region = _map.metadata((void *)addr); + + /* walk region holes page-by-page */ + size_t iteration_size = 0x1000; + + if (region) { + iteration_size = region->size(); + detach_at(region->base(), unmap_fn); + } + + if (addr >= guest_phys_end - (iteration_size - 1)) + break; + + addr += iteration_size; + } while (true); + } + + + Guest_memory(Constrained_ram_allocator &constrained_md_ram_alloc, + Region_map ®ion_map) + : + _sliced_heap(constrained_md_ram_alloc, region_map) + { + /* configure managed VM area */ + _map.add_range(0UL, ~0UL); + } + + ~Guest_memory() + { + /* detach all regions */ + while (true) { + addr_t out_addr = 0; + + if (!_map.any_block_addr(&out_addr)) + break; + + detach_at(out_addr, [](addr_t, size_t) { }); + } + } + + + void detach_at(addr_t addr, + auto const &unmap_fn) + { + _with_region(addr, [&] (Rm_region ®ion) { + + if (!region.reserved()) + reserve_and_flush(addr, unmap_fn); + + /* free the reserved region */ + _map.free(reinterpret_cast(region.base())); + }); + } + + + void reserve_and_flush(addr_t addr, + auto const &unmap_fn) + { + _with_region(addr, [&] (Rm_region ®ion) { + + /* inform dataspace */ + region.with_dataspace([&] (Dataspace_component &dataspace) { + dataspace.detached_from(region); + }); + + region.mark_as_reserved(); + + unmap_fn(region.base(), region.size()); + }); + } +}; + +#endif /* _CORE__GUEST_MEMORY_H_ */ diff --git a/repos/base-hw/src/core/io_mem_session_support.cc b/repos/base-hw/src/core/io_mem_session_support.cc index a25f199fd8..42092b1e6a 100644 --- a/repos/base-hw/src/core/io_mem_session_support.cc +++ b/repos/base-hw/src/core/io_mem_session_support.cc @@ -21,5 +21,7 @@ using namespace Core; void Io_mem_session_component::_unmap_local(addr_t, size_t, addr_t) { } -addr_t Io_mem_session_component::_map_local(addr_t base, size_t) { return base; } - +Io_mem_session_component::Map_local_result Io_mem_session_component::_map_local(addr_t const base, size_t) +{ + return { .core_local_addr = base, .success = true }; +} diff --git a/repos/base-hw/src/core/irq_session_component.cc b/repos/base-hw/src/core/irq_session_component.cc index 6c33684f91..daa4a71c96 100644 --- a/repos/base-hw/src/core/irq_session_component.cc +++ b/repos/base-hw/src/core/irq_session_component.cc @@ -18,7 +18,7 @@ /* core includes */ #include #include -#include +#include /* base-internal includes */ #include diff --git a/repos/base-hw/src/core/kernel/core_interface.h b/repos/base-hw/src/core/kernel/core_interface.h index 4e606ee1be..a57c0acf6e 100644 --- a/repos/base-hw/src/core/kernel/core_interface.h +++ b/repos/base-hw/src/core/kernel/core_interface.h @@ -66,6 +66,7 @@ namespace Kernel { constexpr Call_arg call_id_set_cpu_state() { return 125; } constexpr Call_arg call_id_exception_state() { return 126; } constexpr Call_arg call_id_single_step() { return 127; } + constexpr Call_arg call_id_ack_pager_signal() { return 128; } /** * Invalidate TLB entries for the `pd` in region `addr`, `sz` @@ -137,10 +138,9 @@ namespace Kernel { * \retval 0 suceeded * \retval !=0 failed */ - inline int start_thread(Thread & thread, unsigned const cpu_id, - Pd & pd, Native_utcb & utcb) + inline int start_thread(Thread & thread, Pd & pd, Native_utcb & utcb) { - return (int)call(call_id_start_thread(), (Call_arg)&thread, cpu_id, + return (int)call(call_id_start_thread(), (Call_arg)&thread, (Call_arg)&pd, (Call_arg)&utcb); } @@ -148,13 +148,16 @@ namespace Kernel { /** * Set or unset the handler of an event that can be triggered by a thread * - * \param thread pointer to thread kernel object + * \param thread reference to thread kernel object + * \param pager reference to pager kernel object * \param signal_context_id capability id of the page-fault handler */ - inline void thread_pager(Thread & thread, + inline void thread_pager(Thread &thread, + Thread &pager, capid_t const signal_context_id) { - call(call_id_thread_pager(), (Call_arg)&thread, signal_context_id); + call(call_id_thread_pager(), (Call_arg)&thread, (Call_arg)&pager, + signal_context_id); } @@ -203,6 +206,18 @@ namespace Kernel { { call(call_id_single_step(), (Call_arg)&thread, (Call_arg)&on); } + + /** + * Acknowledge a signal transmitted to a pager + * + * \param context signal context to acknowledge + * \param thread reference to faulting thread kernel object + * \param resolved whether fault got resolved + */ + inline void ack_pager_signal(capid_t const context, Thread &thread, bool resolved) + { + call(call_id_ack_pager_signal(), context, (Call_arg)&thread, resolved); + } } #endif /* _CORE__KERNEL__CORE_INTERFACE_H_ */ diff --git a/repos/base-hw/src/core/kernel/cpu.cc b/repos/base-hw/src/core/kernel/cpu.cc index 0e0c686984..7964230ebf 100644 --- a/repos/base-hw/src/core/kernel/cpu.cc +++ b/repos/base-hw/src/core/kernel/cpu.cc @@ -27,35 +27,35 @@ using namespace Kernel; -/************* - ** Cpu_job ** - *************/ +/***************** + ** Cpu_context ** + *****************/ -void Cpu_job::_activate_own_share() { _cpu->schedule(this); } +void Cpu_context::_activate() { _cpu().schedule(*this); } -void Cpu_job::_deactivate_own_share() +void Cpu_context::_deactivate() { - assert(_cpu->id() == Cpu::executing_id()); - _cpu->scheduler().unready(*this); + assert(_cpu().id() == Cpu::executing_id()); + _cpu().scheduler().unready(*this); } -void Cpu_job::_yield() +void Cpu_context::_yield() { - assert(_cpu->id() == Cpu::executing_id()); - _cpu->scheduler().yield(); + assert(_cpu().id() == Cpu::executing_id()); + _cpu().scheduler().yield(); } -void Cpu_job::_interrupt(Irq::Pool &user_irq_pool, unsigned const /* cpu_id */) +void Cpu_context::_interrupt(Irq::Pool &user_irq_pool) { /* let the IRQ controller take a pending IRQ for handling, if any */ unsigned irq_id; - if (_cpu->pic().take_request(irq_id)) + if (_cpu().pic().take_request(irq_id)) - /* let the CPU of this job handle the IRQ if it is a CPU-local one */ - if (!_cpu->handle_if_cpu_local_interrupt(irq_id)) { + /* let the CPU of this context handle the IRQ if it is a CPU-local one */ + if (!_cpu().handle_if_cpu_local_interrupt(irq_id)) { /* it isn't a CPU-local IRQ, so, it must be a user IRQ */ User_irq * irq = User_irq::object(user_irq_pool, irq_id); @@ -64,38 +64,37 @@ void Cpu_job::_interrupt(Irq::Pool &user_irq_pool, unsigned const /* cpu_id */) } /* let the IRQ controller finish the currently taken IRQ */ - _cpu->pic().finish_request(); + _cpu().pic().finish_request(); } -void Cpu_job::affinity(Cpu &cpu) +void Cpu_context::affinity(Cpu &cpu) { - _cpu = &cpu; - _cpu->scheduler().insert(*this); + _cpu().scheduler().remove(*this); + _cpu_ptr = &cpu; + _cpu().scheduler().insert(*this); } -void Cpu_job::quota(unsigned const q) +void Cpu_context::quota(unsigned const q) { - if (_cpu) - _cpu->scheduler().quota(*this, q); - else - Context::quota(q); + _cpu().scheduler().quota(*this, q); } -Cpu_job::Cpu_job(Priority const p, unsigned const q) +Cpu_context::Cpu_context(Cpu &cpu, + Priority const priority, + unsigned const quota) : - Context(p, q), _cpu(0) -{ } - - -Cpu_job::~Cpu_job() + Context(priority, quota), _cpu_ptr(&cpu) { - if (!_cpu) - return; + _cpu().scheduler().insert(*this); +} - _cpu->scheduler().remove(*this); + +Cpu_context::~Cpu_context() +{ + _cpu().scheduler().remove(*this); } @@ -112,19 +111,17 @@ Cpu::Idle_thread::Idle_thread(Board::Address_space_id_allocator &addr_space_id_a Cpu &cpu, Pd &core_pd) : - Thread { addr_space_id_alloc, user_irq_pool, cpu_pool, core_pd, - Priority::min(), 0, "idle", Thread::IDLE } + Thread { addr_space_id_alloc, user_irq_pool, cpu_pool, cpu, + core_pd, Priority::min(), 0, "idle", Thread::IDLE } { regs->ip = (addr_t)&idle_thread_main; - - affinity(cpu); Thread::_pd = &core_pd; } -void Cpu::schedule(Job * const job) +void Cpu::schedule(Context &context) { - _scheduler.ready(job->context()); + _scheduler.ready(static_cast(context)); if (_id != executing_id() && _scheduler.need_to_schedule()) trigger_ip_interrupt(); } @@ -142,33 +139,34 @@ bool Cpu::handle_if_cpu_local_interrupt(unsigned const irq_id) } -Cpu_job & Cpu::schedule() +Cpu::Context & Cpu::handle_exception_and_schedule() { - /* update scheduler */ - Job & old_job = scheduled_job(); - old_job.exception(*this); + Context &context = current_context(); + context.exception(); if (_state == SUSPEND || _state == HALT) return _halt_job; + /* update schedule if necessary */ if (_scheduler.need_to_schedule()) { _timer.process_timeouts(); _scheduler.update(_timer.time()); time_t t = _scheduler.current_time_left(); _timer.set_timeout(&_timeout, t); time_t duration = _timer.schedule_timeout(); - old_job.update_execution_time(duration); + context.update_execution_time(duration); } - /* return new job */ - return scheduled_job(); + /* return current context */ + return current_context(); } addr_t Cpu::stack_start() { return Abi::stack_align(Hw::Mm::cpu_local_memory().base + - (1024*1024*_id) + (64*1024)); + (Hw::Mm::CPU_LOCAL_MEMORY_SLOT_SIZE*_id) + + Hw::Mm::KERNEL_STACK_SIZE); } diff --git a/repos/base-hw/src/core/kernel/cpu.h b/repos/base-hw/src/core/kernel/cpu.h index 83f2d5b7cc..e7bf8ff30c 100644 --- a/repos/base-hw/src/core/kernel/cpu.h +++ b/repos/base-hw/src/core/kernel/cpu.h @@ -39,9 +39,11 @@ namespace Kernel { class Kernel::Cpu : public Core::Cpu, private Irq::Pool, public Genode::List::Element { - private: + public: - using Job = Cpu_job; + using Context = Cpu_context; + + private: /** * Inter-processor-interrupt object of the cpu @@ -83,16 +85,14 @@ class Kernel::Cpu : public Core::Cpu, private Irq::Pool, Pd &core_pd); }; - struct Halt_job : Job + struct Halt_job : Cpu_context { - Halt_job() : Job (0, 0) { } + Halt_job(Cpu &cpu) + : Cpu_context(cpu, 0, 0) { } - void exception(Kernel::Cpu &) override { } - - void proceed(Kernel::Cpu &) override; - - Kernel::Cpu_job* helping_destination() override { return this; } - } _halt_job { }; + void exception() override { } + void proceed() override; + } _halt_job { *this }; enum State { RUN, HALT, SUSPEND }; @@ -143,14 +143,14 @@ class Kernel::Cpu : public Core::Cpu, private Irq::Pool, bool handle_if_cpu_local_interrupt(unsigned const irq_id); /** - * Schedule 'job' at this CPU + * Schedule 'context' at this CPU */ - void schedule(Job * const job); + void schedule(Context& context); /** - * Return the job that should be executed at next + * Return the context that should be executed next */ - Cpu_job& schedule(); + Context& handle_exception_and_schedule(); Board::Pic & pic() { return _pic; } Timer & timer() { return _timer; } @@ -158,10 +158,10 @@ class Kernel::Cpu : public Core::Cpu, private Irq::Pool, addr_t stack_start(); /** - * Returns the currently active job + * Returns the currently scheduled context */ - Job & scheduled_job() { - return *static_cast(&_scheduler.current())->helping_destination(); } + Context & current_context() { + return static_cast(_scheduler.current().helping_destination()); } unsigned id() const { return _id; } Scheduler &scheduler() { return _scheduler; } diff --git a/repos/base-hw/src/core/kernel/cpu_context.h b/repos/base-hw/src/core/kernel/cpu_context.h index 8c7444ac3d..ad062bc097 100644 --- a/repos/base-hw/src/core/kernel/cpu_context.h +++ b/repos/base-hw/src/core/kernel/cpu_context.h @@ -22,46 +22,39 @@ namespace Kernel { class Cpu; - - /** - * Context of a job (thread, VM, idle) that shall be executed by a CPU - */ - class Cpu_job; + class Cpu_context; } -class Kernel::Cpu_job : private Scheduler::Context +/** + * Context (thread, vcpu) that shall be executed by a CPU + */ +class Kernel::Cpu_context : private Scheduler::Context { private: - friend class Cpu; /* static_cast from 'Scheduler::Context' to 'Cpu_job' */ + friend class Cpu; time_t _execution_time { 0 }; + Cpu *_cpu_ptr; /* * Noncopyable */ - Cpu_job(Cpu_job const &); - Cpu_job &operator = (Cpu_job const &); + Cpu_context(Cpu_context const &); + Cpu_context &operator = (Cpu_context const &); protected: - Cpu * _cpu; + Cpu &_cpu() const { return *_cpu_ptr; } /** - * Handle interrupt exception that occured during execution on CPU 'id' + * Handle interrupt exception */ - void _interrupt(Irq::Pool &user_irq_pool, unsigned const id); + void _interrupt(Irq::Pool &user_irq_pool); - /** - * Activate our own CPU-share - */ - void _activate_own_share(); - - /** - * Deactivate our own CPU-share - */ - void _deactivate_own_share(); + void _activate(); + void _deactivate(); /** * Yield the currently scheduled CPU share of this context @@ -69,55 +62,37 @@ class Kernel::Cpu_job : private Scheduler::Context void _yield(); /** - * Return wether we are allowed to help job 'j' with our CPU-share + * Return possibility to help context 'j' scheduling-wise */ - bool _helping_possible(Cpu_job const &j) const { return j._cpu == _cpu; } + bool _helping_possible(Cpu_context const &j) const { + return j._cpu_ptr == _cpu_ptr; } + + void _help(Cpu_context &context) { Context::help(context); } + + using Context::ready; + using Context::helping_finished; public: using Context = Scheduler::Context; using Priority = Scheduler::Priority; - /** - * Handle exception that occured during execution on CPU 'id' - */ - virtual void exception(Cpu & cpu) = 0; + Cpu_context(Cpu &cpu, + Priority const priority, + unsigned const quota); + + virtual ~Cpu_context(); /** - * Continue execution on CPU 'id' - */ - virtual void proceed(Cpu & cpu) = 0; - - /** - * Return which job currently uses our CPU-share - */ - virtual Cpu_job * helping_destination() = 0; - - /** - * Construct a job with scheduling priority 'p' and time quota 'q' - */ - Cpu_job(Priority const p, unsigned const q); - - /** - * Destructor - */ - virtual ~Cpu_job(); - - /** - * Link job to CPU 'cpu' + * Link context to CPU 'cpu' */ void affinity(Cpu &cpu); /** - * Set CPU quota of the job to 'q' + * Set CPU quota of the context to 'q' */ void quota(unsigned const q); - /** - * Return wether our CPU-share is currently active - */ - bool own_share_active() { return Context::ready(); } - /** * Update total execution time */ @@ -128,14 +103,15 @@ class Kernel::Cpu_job : private Scheduler::Context */ time_t execution_time() const { return _execution_time; } + /** + * Handle exception that occured during execution of this context + */ + virtual void exception() = 0; - /*************** - ** Accessors ** - ***************/ - - void cpu(Cpu &cpu) { _cpu = &cpu; } - - Context &context() { return *this; } + /** + * Continue execution of this context + */ + virtual void proceed() = 0; }; #endif /* _CORE__KERNEL__CPU_CONTEXT_H_ */ diff --git a/repos/base-hw/src/core/kernel/inter_processor_work.h b/repos/base-hw/src/core/kernel/inter_processor_work.h index f2791ccac7..3a4d078a65 100644 --- a/repos/base-hw/src/core/kernel/inter_processor_work.h +++ b/repos/base-hw/src/core/kernel/inter_processor_work.h @@ -11,8 +11,8 @@ * under the terms of the GNU Affero General Public License version 3. */ -#ifndef _CORE__KERNEL__SMP_H_ -#define _CORE__KERNEL__SMP_H_ +#ifndef _CORE__KERNEL__INTER_PROCESSOR_WORK_H_ +#define _CORE__KERNEL__INTER_PROCESSOR_WORK_H_ #include @@ -32,11 +32,11 @@ class Kernel::Inter_processor_work : Genode::Interface { public: - virtual void execute(Cpu &) = 0; + virtual void execute(Cpu & cpu) = 0; protected: Genode::List_element _le { this }; }; -#endif /* _CORE__KERNEL__SMP_H_ */ +#endif /* _CORE__KERNEL__INTER_PROCESSOR_WORK_H_ */ diff --git a/repos/base-hw/src/core/kernel/ipc_node.cc b/repos/base-hw/src/core/kernel/ipc_node.cc index f06b557c36..e323d21e75 100644 --- a/repos/base-hw/src/core/kernel/ipc_node.cc +++ b/repos/base-hw/src/core/kernel/ipc_node.cc @@ -57,19 +57,13 @@ void Ipc_node::_cancel_send() } -bool Ipc_node::_helping() const -{ - return _out.state == Out::SEND_HELPING && _out.node; -} - - bool Ipc_node::ready_to_send() const { return _out.state == Out::READY && !_in.waiting(); } -void Ipc_node::send(Ipc_node &node, bool help) +void Ipc_node::send(Ipc_node &node) { node._in.queue.enqueue(_queue_item); @@ -78,13 +72,7 @@ void Ipc_node::send(Ipc_node &node, bool help) node._thread.ipc_await_request_succeeded(); } _out.node = &node; - _out.state = help ? Out::SEND_HELPING : Out::SEND; -} - - -Thread &Ipc_node::helping_destination() -{ - return _helping() ? _out.node->helping_destination() : _thread; + _out.state = Out::SEND; } diff --git a/repos/base-hw/src/core/kernel/ipc_node.h b/repos/base-hw/src/core/kernel/ipc_node.h index df9f3d7d19..6bdd899eaf 100644 --- a/repos/base-hw/src/core/kernel/ipc_node.h +++ b/repos/base-hw/src/core/kernel/ipc_node.h @@ -50,14 +50,14 @@ class Kernel::Ipc_node struct Out { - enum State { READY, SEND, SEND_HELPING, DESTRUCT }; + enum State { READY, SEND, DESTRUCT }; State state { READY }; Ipc_node *node { nullptr }; bool sending() const { - return state == SEND_HELPING || state == SEND; + return state == SEND; } }; @@ -76,11 +76,6 @@ class Kernel::Ipc_node */ void _cancel_send(); - /** - * Return wether this IPC node is helping another one - */ - bool _helping() const; - /** * Noncopyable */ @@ -102,28 +97,8 @@ class Kernel::Ipc_node * Send a message and wait for the according reply * * \param node targeted IPC node - * \param help wether the request implies a helping relationship */ - void send(Ipc_node &node, bool help); - - /** - * Return final destination of the helping-chain - * this IPC node is part of, or its own thread otherwise - */ - Thread &helping_destination(); - - /** - * Call 'fn' of type 'void (Ipc_node *)' for each helper - */ - void for_each_helper(auto const &fn) - { - _in.queue.for_each([fn] (Queue_item &item) { - Ipc_node &node { item.object() }; - - if (node._helping()) - fn(node._thread); - }); - } + void send(Ipc_node &node); /** * Return whether this IPC node is ready to wait for messages diff --git a/repos/base-hw/src/core/kernel/irq.h b/repos/base-hw/src/core/kernel/irq.h index 9b8be0bf65..bdfb858fc1 100644 --- a/repos/base-hw/src/core/kernel/irq.h +++ b/repos/base-hw/src/core/kernel/irq.h @@ -20,7 +20,7 @@ #include /* core includes */ -#include +#include namespace Board { @@ -161,9 +161,7 @@ class Kernel::User_irq : public Kernel::Irq */ void occurred() override { - if (_context.can_submit(1)) { - _context.submit(1); - } + _context.submit(1); disable(); } diff --git a/repos/base-hw/src/core/kernel/main.cc b/repos/base-hw/src/core/kernel/main.cc index e14b17f1c5..a66f1405ce 100644 --- a/repos/base-hw/src/core/kernel/main.cc +++ b/repos/base-hw/src/core/kernel/main.cc @@ -63,16 +63,16 @@ Kernel::Main *Kernel::Main::_instance; void Kernel::Main::_handle_kernel_entry() { - Cpu &cpu = _cpu_pool.cpu(Cpu::executing_id()); - Cpu_job * new_job; + Cpu::Context * context; { Lock::Guard guard(_data_lock); - new_job = &cpu.schedule(); + context = + &_cpu_pool.cpu(Cpu::executing_id()).handle_exception_and_schedule(); } - new_job->proceed(cpu); + context->proceed(); } diff --git a/repos/base-hw/src/core/kernel/scheduler.cc b/repos/base-hw/src/core/kernel/scheduler.cc index 5dbd7f2c18..da8d8accb2 100644 --- a/repos/base-hw/src/core/kernel/scheduler.cc +++ b/repos/base-hw/src/core/kernel/scheduler.cc @@ -19,6 +19,38 @@ using namespace Kernel; +void Scheduler::Context::help(Scheduler::Context &c) +{ + _destination = &c; + c._helper_list.insert(&_helper_le); +} + + +void Scheduler::Context::helping_finished() +{ + if (!_destination) + return; + + _destination->_helper_list.remove(&_helper_le); + _destination = nullptr; +} + + +Scheduler::Context& Scheduler::Context::helping_destination() +{ + return (_destination) ? _destination->helping_destination() : *this; +} + + +Scheduler::Context::~Context() +{ + helping_finished(); + + for (Context::List_element *h = _helper_list.first(); h; h = h->next()) + h->object()->helping_finished(); +} + + void Scheduler::_consumed(unsigned const time) { if (_super_period_left > time) { @@ -149,7 +181,10 @@ void Scheduler::update(time_t time) void Scheduler::ready(Context &c) { - assert(!c.ready() && &c != &_idle); + assert(&c != &_idle); + + if (c.ready()) + return; c._ready = true; @@ -170,23 +205,33 @@ void Scheduler::ready(Context &c) _slack_list.insert_head(&c._slack_le); if (!keep_current && _state == UP_TO_DATE) _state = OUT_OF_DATE; + + for (Context::List_element *helper = c._helper_list.first(); + helper; helper = helper->next()) + if (!helper->object()->ready()) ready(*helper->object()); } void Scheduler::unready(Context &c) { - assert(c.ready() && &c != &_idle); + assert(&c != &_idle); + + if (!c.ready()) + return; if (&c == _current && _state == UP_TO_DATE) _state = OUT_OF_DATE; c._ready = false; _slack_list.remove(&c._slack_le); - if (!c._quota) - return; + if (c._quota) { + _rpl[c._priority].remove(&c._priotized_le); + _upl[c._priority].insert_tail(&c._priotized_le); + } - _rpl[c._priority].remove(&c._priotized_le); - _upl[c._priority].insert_tail(&c._priotized_le); + for (Context::List_element *helper = c._helper_list.first(); + helper; helper = helper->next()) + if (helper->object()->ready()) unready(*helper->object()); } diff --git a/repos/base-hw/src/core/kernel/scheduler.h b/repos/base-hw/src/core/kernel/scheduler.h index 7727b24995..4f4af83714 100644 --- a/repos/base-hw/src/core/kernel/scheduler.h +++ b/repos/base-hw/src/core/kernel/scheduler.h @@ -65,6 +65,7 @@ class Kernel::Scheduler friend class Scheduler_test::Context; using List_element = Genode::List_element; + using List = Genode::List; unsigned _priority; unsigned _quota; @@ -74,10 +75,20 @@ class Kernel::Scheduler List_element _slack_le { this }; unsigned _slack_time_left { 0 }; + List_element _helper_le { this }; + List _helper_list {}; + Context *_destination { nullptr }; + bool _ready { false }; void _reset() { _priotized_time_left = _quota; } + /** + * Noncopyable + */ + Context(const Context&) = delete; + Context& operator=(const Context&) = delete; + public: Context(Priority const priority, @@ -85,9 +96,14 @@ class Kernel::Scheduler : _priority(priority.value), _quota(quota) { } + ~Context(); bool ready() const { return _ready; } void quota(unsigned const q) { _quota = q; } + + void help(Context &c); + void helping_finished(); + Context& helping_destination(); }; private: diff --git a/repos/base-hw/src/core/kernel/signal_receiver.cc b/repos/base-hw/src/core/kernel/signal.cc similarity index 83% rename from repos/base-hw/src/core/kernel/signal_receiver.cc rename to repos/base-hw/src/core/kernel/signal.cc index 5c99894103..ad5017386a 100644 --- a/repos/base-hw/src/core/kernel/signal_receiver.cc +++ b/repos/base-hw/src/core/kernel/signal.cc @@ -1,18 +1,19 @@ /* * \brief Kernel backend for asynchronous inter-process communication * \author Martin Stein + * \author Stefan Kalkowski * \date 2012-11-30 */ /* - * Copyright (C) 2012-2019 Genode Labs GmbH + * Copyright (C) 2012-2025 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. */ /* core includes */ -#include +#include #include using namespace Kernel; @@ -26,7 +27,7 @@ void Signal_handler::cancel_waiting() { if (_receiver) { _receiver->_handler_cancelled(*this); - _receiver = 0; + _receiver = nullptr; } } @@ -71,28 +72,20 @@ void Signal_context::_deliverable() void Signal_context::_delivered() { _submits = 0; - _ack = 0; + _ack = false; } -void Signal_context::_killer_cancelled() { _killer = 0; } - - -bool Signal_context::can_submit(unsigned const n) const -{ - if (_killed || _submits >= (unsigned)~0 - n) - return false; - - return true; -} +void Signal_context::_killer_cancelled() { _killer = nullptr; } void Signal_context::submit(unsigned const n) { - if (_killed || _submits >= (unsigned)~0 - n) + if (_killed) return; - _submits += n; + if (_submits < ((unsigned)~0 - n)) + _submits += n; if (_ack) _deliverable(); @@ -105,32 +98,19 @@ void Signal_context::ack() return; if (!_killed) { - _ack = 1; + _ack = true; _deliverable(); return; } if (_killer) { - _killer->_context = 0; + _killer->_context = nullptr; _killer->_thread.signal_context_kill_done(); - _killer = 0; + _killer = nullptr; } } -bool Signal_context::can_kill() const -{ - /* check if in a kill operation or already killed */ - if (_killed) { - if (_ack) - return true; - - return false; - } - return true; -} - - void Signal_context::kill(Signal_context_killer &k) { /* check if in a kill operation or already killed */ @@ -139,13 +119,13 @@ void Signal_context::kill(Signal_context_killer &k) /* kill directly if there is no unacknowledged delivery */ if (_ack) { - _killed = 1; + _killed = true; return; } /* wait for delivery acknowledgement */ _killer = &k; - _killed = 1; + _killed = true; _killer->_context = this; _killer->_thread.signal_context_kill_pending(); } @@ -231,24 +211,17 @@ void Signal_receiver::_add_context(Signal_context &c) { _contexts.enqueue(c._contexts_fe); } -bool Signal_receiver::can_add_handler(Signal_handler const &h) const + +bool Signal_receiver::add_handler(Signal_handler &h) { if (h._receiver) return false; - return true; -} - - -void Signal_receiver::add_handler(Signal_handler &h) -{ - if (h._receiver) - return; - _handlers.enqueue(h._handlers_fe); h._receiver = this; h._thread.signal_wait_for_signal(); _listen(); + return true; } diff --git a/repos/base-hw/src/core/kernel/signal_receiver.h b/repos/base-hw/src/core/kernel/signal.h similarity index 91% rename from repos/base-hw/src/core/kernel/signal_receiver.h rename to repos/base-hw/src/core/kernel/signal.h index f5b2df09f8..3fa729e481 100644 --- a/repos/base-hw/src/core/kernel/signal_receiver.h +++ b/repos/base-hw/src/core/kernel/signal.h @@ -1,18 +1,19 @@ /* * \brief Kernel backend for asynchronous inter-process communication * \author Martin Stein + * \author Stefan Kalkowski * \date 2012-11-30 */ /* - * Copyright (C) 2012-2017 Genode Labs GmbH + * Copyright (C) 2012-2025 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. */ -#ifndef _CORE__KERNEL__SIGNAL_RECEIVER_H_ -#define _CORE__KERNEL__SIGNAL_RECEIVER_H_ +#ifndef _CORE__KERNEL__SIGNAL_H_ +#define _CORE__KERNEL__SIGNAL_H_ /* Genode includes */ #include @@ -158,20 +159,14 @@ class Kernel::Signal_context * * \param r receiver that the context shall be assigned to * \param imprint userland identification of the context - * - * \throw Assign_to_receiver_failed */ - Signal_context(Signal_receiver & r, addr_t const imprint); + Signal_context(Signal_receiver &, addr_t const imprint); /** * Submit the signal * * \param n number of submits - * - * \retval 0 succeeded - * \retval -1 failed */ - bool can_submit(unsigned const n) const; void submit(unsigned const n); /** @@ -182,12 +177,8 @@ class Kernel::Signal_context /** * Destruct context or prepare to do it as soon as delivery is done * - * \param killer object that shall receive progress reports - * - * \retval 0 succeeded - * \retval -1 failed + * \param k object that shall receive progress reports */ - bool can_kill() const; void kill(Signal_context_killer &k); /** @@ -272,8 +263,7 @@ class Kernel::Signal_receiver * \retval 0 succeeded * \retval -1 failed */ - bool can_add_handler(Signal_handler const &h) const; - void add_handler(Signal_handler &h); + bool add_handler(Signal_handler &h); /** * Syscall to create a signal receiver diff --git a/repos/base-hw/src/core/kernel/thread.cc b/repos/base-hw/src/core/kernel/thread.cc index b4febf8070..f749276bed 100644 --- a/repos/base-hw/src/core/kernel/thread.cc +++ b/repos/base-hw/src/core/kernel/thread.cc @@ -33,45 +33,42 @@ extern "C" void _core_start(void); using namespace Kernel; -void Thread::_ipc_alloc_recv_caps(unsigned cap_count) +Thread::Ipc_alloc_result Thread::_ipc_alloc_recv_caps(unsigned cap_count) { using Allocator = Genode::Allocator; + using Result = Ipc_alloc_result; Allocator &slab = pd().platform_pd().capability_slab(); for (unsigned i = 0; i < cap_count; i++) { if (_obj_id_ref_ptr[i] != nullptr) continue; - slab.try_alloc(sizeof(Object_identity_reference)).with_result( + Result const result = + slab.try_alloc(sizeof(Object_identity_reference)).convert( [&] (void *ptr) { - _obj_id_ref_ptr[i] = ptr; }, + _obj_id_ref_ptr[i] = ptr; + return Result::OK; }, [&] (Allocator::Alloc_error e) { - switch (e) { - case Allocator::Alloc_error::DENIED: - - /* - * Slab is exhausted, reflect condition to the client. - */ - throw Genode::Out_of_ram(); - - case Allocator::Alloc_error::OUT_OF_CAPS: - case Allocator::Alloc_error::OUT_OF_RAM: - - /* - * These conditions cannot happen because the slab - * does not try to grow automatically. It is - * explicitely expanded by the client as response to - * the 'Out_of_ram' condition above. - */ + /* + * Conditions other than DENIED cannot happen because the slab + * does not try to grow automatically. It is explicitely + * expanded by the client as response to the EXHAUSTED return + * value. + */ + if (e != Allocator::Alloc_error::DENIED) Genode::raw("unexpected recv_caps allocation failure"); - } + + return Result::EXHAUSTED; } ); + if (result == Result::EXHAUSTED) + return result; } _ipc_rcv_caps = cap_count; + return Result::OK; } @@ -87,11 +84,20 @@ void Thread::_ipc_free_recv_caps() } -void Thread::_ipc_init(Genode::Native_utcb &utcb, Thread &starter) +Thread::Ipc_alloc_result Thread::_ipc_init(Genode::Native_utcb &utcb, Thread &starter) { _utcb = &utcb; - _ipc_alloc_recv_caps((unsigned)(starter._utcb->cap_cnt())); - ipc_copy_msg(starter); + + switch (_ipc_alloc_recv_caps((unsigned)(starter._utcb->cap_cnt()))) { + + case Ipc_alloc_result::OK: + ipc_copy_msg(starter); + break; + + case Ipc_alloc_result::EXHAUSTED: + return Ipc_alloc_result::EXHAUSTED; + } + return Ipc_alloc_result::OK; } @@ -163,7 +169,7 @@ Thread::Destroy::Destroy(Thread & caller, Core::Kernel_object & to_delet : caller(caller), thread_to_destroy(to_delete) { - thread_to_destroy->_cpu->work_list().insert(&_le); + thread_to_destroy->_cpu().work_list().insert(&_le); caller._become_inactive(AWAITS_RESTART); } @@ -171,7 +177,7 @@ Thread::Destroy::Destroy(Thread & caller, Core::Kernel_object & to_delet void Thread::Destroy::execute(Cpu &) { - thread_to_destroy->_cpu->work_list().remove(&_le); + thread_to_destroy->_cpu().work_list().remove(&_le); thread_to_destroy.destruct(); caller._restart(); } @@ -233,7 +239,8 @@ void Thread::ipc_send_request_succeeded() assert(_state == AWAITS_IPC); user_arg_0(0); _state = ACTIVE; - if (!Cpu_job::own_share_active()) { _activate_used_shares(); } + _activate(); + helping_finished(); } @@ -242,7 +249,8 @@ void Thread::ipc_send_request_failed() assert(_state == AWAITS_IPC); user_arg_0(-1); _state = ACTIVE; - if (!Cpu_job::own_share_active()) { _activate_used_shares(); } + _activate(); + helping_finished(); } @@ -262,32 +270,16 @@ void Thread::ipc_await_request_failed() } -void Thread::_deactivate_used_shares() -{ - Cpu_job::_deactivate_own_share(); - _ipc_node.for_each_helper([&] (Thread &thread) { - thread._deactivate_used_shares(); }); -} - - -void Thread::_activate_used_shares() -{ - Cpu_job::_activate_own_share(); - _ipc_node.for_each_helper([&] (Thread &thread) { - thread._activate_used_shares(); }); -} - - void Thread::_become_active() { - if (_state != ACTIVE && !_paused) { _activate_used_shares(); } + if (_state != ACTIVE && !_paused) Cpu_context::_activate(); _state = ACTIVE; } void Thread::_become_inactive(State const s) { - if (_state == ACTIVE && !_paused) { _deactivate_used_shares(); } + if (_state == ACTIVE && !_paused) Cpu_context::_deactivate(); _state = s; } @@ -295,17 +287,13 @@ void Thread::_become_inactive(State const s) void Thread::_die() { _become_inactive(DEAD); } -Cpu_job * Thread::helping_destination() { - return &_ipc_node.helping_destination(); } - - size_t Thread::_core_to_kernel_quota(size_t const quota) const { using Genode::Cpu_session; /* we assert at timer construction that cpu_quota_us in ticks fits size_t */ size_t const ticks = (size_t) - _cpu->timer().us_to_ticks(Kernel::cpu_quota_us); + _cpu().timer().us_to_ticks(Kernel::cpu_quota_us); return Cpu_session::quota_lim_downscale(quota, ticks); } @@ -313,24 +301,26 @@ size_t Thread::_core_to_kernel_quota(size_t const quota) const void Thread::_call_thread_quota() { Thread * const thread = (Thread *)user_arg_1(); - thread->Cpu_job::quota((unsigned)(_core_to_kernel_quota(user_arg_2()))); + thread->Cpu_context::quota((unsigned)(_core_to_kernel_quota(user_arg_2()))); } void Thread::_call_start_thread() { - /* lookup CPU */ - Cpu & cpu = _cpu_pool.cpu((unsigned)user_arg_2()); user_arg_0(0); Thread &thread = *(Thread*)user_arg_1(); assert(thread._state == AWAITS_START); - thread.affinity(cpu); - /* join protection domain */ - thread._pd = (Pd *) user_arg_3(); - thread._ipc_init(*(Native_utcb *)user_arg_4(), *this); + thread._pd = (Pd *) user_arg_2(); + switch (thread._ipc_init(*(Native_utcb *)user_arg_3(), *this)) { + case Ipc_alloc_result::OK: + break; + case Ipc_alloc_result::EXHAUSTED: + user_arg_0(-2); + return; + } /* * Sanity check core threads! @@ -344,7 +334,8 @@ void Thread::_call_start_thread() * semantic changes, and additional core threads are started * across cpu cores. */ - if (thread._pd == &_core_pd && cpu.id() != _cpu_pool.primary_cpu().id()) + if (thread._pd == &_core_pd && + thread._cpu().id() != _cpu_pool.primary_cpu().id()) Genode::raw("Error: do not start core threads" " on CPU cores different than boot cpu"); @@ -355,8 +346,8 @@ void Thread::_call_start_thread() void Thread::_call_pause_thread() { Thread &thread = *reinterpret_cast(user_arg_1()); - if (thread._state == ACTIVE && !thread._paused) { - thread._deactivate_used_shares(); } + if (thread._state == ACTIVE && !thread._paused) + thread._deactivate(); thread._paused = true; } @@ -365,8 +356,8 @@ void Thread::_call_pause_thread() void Thread::_call_resume_thread() { Thread &thread = *reinterpret_cast(user_arg_1()); - if (thread._state == ACTIVE && thread._paused) { - thread._activate_used_shares(); } + if (thread._state == ACTIVE && thread._paused) + thread._activate(); thread._paused = false; } @@ -394,6 +385,7 @@ void Thread::_call_restart_thread() _die(); return; } + user_arg_0(thread._restart()); } @@ -401,7 +393,10 @@ void Thread::_call_restart_thread() bool Thread::_restart() { assert(_state == ACTIVE || _state == AWAITS_RESTART); - if (_state != AWAITS_RESTART) { return false; } + + if (_state == ACTIVE && _exception_state == NO_EXCEPTION) + return false; + _exception_state = NO_EXCEPTION; _become_active(); return true; @@ -439,7 +434,7 @@ void Thread::_cancel_blocking() void Thread::_call_yield_thread() { - Cpu_job::_yield(); + Cpu_context::_yield(); } @@ -449,12 +444,11 @@ void Thread::_call_delete_thread() *(Core::Kernel_object*)user_arg_1(); /** - * Delete a thread immediately if it has no cpu assigned yet, - * or it is assigned to this cpu, or the assigned cpu did not scheduled it. + * Delete a thread immediately if it is assigned to this cpu, + * or the assigned cpu did not scheduled it. */ - if (!to_delete->_cpu || - (to_delete->_cpu->id() == Cpu::executing_id() || - &to_delete->_cpu->scheduled_job() != &*to_delete)) { + if (to_delete->_cpu().id() == Cpu::executing_id() || + &to_delete->_cpu().current_context() != &*to_delete) { _call_delete(); return; } @@ -463,7 +457,7 @@ void Thread::_call_delete_thread() * Construct a cross-cpu work item and send an IPI */ _destroy.construct(*this, to_delete); - to_delete->_cpu->trigger_ip_interrupt(); + to_delete->_cpu().trigger_ip_interrupt(); } @@ -472,8 +466,8 @@ void Thread::_call_delete_pd() Core::Kernel_object & pd = *(Core::Kernel_object*)user_arg_1(); - if (_cpu->active(pd->mmu_regs)) - _cpu->switch_to(_core_pd.mmu_regs); + if (_cpu().active(pd->mmu_regs)) + _cpu().switch_to(_core_pd.mmu_regs); _call_delete(); } @@ -482,7 +476,14 @@ void Thread::_call_delete_pd() void Thread::_call_await_request_msg() { if (_ipc_node.ready_to_wait()) { - _ipc_alloc_recv_caps((unsigned)user_arg_1()); + + switch (_ipc_alloc_recv_caps((unsigned)user_arg_1())) { + case Ipc_alloc_result::OK: + break; + case Ipc_alloc_result::EXHAUSTED: + user_arg_0(-2); + return; + } _ipc_node.wait(); if (_ipc_node.waiting()) { _become_inactive(AWAITS_IPC); @@ -498,7 +499,7 @@ void Thread::_call_await_request_msg() void Thread::_call_timeout() { - Timer & t = _cpu->timer(); + Timer & t = _cpu().timer(); _timeout_sigid = (Kernel::capid_t)user_arg_2(); t.set_timeout(this, t.us_to_ticks(user_arg_1())); } @@ -506,13 +507,13 @@ void Thread::_call_timeout() void Thread::_call_timeout_max_us() { - user_ret_time(_cpu->timer().timeout_max_us()); + user_ret_time(_cpu().timer().timeout_max_us()); } void Thread::_call_time() { - Timer & t = _cpu->timer(); + Timer & t = _cpu().timer(); user_ret_time(t.ticks_to_us(t.time())); } @@ -521,11 +522,8 @@ void Thread::timeout_triggered() { Signal_context * const c = pd().cap_tree().find(_timeout_sigid); - if (!c || !c->can_submit(1)) { - Genode::raw(*this, ": failed to submit timeout signal"); - return; - } - c->submit(1); + if (c) c->submit(1); + else Genode::warning(*this, ": failed to submit timeout signal"); } @@ -539,19 +537,26 @@ void Thread::_call_send_request_msg() _become_inactive(DEAD); return; } - bool const help = Cpu_job::_helping_possible(*dst); + bool const help = Cpu_context::_helping_possible(*dst); oir = oir->find(dst->pd()); if (!_ipc_node.ready_to_send()) { Genode::raw("IPC send request: bad state"); } else { - _ipc_alloc_recv_caps((unsigned)user_arg_2()); - _ipc_capid = oir ? oir->capid() : cap_id_invalid(); - _ipc_node.send(dst->_ipc_node, help); + switch (_ipc_alloc_recv_caps((unsigned)user_arg_2())) { + case Ipc_alloc_result::OK: + break; + case Ipc_alloc_result::EXHAUSTED: + user_arg_0(-2); + return; + } + _ipc_capid = oir ? oir->capid() : cap_id_invalid(); + _ipc_node.send(dst->_ipc_node); } _state = AWAITS_IPC; - if (!help || !dst->own_share_active()) { _deactivate_used_shares(); } + if (help) Cpu_context::_help(*dst); + if (!help || !dst->ready()) _deactivate(); } @@ -568,7 +573,9 @@ void Thread::_call_pager() { /* override event route */ Thread &thread = *(Thread *)user_arg_1(); - thread._pager = pd().cap_tree().find((Kernel::capid_t)user_arg_2()); + Thread &pager = *(Thread *)user_arg_2(); + Signal_context &sc = *pd().cap_tree().find((Kernel::capid_t)user_arg_3()); + thread._fault_context.construct(pager, sc); } @@ -592,12 +599,11 @@ void Thread::_call_await_signal() return; } /* register handler at the receiver */ - if (!r->can_add_handler(_signal_handler)) { + if (!r->add_handler(_signal_handler)) { Genode::raw("failed to register handler at signal receiver"); user_arg_0(-1); return; } - r->add_handler(_signal_handler); user_arg_0(0); } @@ -614,11 +620,10 @@ void Thread::_call_pending_signal() } /* register handler at the receiver */ - if (!r->can_add_handler(_signal_handler)) { + if (!r->add_handler(_signal_handler)) { user_arg_0(-1); return; } - r->add_handler(_signal_handler); if (_state == AWAITS_SIGNAL) { _cancel_blocking(); @@ -653,20 +658,7 @@ void Thread::_call_submit_signal() { /* lookup signal context */ Signal_context * const c = pd().cap_tree().find((Kernel::capid_t)user_arg_1()); - if(!c) { - /* cannot submit unknown signal context */ - user_arg_0(-1); - return; - } - - /* trigger signal context */ - if (!c->can_submit((unsigned)user_arg_2())) { - Genode::raw("failed to submit signal context"); - user_arg_0(-1); - return; - } - c->submit((unsigned)user_arg_2()); - user_arg_0(0); + if(c) c->submit((unsigned)user_arg_2()); } @@ -674,13 +666,8 @@ void Thread::_call_ack_signal() { /* lookup signal context */ Signal_context * const c = pd().cap_tree().find((Kernel::capid_t)user_arg_1()); - if (!c) { - Genode::raw(*this, ": cannot ack unknown signal context"); - return; - } - - /* acknowledge */ - c->ack(); + if (c) c->ack(); + else Genode::warning(*this, ": cannot ack unknown signal context"); } @@ -688,19 +675,8 @@ void Thread::_call_kill_signal_context() { /* lookup signal context */ Signal_context * const c = pd().cap_tree().find((Kernel::capid_t)user_arg_1()); - if (!c) { - Genode::raw(*this, ": cannot kill unknown signal context"); - user_arg_0(-1); - return; - } - - /* kill signal context */ - if (!c->can_kill()) { - Genode::raw("failed to kill signal context"); - user_arg_0(-1); - return; - } - c->kill(_signal_context_killer); + if (c) c->kill(_signal_context_killer); + else Genode::warning(*this, ": cannot kill unknown signal context"); } @@ -719,7 +695,7 @@ void Thread::_call_new_irq() (Genode::Irq_session::Polarity) (user_arg_3() & 0b11); _call_new((unsigned)user_arg_2(), trigger, polarity, *c, - _cpu->pic(), _user_irq_pool); + _cpu().pic(), _user_irq_pool); } @@ -820,10 +796,27 @@ void Thread::_call_single_step() { } +void Thread::_call_ack_pager_signal() +{ + Signal_context * const c = pd().cap_tree().find((Kernel::capid_t)user_arg_1()); + if (!c) + Genode::raw(*this, ": cannot ack unknown signal context"); + else + c->ack(); + + Thread &thread = *(Thread*)user_arg_2(); + thread.helping_finished(); + + bool resolved = user_arg_3() || + thread._exception_state == NO_EXCEPTION; + if (resolved) thread._restart(); + else thread._become_inactive(AWAITS_RESTART); +} + + + void Thread::_call() { - try { - /* switch over unrestricted kernel calls */ unsigned const call_id = (unsigned)user_arg_0(); switch (call_id) { @@ -863,13 +856,15 @@ void Thread::_call() switch (call_id) { case call_id_new_thread(): _call_new(_addr_space_id_alloc, _user_irq_pool, _cpu_pool, - _core_pd, (unsigned) user_arg_2(), - (unsigned) _core_to_kernel_quota(user_arg_3()), - (char const *) user_arg_4(), USER); + _cpu_pool.cpu((unsigned)user_arg_2()), + _core_pd, (unsigned) user_arg_3(), + (unsigned) _core_to_kernel_quota(user_arg_4()), + (char const *) user_arg_5(), USER); return; case call_id_new_core_thread(): _call_new(_addr_space_id_alloc, _user_irq_pool, _cpu_pool, - _core_pd, (char const *) user_arg_2()); + _cpu_pool.cpu((unsigned)user_arg_2()), + _core_pd, (char const *) user_arg_3()); return; case call_id_thread_quota(): _call_thread_quota(); return; case call_id_delete_thread(): _call_delete_thread(); return; @@ -902,40 +897,70 @@ void Thread::_call() case call_id_set_cpu_state(): _call_set_cpu_state(); return; case call_id_exception_state(): _call_exception_state(); return; case call_id_single_step(): _call_single_step(); return; + case call_id_ack_pager_signal(): _call_ack_pager_signal(); return; default: Genode::raw(*this, ": unknown kernel call"); _die(); return; } - } catch (Genode::Allocator::Out_of_memory &e) { user_arg_0(-2); } +} + + +void Thread::_signal_to_pager() +{ + if (!_fault_context.constructed()) { + Genode::warning(*this, " could not send signal to pager"); + _die(); + return; + } + + /* first signal to pager to wake it up */ + _fault_context->sc.submit(1); + + /* only help pager thread if runnable and scheduler allows it */ + bool const help = Cpu_context::_helping_possible(_fault_context->pager) + && (_fault_context->pager._state == ACTIVE); + if (help) Cpu_context::_help(_fault_context->pager); + else _become_inactive(AWAITS_RESTART); } void Thread::_mmu_exception() { - _become_inactive(AWAITS_RESTART); + using namespace Genode; + using Genode::log; + _exception_state = MMU_FAULT; Cpu::mmu_fault(*regs, _fault); _fault.ip = regs->ip; if (_fault.type == Thread_fault::UNKNOWN) { - Genode::raw(*this, " raised unhandled MMU fault ", _fault); + Genode::warning(*this, " raised unhandled MMU fault ", _fault); + _die(); return; } - if (_type != USER) - Genode::raw(*this, " raised a fault, which should never happen ", - _fault); + if (_type != USER) { + error(*this, " raised a fault, which should never happen ", + _fault); + log("Register dump: ", *regs); + log("Backtrace:"); - if (_pager && _pager->can_submit(1)) { - _pager->submit(1); + Const_byte_range_ptr const stack { + (char const*)Hw::Mm::core_stack_area().base, + Hw::Mm::core_stack_area().size }; + regs->for_each_return_address(stack, [&] (void **p) { + log(*p); }); + _die(); + return; } + + _signal_to_pager(); } void Thread::_exception() { - _become_inactive(AWAITS_RESTART); _exception_state = EXCEPTION; if (_type != USER) { @@ -943,18 +968,14 @@ void Thread::_exception() _die(); } - if (_pager && _pager->can_submit(1)) { - _pager->submit(1); - } else { - Genode::raw(*this, " could not send signal to pager on exception"); - _die(); - } + _signal_to_pager(); } Thread::Thread(Board::Address_space_id_allocator &addr_space_id_alloc, Irq::Pool &user_irq_pool, Cpu_pool &cpu_pool, + Cpu &cpu, Pd &core_pd, unsigned const priority, unsigned const quota, @@ -962,7 +983,7 @@ Thread::Thread(Board::Address_space_id_allocator &addr_space_id_alloc, Type type) : Kernel::Object { *this }, - Cpu_job { priority, quota }, + Cpu_context { cpu, priority, quota }, _addr_space_id_alloc { addr_space_id_alloc }, _user_irq_pool { user_irq_pool }, _cpu_pool { cpu_pool }, @@ -999,8 +1020,8 @@ Core_main_thread(Board::Address_space_id_allocator &addr_space_id_alloc, Cpu_pool &cpu_pool, Pd &core_pd) : - Core_object( - core_pd, addr_space_id_alloc, user_irq_pool, cpu_pool, core_pd, "core") + Core_object(core_pd, addr_space_id_alloc, user_irq_pool, cpu_pool, + cpu_pool.primary_cpu(), core_pd, "core") { using namespace Core; @@ -1016,7 +1037,6 @@ Core_main_thread(Board::Address_space_id_allocator &addr_space_id_alloc, regs->sp = (addr_t)&__initial_stack_base[0] + DEFAULT_STACK_SIZE; regs->ip = (addr_t)&_core_start; - affinity(_cpu_pool.primary_cpu()); _utcb = &_utcb_instance; Thread::_pd = &core_pd; _become_active(); diff --git a/repos/base-hw/src/core/kernel/thread.h b/repos/base-hw/src/core/kernel/thread.h index 5feedebdf8..74fc257250 100644 --- a/repos/base-hw/src/core/kernel/thread.h +++ b/repos/base-hw/src/core/kernel/thread.h @@ -20,7 +20,7 @@ /* base-hw core includes */ #include #include -#include +#include #include #include #include @@ -53,7 +53,7 @@ struct Kernel::Thread_fault /** * Kernel back-end for userland execution-contexts */ -class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout +class Kernel::Thread : private Kernel::Object, public Cpu_context, private Timeout { public: @@ -173,7 +173,15 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout size_t _ipc_rcv_caps { 0 }; Genode::Native_utcb *_utcb { nullptr }; Pd *_pd { nullptr }; - Signal_context *_pager { nullptr }; + + struct Fault_context + { + Thread &pager; + Signal_context ≻ + }; + + Genode::Constructible _fault_context {}; + Thread_fault _fault { }; State _state; Signal_handler _signal_handler { *this }; @@ -216,21 +224,16 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout */ void _become_inactive(State const s); - /** - * Activate our CPU-share and those of our helpers - */ - void _activate_used_shares(); - - /** - * Deactivate our CPU-share and those of our helpers - */ - void _deactivate_used_shares(); - /** * Suspend unrecoverably from execution */ void _die(); + /** + * In case of fault, signal to pager, and help or block + */ + void _signal_to_pager(); + /** * Handle an exception thrown by the memory management unit */ @@ -306,6 +309,7 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout void _call_set_cpu_state(); void _call_exception_state(); void _call_single_step(); + void _call_ack_pager_signal(); template void _call_new(auto &&... args) @@ -322,9 +326,13 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout kobj.destruct(); } - void _ipc_alloc_recv_caps(unsigned rcv_cap_count); + enum Ipc_alloc_result { OK, EXHAUSTED }; + + [[nodiscard]] Ipc_alloc_result _ipc_alloc_recv_caps(unsigned rcv_cap_count); + void _ipc_free_recv_caps(); - void _ipc_init(Genode::Native_utcb &utcb, Thread &callee); + + [[nodiscard]] Ipc_alloc_result _ipc_init(Genode::Native_utcb &utcb, Thread &callee); public: @@ -341,6 +349,7 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout Thread(Board::Address_space_id_allocator &addr_space_id_alloc, Irq::Pool &user_irq_pool, Cpu_pool &cpu_pool, + Cpu &cpu, Pd &core_pd, unsigned const priority, unsigned const quota, @@ -355,11 +364,12 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout Thread(Board::Address_space_id_allocator &addr_space_id_alloc, Irq::Pool &user_irq_pool, Cpu_pool &cpu_pool, + Cpu &cpu, Pd &core_pd, char const *const label) : - Thread(addr_space_id_alloc, user_irq_pool, cpu_pool, core_pd, - Scheduler::Priority::min(), 0, label, CORE) + Thread(addr_space_id_alloc, user_irq_pool, cpu_pool, cpu, + core_pd, Scheduler::Priority::min(), 0, label, CORE) { } ~Thread(); @@ -396,13 +406,14 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout * \retval capability id of the new kernel object */ static capid_t syscall_create(Core::Kernel_object &t, + unsigned const cpu_id, unsigned const priority, size_t const quota, char const * const label) { return (capid_t)call(call_id_new_thread(), (Call_arg)&t, - (Call_arg)priority, (Call_arg)quota, - (Call_arg)label); + (Call_arg)cpu_id, (Call_arg)priority, + (Call_arg)quota, (Call_arg)label); } /** @@ -414,10 +425,11 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout * \retval capability id of the new kernel object */ static capid_t syscall_create(Core::Kernel_object &t, + unsigned const cpu_id, char const * const label) { return (capid_t)call(call_id_new_core_thread(), (Call_arg)&t, - (Call_arg)label); + (Call_arg)cpu_id, (Call_arg)label); } /** @@ -454,13 +466,12 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout void signal_receive_signal(void * const base, size_t const size); - /************* - ** Cpu_job ** - *************/ + /***************** + ** Cpu_context ** + *****************/ - void exception(Cpu & cpu) override; - void proceed(Cpu & cpu) override; - Cpu_job * helping_destination() override; + void exception() override; + void proceed() override; /************* diff --git a/repos/base-hw/src/core/kernel/vm.h b/repos/base-hw/src/core/kernel/vm.h index b742822f7e..7b82c81803 100644 --- a/repos/base-hw/src/core/kernel/vm.h +++ b/repos/base-hw/src/core/kernel/vm.h @@ -18,7 +18,7 @@ /* core includes */ #include #include -#include +#include #include @@ -31,7 +31,7 @@ namespace Kernel { } -class Kernel::Vm : private Kernel::Object, public Cpu_job +class Kernel::Vm : private Kernel::Object, public Cpu_context { public: @@ -66,7 +66,7 @@ class Kernel::Vm : private Kernel::Object, public Cpu_job void _pause_vcpu() { if (_scheduled != INACTIVE) - Cpu_job::_deactivate_own_share(); + Cpu_context::_deactivate(); _scheduled = INACTIVE; } @@ -135,7 +135,7 @@ class Kernel::Vm : private Kernel::Object, public Cpu_job void run() { _sync_from_vmm(); - if (_scheduled != ACTIVE) Cpu_job::_activate_own_share(); + if (_scheduled != ACTIVE) Cpu_context::_activate(); _scheduled = ACTIVE; } @@ -146,13 +146,12 @@ class Kernel::Vm : private Kernel::Object, public Cpu_job } - /************* - ** Cpu_job ** - *************/ + /***************** + ** Cpu_context ** + *****************/ - void exception(Cpu & cpu) override; - void proceed(Cpu & cpu) override; - Cpu_job * helping_destination() override { return this; } + void exception() override; + void proceed() override; }; #endif /* _CORE__KERNEL__VM_H_ */ diff --git a/repos/base-hw/src/core/pager.cc b/repos/base-hw/src/core/pager.cc index 4fcd3d651e..98855756a8 100644 --- a/repos/base-hw/src/core/pager.cc +++ b/repos/base-hw/src/core/pager.cc @@ -19,9 +19,30 @@ /* base-internal includes */ #include +#include using namespace Core; +static unsigned _nr_of_cpus = 0; +static void *_pager_thread_memory = nullptr; + + +void Core::init_pager_thread_per_cpu_memory(unsigned const cpus, void * mem) +{ + _nr_of_cpus = cpus; + _pager_thread_memory = mem; +} + + +void Core::init_page_fault_handling(Rpc_entrypoint &) { } + + +/************* + ** Mapping ** + *************/ + +void Mapping::prepare_map_operation() const { } + /*************** ** Ipc_pager ** @@ -51,13 +72,11 @@ void Pager_object::wake_up() } -void Pager_object::start_paging(Kernel_object & receiver) +void Pager_object::start_paging(Kernel_object &receiver, + Platform_thread &pager_thread) { - using Object = Kernel_object; - using Entry = Object_pool::Entry; - create(*receiver, (unsigned long)this); - Entry::cap(Object::_cap); + _pager_thread = &pager_thread; } @@ -75,11 +94,11 @@ void Pager_object::print(Output &out) const Pager_object::Pager_object(Cpu_session_capability cpu_session_cap, Thread_capability thread_cap, addr_t const badge, - Affinity::Location, Session_label const &, + Affinity::Location location, Session_label const &, Cpu_session::Name const &) : - Object_pool::Entry(Kernel_object::_cap), - _badge(badge), _cpu_session_cap(cpu_session_cap), _thread_cap(thread_cap) + _badge(badge), _location(location), + _cpu_session_cap(cpu_session_cap), _thread_cap(thread_cap) { } @@ -87,27 +106,115 @@ Pager_object::Pager_object(Cpu_session_capability cpu_session_cap, ** Pager_entrypoint ** **********************/ -void Pager_entrypoint::dissolve(Pager_object &o) +void Pager_entrypoint::Thread::entry() { - Kernel::kill_signal_context(Capability_space::capid(o.cap())); - remove(&o); + while (1) { + + /* receive fault */ + if (Kernel::await_signal(Capability_space::capid(_kobj.cap()))) + continue; + + Pager_object *po = *(Pager_object**)Thread::myself()->utcb()->data(); + if (!po) + continue; + + Untyped_capability cap = po->cap(); + + /* fetch fault data */ + Platform_thread * const pt = (Platform_thread *)po->badge(); + if (!pt) { + warning("failed to get platform thread of faulter"); + Kernel::ack_signal(Capability_space::capid(cap)); + continue; + } + + if (pt->exception_state() == + Kernel::Thread::Exception_state::EXCEPTION) { + if (!po->submit_exception_signal()) + warning("unresolvable exception: " + "pd='", pt->pd().label(), "', " + "thread='", pt->label(), "', " + "ip=", Hex(pt->state().cpu.ip)); + pt->fault_resolved(cap, false); + continue; + } + + _fault = pt->fault_info(); + + /* try to resolve fault directly via local region managers */ + if (po->pager(*this) == Pager_object::Pager_result::STOP) { + pt->fault_resolved(cap, false); + continue; + } + + /* apply mapping that was determined by the local region managers */ + { + Locked_ptr locked_ptr(pt->address_space()); + if (!locked_ptr.valid()) { + pt->fault_resolved(cap, false); + continue; + } + + Hw::Address_space * as = static_cast(&*locked_ptr); + + Cache cacheable = Genode::CACHED; + if (!_mapping.cached) + cacheable = Genode::UNCACHED; + if (_mapping.write_combined) + cacheable = Genode::WRITE_COMBINED; + + Hw::Page_flags const flags { + .writeable = _mapping.writeable ? Hw::RW : Hw::RO, + .executable = _mapping.executable ? Hw::EXEC : Hw::NO_EXEC, + .privileged = Hw::USER, + .global = Hw::NO_GLOBAL, + .type = _mapping.io_mem ? Hw::DEVICE : Hw::RAM, + .cacheable = cacheable + }; + + as->insert_translation(_mapping.dst_addr, _mapping.src_addr, + 1UL << _mapping.size_log2, flags); + } + + pt->fault_resolved(cap, true); + } } -Pager_entrypoint::Pager_entrypoint(Rpc_cap_factory &) +Pager_entrypoint::Thread::Thread(Affinity::Location cpu) : - Thread(Weight::DEFAULT_WEIGHT, "pager_ep", PAGER_EP_STACK_SIZE, - Type::NORMAL), - + Genode::Thread(Weight::DEFAULT_WEIGHT, "pager_ep", PAGER_EP_STACK_SIZE, cpu), _kobj(_kobj.CALLED_FROM_CORE) { start(); } +void Pager_entrypoint::dissolve(Pager_object &o) +{ + Kernel::kill_signal_context(Capability_space::capid(o.cap())); +} + + Pager_capability Pager_entrypoint::manage(Pager_object &o) { - o.start_paging(_kobj); - insert(&o); + unsigned const cpu = o.location().xpos(); + if (cpu >= _cpus) { + error("Invalid location of pager object ", cpu); + } else { + o.start_paging(_threads[cpu]._kobj, + *_threads[cpu].native_thread().platform_thread); + } + return reinterpret_cap_cast(o.cap()); } + + +Pager_entrypoint::Pager_entrypoint(Rpc_cap_factory &) +: + _cpus(_nr_of_cpus), + _threads((Thread*)_pager_thread_memory) +{ + for (unsigned i = 0; i < _cpus; i++) + construct_at((void*)&_threads[i], Affinity::Location(i, 0)); +} diff --git a/repos/base-hw/src/core/pager.h b/repos/base-hw/src/core/pager.h index 29f650e187..3932bb22fe 100644 --- a/repos/base-hw/src/core/pager.h +++ b/repos/base-hw/src/core/pager.h @@ -17,12 +17,11 @@ /* Genode includes */ #include #include -#include #include #include /* core includes */ -#include +#include #include #include #include @@ -30,6 +29,9 @@ namespace Core { + class Platform; + class Platform_thread; + /** * Interface used by generic region_map code */ @@ -53,6 +55,10 @@ namespace Core { using Pager_capability = Capability; enum { PAGER_EP_STACK_SIZE = sizeof(addr_t) * 2048 }; + + extern void init_page_fault_handling(Rpc_entrypoint &); + + void init_pager_thread_per_cpu_memory(unsigned const cpus, void * mem); } @@ -93,17 +99,17 @@ class Core::Ipc_pager }; -class Core::Pager_object : private Object_pool::Entry, - private Kernel_object +class Core::Pager_object : private Kernel_object { friend class Pager_entrypoint; - friend class Object_pool; private: unsigned long const _badge; + Affinity::Location _location; Cpu_session_capability _cpu_session_cap; Thread_capability _thread_cap; + Platform_thread *_pager_thread { nullptr }; /** * User-level signal handler registered for this pager object via @@ -111,6 +117,12 @@ class Core::Pager_object : private Object_pool::Entry, */ Signal_context_capability _exception_sigh { }; + /* + * Noncopyable + */ + Pager_object(const Pager_object&) = delete; + Pager_object& operator=(const Pager_object&) = delete; + public: /** @@ -123,11 +135,15 @@ class Core::Pager_object : private Object_pool::Entry, Affinity::Location, Session_label const&, Cpu_session::Name const&); + virtual ~Pager_object() {} + /** * User identification of pager object */ unsigned long badge() const { return _badge; } + Affinity::Location location() { return _location; } + /** * Resume faulter */ @@ -158,7 +174,8 @@ class Core::Pager_object : private Object_pool::Entry, * * \param receiver signal receiver that receives the page faults */ - void start_paging(Kernel_object & receiver); + void start_paging(Kernel_object &receiver, + Platform_thread &pager_thread); /** * Called when a page-fault finally could not be resolved @@ -167,6 +184,11 @@ class Core::Pager_object : private Object_pool::Entry, void print(Output &out) const; + void with_pager(auto const &fn) + { + if (_pager_thread) fn(*_pager_thread); + } + /****************** ** Pure virtual ** @@ -192,24 +214,44 @@ class Core::Pager_object : private Object_pool::Entry, Cpu_session_capability cpu_session_cap() const { return _cpu_session_cap; } Thread_capability thread_cap() const { return _thread_cap; } - using Object_pool::Entry::cap; + Untyped_capability cap() { + return Kernel_object::_cap; } }; -class Core::Pager_entrypoint : public Object_pool, - public Thread, - private Ipc_pager +class Core::Pager_entrypoint { private: - Kernel_object _kobj; + friend class Platform; + + class Thread : public Genode::Thread, + private Ipc_pager + { + private: + + friend class Pager_entrypoint; + + Kernel_object _kobj; + + public: + + explicit Thread(Affinity::Location); + + + /********************** + ** Thread interface ** + **********************/ + + void entry() override; + }; + + unsigned const _cpus; + Thread *_threads; public: - /** - * Constructor - */ - Pager_entrypoint(Rpc_cap_factory &); + explicit Pager_entrypoint(Rpc_cap_factory &); /** * Associate pager object 'obj' with entry point @@ -220,13 +262,6 @@ class Core::Pager_entrypoint : public Object_pool, * Dissolve pager object 'obj' from entry point */ void dissolve(Pager_object &obj); - - - /********************** - ** Thread interface ** - **********************/ - - void entry() override; }; #endif /* _CORE__PAGER_H_ */ diff --git a/repos/base-hw/src/core/phys_allocated.h b/repos/base-hw/src/core/phys_allocated.h new file mode 100644 index 0000000000..dd640930b5 --- /dev/null +++ b/repos/base-hw/src/core/phys_allocated.h @@ -0,0 +1,79 @@ +/* + * \brief Allocate an object with a physical address + * \author Norman Feske + * \author Benjamin Lamowski + * \date 2024-12-02 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CORE__PHYS_ALLOCATED_H_ +#define _CORE__PHYS_ALLOCATED_H_ + +/* base includes */ +#include +#include +#include + +/* core-local includes */ +#include + +namespace Core { + template + class Phys_allocated; +} + +using namespace Core; + + +template +class Core::Phys_allocated : Genode::Noncopyable +{ + private: + + Rpc_entrypoint &_ep; + Ram_allocator &_ram; + Region_map &_rm; + + Attached_ram_dataspace _ds { _ram, _rm, sizeof(T) }; + public: + + T &obj = *_ds.local_addr(); + + Phys_allocated(Rpc_entrypoint &ep, + Ram_allocator &ram, + Region_map &rm) + : + _ep(ep), _ram(ram), _rm(rm) + { + construct_at(&obj); + } + + Phys_allocated(Rpc_entrypoint &ep, + Ram_allocator &ram, + Region_map &rm, + auto const &construct_fn) + : + _ep(ep), _ram(ram), _rm(rm) + { + construct_fn(*this, &obj); + } + + ~Phys_allocated() { obj.~T(); } + + addr_t phys_addr() { + addr_t phys_addr { }; + _ep.apply(_ds.cap(), [&](Dataspace_component *dsc) { + phys_addr = dsc->phys_addr(); + }); + + return phys_addr; + } +}; + +#endif /* _CORE__PHYS_ALLOCATED_H_ */ diff --git a/repos/base-hw/src/core/platform.cc b/repos/base-hw/src/core/platform.cc index 4df49e25f3..5e2cf3a982 100644 --- a/repos/base-hw/src/core/platform.cc +++ b/repos/base-hw/src/core/platform.cc @@ -19,6 +19,7 @@ /* base-hw core includes */ #include +#include #include #include #include @@ -31,7 +32,6 @@ /* base internal includes */ #include #include -#include /* base includes */ #include @@ -60,8 +60,9 @@ Hw::Page_table::Allocator & Platform::core_page_table_allocator() using Allocator = Hw::Page_table::Allocator; using Array = Allocator::Array; addr_t virt_addr = Hw::Mm::core_page_tables().base + sizeof(Hw::Page_table); - return *unmanaged_singleton(_boot_info().table_allocator, - virt_addr); + + static Array::Allocator alloc { _boot_info().table_allocator, virt_addr }; + return alloc; } @@ -70,6 +71,7 @@ addr_t Platform::core_main_thread_phys_utcb() return core_phys_addr(_boot_info().core_main_thread_utcb); } + void Platform::_init_io_mem_alloc() { /* add entire adress space minus the RAM memory regions */ @@ -81,8 +83,9 @@ void Platform::_init_io_mem_alloc() Hw::Memory_region_array const & Platform::_core_virt_regions() { - return *unmanaged_singleton( - Hw::Memory_region(stack_area_virtual_base(), stack_area_virtual_size())); + static Hw::Memory_region_array array { + Hw::Memory_region(stack_area_virtual_base(), stack_area_virtual_size()) }; + return array; } @@ -161,6 +164,9 @@ void Platform::_init_platform_info() xml.attribute("acpi", true); xml.attribute("msi", true); }); + xml.node("board", [&] { + xml.attribute("name", BOARD_NAME); + }); _init_additional_platform_info(xml); xml.node("affinity-space", [&] { xml.attribute("width", affinity_space().width()); @@ -248,6 +254,10 @@ Platform::Platform() ); } + unsigned const cpus = _boot_info().cpus; + size_t size = cpus * sizeof(Pager_entrypoint::Thread); + init_pager_thread_per_cpu_memory(cpus, _core_mem_alloc.alloc(size)); + class Idle_thread_trace_source : public Trace::Source::Info_accessor, private Trace::Control, private Trace::Source diff --git a/repos/base-hw/src/core/platform.h b/repos/base-hw/src/core/platform.h index de24fa5150..62fd61469e 100644 --- a/repos/base-hw/src/core/platform.h +++ b/repos/base-hw/src/core/platform.h @@ -119,6 +119,18 @@ class Core::Platform : public Platform_generic static addr_t core_page_table(); static Hw::Page_table::Allocator & core_page_table_allocator(); + /** + * Determine size of a core local mapping required for a + * Core_region_map::detach(). + */ + size_t region_alloc_size_at(void * addr) + { + using Size_at_error = Allocator_avl::Size_at_error; + + return (_core_mem_alloc.virt_alloc())()->size_at(addr).convert( + [ ] (size_t s) { return s; }, + [ ] (Size_at_error) { return 0U; }); + } /******************************** ** Platform_generic interface ** diff --git a/repos/base-hw/src/core/platform_pd.cc b/repos/base-hw/src/core/platform_pd.cc index b96e1ee8b2..97d3e93977 100644 --- a/repos/base-hw/src/core/platform_pd.cc +++ b/repos/base-hw/src/core/platform_pd.cc @@ -60,6 +60,13 @@ bool Hw::Address_space::insert_translation(addr_t virt, addr_t phys, _tt.insert_translation(virt, phys, size, flags, _tt_alloc); return true; } catch(Hw::Out_of_tables &) { + + /* core/kernel's page-tables should never get flushed */ + if (_tt_phys == Platform::core_page_table()) { + error("core's page-table allocator is empty!"); + return false; + } + flush(platform().vm_start(), platform().vm_size()); } } diff --git a/repos/base-hw/src/core/platform_thread.cc b/repos/base-hw/src/core/platform_thread.cc index 7ae23acd04..c538306fa9 100644 --- a/repos/base-hw/src/core/platform_thread.cc +++ b/repos/base-hw/src/core/platform_thread.cc @@ -15,7 +15,6 @@ /* core includes */ #include #include -#include #include #include @@ -30,6 +29,48 @@ using namespace Core; +addr_t Platform_thread::Utcb::_attach(Region_map &core_rm) +{ + Region_map::Attr attr { }; + attr.writeable = true; + return core_rm.attach(_ds, attr).convert( + [&] (Region_map::Range range) { return range.start; }, + [&] (Region_map::Attach_error) { + error("failed to attach UTCB of new thread within core"); + return 0ul; }); +} + + +static addr_t _alloc_core_local_utcb(addr_t core_addr) +{ + /* + * All non-core threads use the typical dataspace/rm_session + * mechanisms to allocate and attach its UTCB. + * But for the very first core threads, we need to use plain + * physical and virtual memory allocators to create/attach its + * UTCBs. Therefore, we've to allocate and map those here. + */ + return platform().ram_alloc().try_alloc(sizeof(Native_utcb)).convert( + + [&] (void *utcb_phys) { + map_local((addr_t)utcb_phys, core_addr, + sizeof(Native_utcb) / get_page_size()); + return addr_t(utcb_phys); + }, + [&] (Range_allocator::Alloc_error) { + error("failed to allocate UTCB for core/kernel thread!"); + return 0ul; + }); +} + + +Platform_thread::Utcb::Utcb(addr_t core_addr) +: + core_addr(core_addr), + phys_addr(_alloc_core_local_utcb(core_addr)) +{ } + + void Platform_thread::_init() { } @@ -37,21 +78,6 @@ Weak_ptr& Platform_thread::address_space() { return _address_space; } -Platform_thread::~Platform_thread() -{ - /* detach UTCB of main threads */ - if (_main_thread) { - Locked_ptr locked_ptr(_address_space); - if (locked_ptr.valid()) - locked_ptr->flush((addr_t)_utcb_pd_addr, sizeof(Native_utcb), - Address_space::Core_local_addr{0}); - } - - /* free UTCB */ - core_env().pd_session()->free(_utcb); -} - - void Platform_thread::quota(size_t const quota) { _quota = (unsigned)quota; @@ -64,65 +90,57 @@ Platform_thread::Platform_thread(Label const &label, Native_utcb &utcb) _label(label), _pd(_kernel_main_get_core_platform_pd()), _pager(nullptr), - _utcb_core_addr(&utcb), - _utcb_pd_addr(&utcb), + _utcb((addr_t)&utcb), _main_thread(false), _location(Affinity::Location()), - _kobj(_kobj.CALLED_FROM_CORE, _label.string()) -{ - /* create UTCB for a core thread */ - platform().ram_alloc().try_alloc(sizeof(Native_utcb)).with_result( - - [&] (void *utcb_phys) { - map_local((addr_t)utcb_phys, (addr_t)_utcb_core_addr, - sizeof(Native_utcb) / get_page_size()); - }, - [&] (Range_allocator::Alloc_error) { - error("failed to allocate UTCB"); - /* XXX distinguish error conditions */ - throw Out_of_ram(); - } - ); -} + _kobj(_kobj.CALLED_FROM_CORE, _location.xpos(), _label.string()) +{ } Platform_thread::Platform_thread(Platform_pd &pd, + Rpc_entrypoint &ep, + Ram_allocator &ram, + Region_map &core_rm, size_t const quota, Label const &label, unsigned const virt_prio, Affinity::Location const location, - addr_t const utcb) + addr_t /* utcb */) : _label(label), _pd(pd), _pager(nullptr), - _utcb_pd_addr((Native_utcb *)utcb), + _utcb(ep, ram, core_rm), _priority(_scale_priority(virt_prio)), _quota((unsigned)quota), _main_thread(!pd.has_any_thread), _location(location), - _kobj(_kobj.CALLED_FROM_CORE, _priority, _quota, _label.string()) + _kobj(_kobj.CALLED_FROM_CORE, _location.xpos(), + _priority, _quota, _label.string()) { - try { - _utcb = core_env().pd_session()->alloc(sizeof(Native_utcb), CACHED); - } catch (...) { - error("failed to allocate UTCB"); - throw Out_of_ram(); - } - - Region_map::Attr attr { }; - attr.writeable = true; - core_env().rm_session()->attach(_utcb, attr).with_result( - [&] (Region_map::Range range) { - _utcb_core_addr = (Native_utcb *)range.start; }, - [&] (Region_map::Attach_error) { - error("failed to attach UTCB of new thread within core"); }); - _address_space = pd.weak_ptr(); pd.has_any_thread = true; } +Platform_thread::~Platform_thread() +{ + /* core/kernel threads have no dataspace, but plain memory as UTCB */ + if (!_utcb._ds.valid()) { + error("UTCB of core/kernel thread gets destructed!"); + return; + } + + /* detach UTCB of main threads */ + if (_main_thread) { + Locked_ptr locked_ptr(_address_space); + if (locked_ptr.valid()) + locked_ptr->flush(user_utcb_main_thread(), sizeof(Native_utcb), + Address_space::Core_local_addr{0}); + } +} + + void Platform_thread::affinity(Affinity::Location const &) { /* yet no migration support, don't claim wrong location, e.g. for tracing */ @@ -137,36 +155,23 @@ void Platform_thread::start(void * const ip, void * const sp) /* attach UTCB in case of a main thread */ if (_main_thread) { - /* lookup dataspace component for physical address */ - auto lambda = [&] (Dataspace_component *dsc) { - if (!dsc) return -1; - - /* lock the address space */ - Locked_ptr locked_ptr(_address_space); - if (!locked_ptr.valid()) { - error("invalid RM client"); - return -1; - }; - _utcb_pd_addr = (Native_utcb *)user_utcb_main_thread(); - Hw::Address_space * as = static_cast(&*locked_ptr); - if (!as->insert_translation((addr_t)_utcb_pd_addr, dsc->phys_addr(), - sizeof(Native_utcb), Hw::PAGE_FLAGS_UTCB)) { - error("failed to attach UTCB"); - return -1; - } - return 0; - }; - if (core_env().entrypoint().apply(_utcb, lambda)) + Locked_ptr locked_ptr(_address_space); + if (!locked_ptr.valid()) { + error("unable to start thread in invalid address space"); return; + }; + Hw::Address_space * as = static_cast(&*locked_ptr); + if (!as->insert_translation(user_utcb_main_thread(), _utcb.phys_addr, + sizeof(Native_utcb), Hw::PAGE_FLAGS_UTCB)) { + error("failed to attach UTCB"); + return; + } } /* initialize thread registers */ _kobj->regs->ip = reinterpret_cast(ip); _kobj->regs->sp = reinterpret_cast(sp); - /* start executing new thread */ - unsigned const cpu = _location.xpos(); - Native_utcb &utcb = *Thread::myself()->utcb(); /* reset capability counter */ @@ -174,18 +179,22 @@ void Platform_thread::start(void * const ip, void * const sp) utcb.cap_add(Capability_space::capid(_kobj.cap())); if (_main_thread) { utcb.cap_add(Capability_space::capid(_pd.parent())); - utcb.cap_add(Capability_space::capid(_utcb)); + utcb.cap_add(Capability_space::capid(_utcb._ds)); } - Kernel::start_thread(*_kobj, cpu, _pd.kernel_pd(), *_utcb_core_addr); + + Kernel::start_thread(*_kobj, _pd.kernel_pd(), + *(Native_utcb*)_utcb.core_addr); } -void Platform_thread::pager(Pager_object &pager) +void Platform_thread::pager(Pager_object &po) { using namespace Kernel; - thread_pager(*_kobj, Capability_space::capid(pager.cap())); - _pager = &pager; + po.with_pager([&] (Platform_thread &pt) { + thread_pager(*_kobj, *pt._kobj, + Capability_space::capid(po.cap())); }); + _pager = &po; } @@ -231,3 +240,9 @@ void Platform_thread::restart() { Kernel::restart_thread(Capability_space::capid(_kobj.cap())); } + + +void Platform_thread::fault_resolved(Untyped_capability cap, bool resolved) +{ + Kernel::ack_pager_signal(Capability_space::capid(cap), *_kobj, resolved); +} diff --git a/repos/base-hw/src/core/platform_thread.h b/repos/base-hw/src/core/platform_thread.h index 4c386eb1ef..85ddf9dd15 100644 --- a/repos/base-hw/src/core/platform_thread.h +++ b/repos/base-hw/src/core/platform_thread.h @@ -19,6 +19,7 @@ #include #include #include +#include /* base-internal includes */ #include @@ -26,6 +27,7 @@ /* core includes */ #include #include +#include /* kernel includes */ #include @@ -55,13 +57,66 @@ class Core::Platform_thread : Noncopyable using Label = String<32>; + struct Utcb : Noncopyable + { + struct { + Ram_allocator *_ram_ptr = nullptr; + Region_map *_core_rm_ptr = nullptr; + }; + + Ram_dataspace_capability _ds { }; /* UTCB ds of non-core threads */ + + addr_t const core_addr; /* UTCB address within core/kernel */ + addr_t const phys_addr; + + /* + * \throw Out_of_ram + * \throw Out_of_caps + */ + Ram_dataspace_capability _allocate(Ram_allocator &ram) + { + return ram.alloc(sizeof(Native_utcb), CACHED); + } + + addr_t _attach(Region_map &); + + static addr_t _ds_phys(Rpc_entrypoint &ep, Dataspace_capability ds) + { + return ep.apply(ds, [&] (Dataspace_component *dsc) { + return dsc ? dsc->phys_addr() : 0; }); + } + + /** + * Constructor used for core-local threads + */ + Utcb(addr_t core_addr); + + /** + * Constructor used for threads outside of core + */ + Utcb(Rpc_entrypoint &ep, Ram_allocator &ram, Region_map &core_rm) + : + _core_rm_ptr(&core_rm), + _ds(_allocate(ram)), + core_addr(_attach(core_rm)), + phys_addr(_ds_phys(ep, _ds)) + { } + + ~Utcb() + { + if (_core_rm_ptr) + _core_rm_ptr->detach(core_addr); + + if (_ram_ptr && _ds.valid()) + _ram_ptr->free(_ds); + } + }; + Label const _label; Platform_pd &_pd; Weak_ptr _address_space { }; Pager_object * _pager; - Native_utcb * _utcb_core_addr { }; /* UTCB addr in core */ - Native_utcb * _utcb_pd_addr; /* UTCB addr in pd */ - Ram_dataspace_capability _utcb { }; /* UTCB dataspace */ + Utcb _utcb; unsigned _priority {0}; unsigned _quota {0}; @@ -115,7 +170,8 @@ class Core::Platform_thread : Noncopyable * \param virt_prio unscaled processor-scheduling priority * \param utcb core local pointer to userland stack */ - Platform_thread(Platform_pd &, size_t const quota, Label const &label, + Platform_thread(Platform_pd &, Rpc_entrypoint &, Ram_allocator &, + Region_map &, size_t const quota, Label const &label, unsigned const virt_prio, Affinity::Location, addr_t const utcb); @@ -160,6 +216,8 @@ class Core::Platform_thread : Noncopyable void restart(); + void fault_resolved(Untyped_capability, bool); + /** * Pause this thread */ @@ -241,7 +299,7 @@ class Core::Platform_thread : Noncopyable Platform_pd &pd() const { return _pd; } - Ram_dataspace_capability utcb() const { return _utcb; } + Ram_dataspace_capability utcb() const { return _utcb._ds; } }; #endif /* _CORE__PLATFORM_THREAD_H_ */ diff --git a/repos/base-hw/src/core/region_map_support.cc b/repos/base-hw/src/core/region_map_support.cc deleted file mode 100644 index 4f7f4df79d..0000000000 --- a/repos/base-hw/src/core/region_map_support.cc +++ /dev/null @@ -1,94 +0,0 @@ -/* - * \brief RM- and pager implementations specific for base-hw and core - * \author Martin Stein - * \author Stefan Kalkowski - * \date 2012-02-12 - */ - -/* - * Copyright (C) 2012-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -/* base-hw core includes */ -#include -#include -#include - -using namespace Core; - - -void Pager_entrypoint::entry() -{ - Untyped_capability cap; - - while (1) { - - if (cap.valid()) Kernel::ack_signal(Capability_space::capid(cap)); - - /* receive fault */ - if (Kernel::await_signal(Capability_space::capid(_kobj.cap()))) continue; - - Pager_object *po = *(Pager_object**)Thread::myself()->utcb()->data(); - cap = po->cap(); - - if (!po) continue; - - /* fetch fault data */ - Platform_thread * const pt = (Platform_thread *)po->badge(); - if (!pt) { - warning("failed to get platform thread of faulter"); - continue; - } - - if (pt->exception_state() == - Kernel::Thread::Exception_state::EXCEPTION) { - if (!po->submit_exception_signal()) - warning("unresolvable exception: " - "pd='", pt->pd().label(), "', " - "thread='", pt->label(), "', " - "ip=", Hex(pt->state().cpu.ip)); - continue; - } - - _fault = pt->fault_info(); - - /* try to resolve fault directly via local region managers */ - if (po->pager(*this) == Pager_object::Pager_result::STOP) - continue; - - /* apply mapping that was determined by the local region managers */ - { - Locked_ptr locked_ptr(pt->address_space()); - if (!locked_ptr.valid()) continue; - - Hw::Address_space * as = static_cast(&*locked_ptr); - - Cache cacheable = Genode::CACHED; - if (!_mapping.cached) - cacheable = Genode::UNCACHED; - if (_mapping.write_combined) - cacheable = Genode::WRITE_COMBINED; - - Hw::Page_flags const flags { - .writeable = _mapping.writeable ? Hw::RW : Hw::RO, - .executable = _mapping.executable ? Hw::EXEC : Hw::NO_EXEC, - .privileged = Hw::USER, - .global = Hw::NO_GLOBAL, - .type = _mapping.io_mem ? Hw::DEVICE : Hw::RAM, - .cacheable = cacheable - }; - - as->insert_translation(_mapping.dst_addr, _mapping.src_addr, - 1UL << _mapping.size_log2, flags); - } - - /* let pager object go back to no-fault state */ - po->wake_up(); - } -} - - -void Mapping::prepare_map_operation() const { } diff --git a/repos/base-hw/src/core/signal_source_component.h b/repos/base-hw/src/core/signal_source_component.h index 82186608f3..e4449fc3e7 100644 --- a/repos/base-hw/src/core/signal_source_component.h +++ b/repos/base-hw/src/core/signal_source_component.h @@ -19,7 +19,7 @@ /* core includes */ #include -#include +#include #include namespace Core { diff --git a/repos/base-hw/src/core/spec/arm/cpu.cc b/repos/base-hw/src/core/spec/arm/cpu.cc index 06e6f1baf5..697b9a0cf0 100644 --- a/repos/base-hw/src/core/spec/arm/cpu.cc +++ b/repos/base-hw/src/core/spec/arm/cpu.cc @@ -22,6 +22,32 @@ using namespace Core; +void Arm_cpu::Context::print(Output &output) const +{ + using namespace Genode; + using Genode::print; + + print(output, "\n"); + print(output, " r0 = ", Hex(r0), "\n"); + print(output, " r1 = ", Hex(r1), "\n"); + print(output, " r2 = ", Hex(r2), "\n"); + print(output, " r3 = ", Hex(r3), "\n"); + print(output, " r4 = ", Hex(r4), "\n"); + print(output, " r5 = ", Hex(r5), "\n"); + print(output, " r6 = ", Hex(r6), "\n"); + print(output, " r7 = ", Hex(r7), "\n"); + print(output, " r8 = ", Hex(r8), "\n"); + print(output, " r9 = ", Hex(r9), "\n"); + print(output, " r10 = ", Hex(r10), "\n"); + print(output, " r11 = ", Hex(r11), "\n"); + print(output, " r12 = ", Hex(r12), "\n"); + print(output, " ip = ", Hex(ip), "\n"); + print(output, " sp = ", Hex(sp), "\n"); + print(output, " lr = ", Hex(lr), "\n"); + print(output, " cpsr = ", Hex(cpsr)); +} + + Arm_cpu::Context::Context(bool privileged) { using Psr = Arm_cpu::Psr; diff --git a/repos/base-hw/src/core/spec/arm/cpu_support.h b/repos/base-hw/src/core/spec/arm/cpu_support.h index ef7fabdaf5..012b04eceb 100644 --- a/repos/base-hw/src/core/spec/arm/cpu_support.h +++ b/repos/base-hw/src/core/spec/arm/cpu_support.h @@ -49,6 +49,18 @@ struct Core::Arm_cpu : public Hw::Arm_cpu struct alignas(8) Context : Cpu_state, Fpu_context { Context(bool privileged); + + void print(Output &output) const; + + void for_each_return_address(Const_byte_range_ptr const &stack, + auto const &fn) + { + void **fp = (void**)r11; + while (stack.contains(fp-1) && stack.contains(fp) && fp[0]) { + fn(fp); + fp = (void **) fp[-1]; + } + } }; /** diff --git a/repos/base-hw/src/core/spec/arm/kernel/thread.cc b/repos/base-hw/src/core/spec/arm/kernel/thread.cc index c353745e46..39b3e2030a 100644 --- a/repos/base-hw/src/core/spec/arm/kernel/thread.cc +++ b/repos/base-hw/src/core/spec/arm/kernel/thread.cc @@ -23,32 +23,35 @@ using namespace Kernel; -extern "C" void kernel_to_user_context_switch(Cpu::Context*, Cpu::Fpu_context*); +extern "C" void kernel_to_user_context_switch(Core::Cpu::Context*, + Core::Cpu::Fpu_context*); void Thread::_call_suspend() { } -void Thread::exception(Cpu & cpu) +void Thread::exception() { + using Ctx = Core::Cpu::Context; + switch (regs->cpu_exception) { - case Cpu::Context::SUPERVISOR_CALL: + case Ctx::SUPERVISOR_CALL: _call(); return; - case Cpu::Context::PREFETCH_ABORT: - case Cpu::Context::DATA_ABORT: + case Ctx::PREFETCH_ABORT: + case Ctx::DATA_ABORT: _mmu_exception(); return; - case Cpu::Context::INTERRUPT_REQUEST: - case Cpu::Context::FAST_INTERRUPT_REQUEST: - _interrupt(_user_irq_pool, cpu.id()); + case Ctx::INTERRUPT_REQUEST: + case Ctx::FAST_INTERRUPT_REQUEST: + _interrupt(_user_irq_pool); return; - case Cpu::Context::UNDEFINED_INSTRUCTION: + case Ctx::UNDEFINED_INSTRUCTION: Genode::raw(*this, ": undefined instruction at ip=", Genode::Hex(regs->ip)); _die(); return; - case Cpu::Context::RESET: + case Ctx::RESET: return; default: Genode::raw(*this, ": triggered an unknown exception ", @@ -71,17 +74,17 @@ void Kernel::Thread::Tlb_invalidation::execute(Cpu &) { } void Thread::Flush_and_stop_cpu::execute(Cpu &) { } -void Cpu::Halt_job::proceed(Kernel::Cpu &) { } +void Cpu::Halt_job::proceed() { } -void Thread::proceed(Cpu & cpu) +void Thread::proceed() { - if (!cpu.active(pd().mmu_regs) && type() != CORE) - cpu.switch_to(pd().mmu_regs); + if (!_cpu().active(pd().mmu_regs) && type() != CORE) + _cpu().switch_to(pd().mmu_regs); - regs->cpu_exception = cpu.stack_start(); - kernel_to_user_context_switch((static_cast(&*regs)), - (static_cast(&*regs))); + regs->cpu_exception = _cpu().stack_start(); + kernel_to_user_context_switch((static_cast(&*regs)), + (static_cast(&*regs))); } diff --git a/repos/base-hw/src/core/spec/arm/virtualization/platform_services.cc b/repos/base-hw/src/core/spec/arm/virtualization/platform_services.cc index 67c15ca117..a7d355235d 100644 --- a/repos/base-hw/src/core/spec/arm/virtualization/platform_services.cc +++ b/repos/base-hw/src/core/spec/arm/virtualization/platform_services.cc @@ -16,12 +16,11 @@ /* core includes */ #include +#include #include -#include #include #include #include -#include using namespace Core; @@ -32,10 +31,13 @@ extern addr_t hypervisor_exception_vector; /* * Add ARM virtualization specific vm service */ -void Core::platform_add_local_services(Rpc_entrypoint &ep, - Sliced_heap &sh, - Registry &services, - Core::Trace::Source_registry &trace_sources) +void Core::platform_add_local_services(Rpc_entrypoint &ep, + Sliced_heap &sh, + Registry &services, + Trace::Source_registry &trace_sources, + Ram_allocator &core_ram, + Region_map &core_rm, + Range_allocator &) { map_local(Platform::core_phys_addr((addr_t)&hypervisor_exception_vector), Hw::Mm::hypervisor_exception_vector().base, @@ -50,8 +52,7 @@ void Core::platform_add_local_services(Rpc_entrypoint &ep, Hw::Mm::hypervisor_stack().size / get_page_size(), Hw::PAGE_FLAGS_KERN_DATA); - static Vm_root vm_root(ep, sh, core_env().ram_allocator(), - core_env().local_rm(), trace_sources); + static Vm_root vm_root(ep, sh, core_ram, core_rm, trace_sources); static Core_service vm_service(services, vm_root); }, [&] (Range_allocator::Alloc_error) { diff --git a/repos/base-hw/src/core/spec/arm/virtualization/vm_session_component.cc b/repos/base-hw/src/core/spec/arm/virtualization/vm_session_component.cc index 9eb54ab608..fdd40179e5 100644 --- a/repos/base-hw/src/core/spec/arm/virtualization/vm_session_component.cc +++ b/repos/base-hw/src/core/spec/arm/virtualization/vm_session_component.cc @@ -14,15 +14,11 @@ /* Genode includes */ #include -/* base internal includes */ -#include - /* core includes */ #include #include #include #include -#include using namespace Core; @@ -87,29 +83,14 @@ void * Vm_session_component::_alloc_table() } -using Vmid_allocator = Bit_allocator<256>; - -static Vmid_allocator &alloc() -{ - static Vmid_allocator * allocator = nullptr; - if (!allocator) { - allocator = unmanaged_singleton(); - - /* reserve VM ID 0 for the hypervisor */ - addr_t id = allocator->alloc(); - assert (id == 0); - } - return *allocator; -} - - Genode::addr_t Vm_session_component::_alloc_vcpu_data(Genode::addr_t ds_addr) { return ds_addr; } -Vm_session_component::Vm_session_component(Rpc_entrypoint &ds_ep, +Vm_session_component::Vm_session_component(Vmid_allocator & vmid_alloc, + Rpc_entrypoint &ds_ep, Resources resources, Label const &, Diag, @@ -127,7 +108,8 @@ Vm_session_component::Vm_session_component(Rpc_entrypoint &ds_ep, _table(*construct_at(_alloc_table())), _table_array(*(new (cma()) Board::Vm_page_table_array([] (void * virt) { return (addr_t)cma().phys_addr(virt);}))), - _id({(unsigned)alloc().alloc(), cma().phys_addr(&_table)}) + _vmid_alloc(vmid_alloc), + _id({(unsigned)_vmid_alloc.alloc(), cma().phys_addr(&_table)}) { /* configure managed VM area */ _map.add_range(0, 0UL - 0x1000); @@ -162,5 +144,5 @@ Vm_session_component::~Vm_session_component() /* free guest-to-host page tables */ destroy(platform().core_mem_alloc(), &_table); destroy(platform().core_mem_alloc(), &_table_array); - alloc().free(_id.id); + _vmid_alloc.free(_id.id); } diff --git a/repos/base-hw/src/core/spec/arm_v7/trustzone/kernel/vm.cc b/repos/base-hw/src/core/spec/arm_v7/trustzone/kernel/vm.cc index 16fddfcb6d..54256ead92 100644 --- a/repos/base-hw/src/core/spec/arm_v7/trustzone/kernel/vm.cc +++ b/repos/base-hw/src/core/spec/arm_v7/trustzone/kernel/vm.cc @@ -28,14 +28,13 @@ Vm::Vm(Irq::Pool & user_irq_pool, Identity & id) : Kernel::Object { *this }, - Cpu_job(Scheduler::Priority::min(), 0), + Cpu_context(cpu, Scheduler::Priority::min(), 0), _user_irq_pool(user_irq_pool), _state(data), _context(context), _id(id), _vcpu_context(cpu) { - affinity(cpu); /* once constructed, exit with a startup exception */ pause(); _state.cpu_exception = Genode::VCPU_EXCEPTION_STARTUP; @@ -46,12 +45,12 @@ Vm::Vm(Irq::Pool & user_irq_pool, Vm::~Vm() {} -void Vm::exception(Cpu & cpu) +void Vm::exception() { switch(_state.cpu_exception) { case Genode::Cpu_state::INTERRUPT_REQUEST: [[fallthrough]]; case Genode::Cpu_state::FAST_INTERRUPT_REQUEST: - _interrupt(_user_irq_pool, cpu.id()); + _interrupt(_user_irq_pool); return; case Genode::Cpu_state::DATA_ABORT: _state.dfar = Cpu::Dfar::read(); @@ -69,19 +68,19 @@ bool secure_irq(unsigned const i); extern "C" void monitor_mode_enter_normal_world(Genode::Vcpu_state&, void*); -void Vm::proceed(Cpu & cpu) +void Vm::proceed() { unsigned const irq = _state.irq_injection; if (irq) { - if (cpu.pic().secure(irq)) { + if (_cpu().pic().secure(irq)) { Genode::raw("Refuse to inject secure IRQ into VM"); } else { - cpu.pic().trigger(irq); + _cpu().pic().trigger(irq); _state.irq_injection = 0; } } - monitor_mode_enter_normal_world(_state, (void*) cpu.stack_start()); + monitor_mode_enter_normal_world(_state, (void*) _cpu().stack_start()); } diff --git a/repos/base-hw/src/core/spec/arm_v7/trustzone/platform_services.cc b/repos/base-hw/src/core/spec/arm_v7/trustzone/platform_services.cc index 2a3919d40a..3d121ef192 100644 --- a/repos/base-hw/src/core/spec/arm_v7/trustzone/platform_services.cc +++ b/repos/base-hw/src/core/spec/arm_v7/trustzone/platform_services.cc @@ -17,7 +17,6 @@ /* core includes */ #include #include -#include #include #include #include @@ -29,10 +28,13 @@ extern int monitor_mode_exception_vector; /* * Add TrustZone specific vm service */ -void Core::platform_add_local_services(Rpc_entrypoint &ep, - Sliced_heap &sliced_heap, - Registry &local_services, - Core::Trace::Source_registry &trace_sources) +void Core::platform_add_local_services(Rpc_entrypoint &ep, + Sliced_heap &sliced_heap, + Registry &services, + Trace::Source_registry &trace_sources, + Ram_allocator &core_ram, + Region_map &core_rm, + Range_allocator &) { static addr_t const phys_base = Platform::core_phys_addr((addr_t)&monitor_mode_exception_vector); @@ -40,8 +42,7 @@ void Core::platform_add_local_services(Rpc_entrypoint &ep, map_local(phys_base, Hw::Mm::system_exception_vector().base, 1, Hw::PAGE_FLAGS_KERN_TEXT); - static Vm_root vm_root(ep, sliced_heap, core_env().ram_allocator(), - core_env().local_rm(), trace_sources); + static Vm_root vm_root(ep, sliced_heap, core_ram, core_rm, trace_sources); - static Core_service vm_service(local_services, vm_root); + static Core_service vm_service(services, vm_root); } diff --git a/repos/base-hw/src/core/spec/arm_v7/trustzone/vm_session_component.cc b/repos/base-hw/src/core/spec/arm_v7/trustzone/vm_session_component.cc index a189cc5d8c..2f64076c47 100644 --- a/repos/base-hw/src/core/spec/arm_v7/trustzone/vm_session_component.cc +++ b/repos/base-hw/src/core/spec/arm_v7/trustzone/vm_session_component.cc @@ -58,7 +58,7 @@ Genode::addr_t Vm_session_component::_alloc_vcpu_data(Genode::addr_t ds_addr) } -Vm_session_component::Vm_session_component(Rpc_entrypoint &ep, +Vm_session_component::Vm_session_component(Vmid_allocator &vmids, Rpc_entrypoint &ep, Resources resources, Label const &, Diag, @@ -74,6 +74,7 @@ Vm_session_component::Vm_session_component(Rpc_entrypoint &ep, _region_map(region_map), _table(*construct_at(_alloc_table())), _table_array(dummy_array()), + _vmid_alloc(vmids), _id({id_alloc++, nullptr}) { if (_id.id) { diff --git a/repos/base-hw/src/core/spec/arm_v7/virtualization/kernel/vm.cc b/repos/base-hw/src/core/spec/arm_v7/virtualization/kernel/vm.cc index c8f5ece998..e533e62257 100644 --- a/repos/base-hw/src/core/spec/arm_v7/virtualization/kernel/vm.cc +++ b/repos/base-hw/src/core/spec/arm_v7/virtualization/kernel/vm.cc @@ -101,7 +101,7 @@ void Board::Vcpu_context::Vm_irq::handle(Vm & vm, unsigned irq) { void Board::Vcpu_context::Vm_irq::occurred() { - Vm *vm = dynamic_cast(&_cpu.scheduled_job()); + Vm *vm = dynamic_cast(&_cpu.current_context()); if (!vm) Genode::raw("VM interrupt while VM is not runnning!"); else handle(*vm, _irq_nr); } @@ -140,14 +140,13 @@ Kernel::Vm::Vm(Irq::Pool & user_irq_pool, Identity & id) : Kernel::Object { *this }, - Cpu_job(Scheduler::Priority::min(), 0), + Cpu_context(cpu, Scheduler::Priority::min(), 0), _user_irq_pool(user_irq_pool), _state(data), _context(context), _id(id), _vcpu_context(cpu) { - affinity(cpu); /* once constructed, exit with a startup exception */ pause(); _state.cpu_exception = Genode::VCPU_EXCEPTION_STARTUP; @@ -164,29 +163,29 @@ Kernel::Vm::~Vm() } -void Kernel::Vm::exception(Cpu & cpu) +void Kernel::Vm::exception() { switch(_state.cpu_exception) { case Genode::Cpu_state::INTERRUPT_REQUEST: case Genode::Cpu_state::FAST_INTERRUPT_REQUEST: - _interrupt(_user_irq_pool, cpu.id()); + _interrupt(_user_irq_pool); break; default: pause(); _context.submit(1); } - if (cpu.pic().ack_virtual_irq(_vcpu_context.pic)) + if (_cpu().pic().ack_virtual_irq(_vcpu_context.pic)) inject_irq(Board::VT_MAINTAINANCE_IRQ); _vcpu_context.vtimer_irq.disable(); } -void Kernel::Vm::proceed(Cpu & cpu) +void Kernel::Vm::proceed() { if (_state.timer.irq) _vcpu_context.vtimer_irq.enable(); - cpu.pic().insert_virtual_irq(_vcpu_context.pic, _state.irqs.virtual_irq); + _cpu().pic().insert_virtual_irq(_vcpu_context.pic, _state.irqs.virtual_irq); /* * the following values have to be enforced by the hypervisor @@ -202,7 +201,7 @@ void Kernel::Vm::proceed(Cpu & cpu) _state.esr_el2 = Cpu::Hstr::init(); _state.hpfar_el2 = Cpu::Hcr::init(); - Hypervisor::switch_world(_state, host_context(cpu)); + Hypervisor::switch_world(_state, host_context(_cpu())); } diff --git a/repos/base-hw/src/core/spec/arm_v8/cpu.cc b/repos/base-hw/src/core/spec/arm_v8/cpu.cc index e64e9f88e9..cca9f9c59e 100644 --- a/repos/base-hw/src/core/spec/arm_v8/cpu.cc +++ b/repos/base-hw/src/core/spec/arm_v8/cpu.cc @@ -22,6 +22,22 @@ using namespace Core; +void Cpu::Context::print(Output &output) const +{ + using namespace Genode; + using Genode::print; + + print(output, "\n"); + for (unsigned i = 0; i < 31; i++) + print(output, " x", i, " = ", Hex(r[i]), "\n"); + print(output, " ip = ", Hex(ip), "\n"); + print(output, " sp = ", Hex(sp), "\n"); + print(output, " esr = ", Hex(esr_el1), "\n"); + print(output, " pstate = ", Hex(pstate), "\n"); + print(output, " mdscr = ", Hex(mdscr_el1)); +} + + Cpu::Context::Context(bool privileged) { Spsr::El::set(pstate, privileged ? 1 : 0); diff --git a/repos/base-hw/src/core/spec/arm_v8/cpu.h b/repos/base-hw/src/core/spec/arm_v8/cpu.h index e4b38183cb..b48e8bec9b 100644 --- a/repos/base-hw/src/core/spec/arm_v8/cpu.h +++ b/repos/base-hw/src/core/spec/arm_v8/cpu.h @@ -79,6 +79,18 @@ struct Core::Cpu : Hw::Arm_64_cpu Fpu_state fpu_state { }; Context(bool privileged); + + void print(Output &output) const; + + void for_each_return_address(Const_byte_range_ptr const &stack, + auto const &fn) + { + void **fp = (void**)r[29]; + while (stack.contains(fp) && stack.contains(fp + 1) && fp[1]) { + fn(fp + 1); + fp = (void **) fp[0]; + } + } }; class Mmu_context diff --git a/repos/base-hw/src/core/spec/arm_v8/kernel/thread.cc b/repos/base-hw/src/core/spec/arm_v8/kernel/thread.cc index f4445005e9..171d0ad985 100644 --- a/repos/base-hw/src/core/spec/arm_v8/kernel/thread.cc +++ b/repos/base-hw/src/core/spec/arm_v8/kernel/thread.cc @@ -27,7 +27,7 @@ using namespace Kernel; void Thread::_call_suspend() { } -void Thread::exception(Cpu & cpu) +void Thread::exception() { switch (regs->exception_type) { case Cpu::RESET: return; @@ -35,7 +35,7 @@ void Thread::exception(Cpu & cpu) case Cpu::IRQ_LEVEL_EL1: [[fallthrough]]; case Cpu::FIQ_LEVEL_EL0: [[fallthrough]]; case Cpu::FIQ_LEVEL_EL1: - _interrupt(_user_irq_pool, cpu.id()); + _interrupt(_user_irq_pool); return; case Cpu::SYNC_LEVEL_EL0: [[fallthrough]]; case Cpu::SYNC_LEVEL_EL1: @@ -94,51 +94,51 @@ void Kernel::Thread::Tlb_invalidation::execute(Cpu &) { } void Thread::Flush_and_stop_cpu::execute(Cpu &) { } -void Cpu::Halt_job::proceed(Kernel::Cpu &) { } + void Cpu::Halt_job::proceed() { } -bool Kernel::Pd::invalidate_tlb(Cpu & cpu, addr_t addr, size_t size) -{ - using namespace Genode; + bool Kernel::Pd::invalidate_tlb(Cpu & cpu, addr_t addr, size_t size) + { + using namespace Genode; - /* only apply to the active cpu */ - if (cpu.id() != Cpu::executing_id()) - return false; + /* 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 + * therefore we have to invalidate it differently + */ + if (addr >= Hw::Mm::supervisor_exception_vector().base) { + for (addr_t end = addr+size; addr < end; addr += get_page_size()) + asm volatile ("tlbi vaae1is, %0" :: "r" (addr >> 12)); + return false; + } + + /** + * Too big mappings will result in long running invalidation loops, + * just invalidate the whole tlb for the ASID then. + */ + if (size > 8 * get_page_size()) { + asm volatile ("tlbi aside1is, %0" + :: "r" ((uint64_t)mmu_regs.id() << 48)); + return false; + } - /** - * The kernel part of the address space is mapped as global - * therefore we have to invalidate it differently - */ - if (addr >= Hw::Mm::supervisor_exception_vector().base) { for (addr_t end = addr+size; addr < end; addr += get_page_size()) - asm volatile ("tlbi vaae1is, %0" :: "r" (addr >> 12)); + asm volatile ("tlbi vae1is, %0" + :: "r" (addr >> 12 | (uint64_t)mmu_regs.id() << 48)); return false; } - /** - * Too big mappings will result in long running invalidation loops, - * just invalidate the whole tlb for the ASID then. - */ - if (size > 8 * get_page_size()) { - asm volatile ("tlbi aside1is, %0" - :: "r" ((uint64_t)mmu_regs.id() << 48)); - return false; - } - for (addr_t end = addr+size; addr < end; addr += get_page_size()) - asm volatile ("tlbi vae1is, %0" - :: "r" (addr >> 12 | (uint64_t)mmu_regs.id() << 48)); - return false; -} + void Thread::proceed() + { + if (!_cpu().active(pd().mmu_regs) && type() != CORE) + _cpu().switch_to(pd().mmu_regs); - -void Thread::proceed(Cpu & cpu) -{ - if (!cpu.active(pd().mmu_regs) && type() != CORE) - cpu.switch_to(pd().mmu_regs); - - kernel_to_user_context_switch((static_cast(&*regs)), - (void*)cpu.stack_start()); + kernel_to_user_context_switch((static_cast(&*regs)), + (void*)_cpu().stack_start()); } diff --git a/repos/base-hw/src/core/spec/arm_v8/virtualization/kernel/vm.cc b/repos/base-hw/src/core/spec/arm_v8/virtualization/kernel/vm.cc index 511a0e99a1..fe5176cffb 100644 --- a/repos/base-hw/src/core/spec/arm_v8/virtualization/kernel/vm.cc +++ b/repos/base-hw/src/core/spec/arm_v8/virtualization/kernel/vm.cc @@ -76,7 +76,7 @@ void Board::Vcpu_context::Vm_irq::handle(Vm & vm, unsigned irq) { void Board::Vcpu_context::Vm_irq::occurred() { - Vm *vm = dynamic_cast(&_cpu.scheduled_job()); + Vm *vm = dynamic_cast(&_cpu.current_context()); if (!vm) Genode::raw("VM interrupt while VM is not runnning!"); else handle(*vm, _irq_nr); } @@ -115,15 +115,13 @@ Vm::Vm(Irq::Pool & user_irq_pool, Identity & id) : Kernel::Object { *this }, - Cpu_job(Scheduler::Priority::min(), 0), + Cpu_context(cpu, Scheduler::Priority::min(), 0), _user_irq_pool(user_irq_pool), _state(data), _context(context), _id(id), _vcpu_context(cpu) { - affinity(cpu); - _state.id_aa64isar0_el1 = Cpu::Id_aa64isar0_el1::read(); _state.id_aa64isar1_el1 = Cpu::Id_aa64isar1_el1::read(); _state.id_aa64mmfr0_el1 = Cpu::Id_aa64mmfr0_el1::read(); @@ -167,14 +165,14 @@ Vm::~Vm() } -void Vm::exception(Cpu & cpu) +void Vm::exception() { switch (_state.exception_type) { case Cpu::IRQ_LEVEL_EL0: [[fallthrough]]; case Cpu::IRQ_LEVEL_EL1: [[fallthrough]]; case Cpu::FIQ_LEVEL_EL0: [[fallthrough]]; case Cpu::FIQ_LEVEL_EL1: - _interrupt(_user_irq_pool, cpu.id()); + _interrupt(_user_irq_pool); break; case Cpu::SYNC_LEVEL_EL0: [[fallthrough]]; case Cpu::SYNC_LEVEL_EL1: [[fallthrough]]; @@ -188,17 +186,17 @@ void Vm::exception(Cpu & cpu) " not implemented!"); }; - if (cpu.pic().ack_virtual_irq(_vcpu_context.pic)) + if (_cpu().pic().ack_virtual_irq(_vcpu_context.pic)) inject_irq(Board::VT_MAINTAINANCE_IRQ); _vcpu_context.vtimer_irq.disable(); } -void Vm::proceed(Cpu & cpu) +void Vm::proceed() { if (_state.timer.irq) _vcpu_context.vtimer_irq.enable(); - cpu.pic().insert_virtual_irq(_vcpu_context.pic, _state.irqs.virtual_irq); + _cpu().pic().insert_virtual_irq(_vcpu_context.pic, _state.irqs.virtual_irq); /* * the following values have to be enforced by the hypervisor @@ -208,7 +206,7 @@ void Vm::proceed(Cpu & cpu) Cpu::Vttbr_el2::Asid::set(vttbr_el2, _id.id); addr_t guest = Hw::Mm::el2_addr(&_state); 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::switch_world(guest, host, pic, vttbr_el2); } diff --git a/repos/base-hw/src/core/spec/riscv/cpu.cc b/repos/base-hw/src/core/spec/riscv/cpu.cc index df9495c743..0d58bef4a6 100644 --- a/repos/base-hw/src/core/spec/riscv/cpu.cc +++ b/repos/base-hw/src/core/spec/riscv/cpu.cc @@ -25,6 +25,47 @@ using Mmu_context = Core::Cpu::Mmu_context; using namespace Core; +void Cpu::Context::print(Output &output) const +{ + using namespace Genode; + using Genode::print; + + print(output, "\n"); + print(output, " ip = ", Hex(ip), "\n"); + print(output, " ra = ", Hex(ra), "\n"); + print(output, " sp = ", Hex(sp), "\n"); + print(output, " gp = ", Hex(gp), "\n"); + print(output, " tp = ", Hex(tp), "\n"); + print(output, " t0 = ", Hex(t0), "\n"); + print(output, " t1 = ", Hex(t1), "\n"); + print(output, " t2 = ", Hex(t2), "\n"); + print(output, " s0 = ", Hex(s0), "\n"); + print(output, " s1 = ", Hex(s1), "\n"); + print(output, " a0 = ", Hex(a0), "\n"); + print(output, " a1 = ", Hex(a1), "\n"); + print(output, " a2 = ", Hex(a2), "\n"); + print(output, " a3 = ", Hex(a3), "\n"); + print(output, " a4 = ", Hex(a4), "\n"); + print(output, " a5 = ", Hex(a5), "\n"); + print(output, " a6 = ", Hex(a6), "\n"); + print(output, " a7 = ", Hex(a7), "\n"); + print(output, " s2 = ", Hex(s2), "\n"); + print(output, " s3 = ", Hex(s3), "\n"); + print(output, " s4 = ", Hex(s4), "\n"); + print(output, " s5 = ", Hex(s5), "\n"); + print(output, " s6 = ", Hex(s6), "\n"); + print(output, " s7 = ", Hex(s7), "\n"); + print(output, " s8 = ", Hex(s8), "\n"); + print(output, " s9 = ", Hex(s9), "\n"); + print(output, " s10 = ", Hex(s10), "\n"); + print(output, " s11 = ", Hex(s11), "\n"); + print(output, " t3 = ", Hex(t3), "\n"); + print(output, " t4 = ", Hex(t4), "\n"); + print(output, " t5 = ", Hex(t5), "\n"); + print(output, " t6 = ", Hex(t6)); +} + + Cpu::Context::Context(bool) { /* diff --git a/repos/base-hw/src/core/spec/riscv/cpu.h b/repos/base-hw/src/core/spec/riscv/cpu.h index 40db57db70..4d8e1a262e 100644 --- a/repos/base-hw/src/core/spec/riscv/cpu.h +++ b/repos/base-hw/src/core/spec/riscv/cpu.h @@ -56,6 +56,11 @@ class Core::Cpu : public Hw::Riscv_cpu struct alignas(8) Context : Genode::Cpu_state { Context(bool); + + void print(Output &output) const; + + void for_each_return_address(Const_byte_range_ptr const &, + auto const &) { } }; class Mmu_context diff --git a/repos/base-hw/src/core/spec/riscv/kernel/interface.cc b/repos/base-hw/src/core/spec/riscv/kernel/interface.cc index 65691bf312..be9b378fbc 100644 --- a/repos/base-hw/src/core/spec/riscv/kernel/interface.cc +++ b/repos/base-hw/src/core/spec/riscv/kernel/interface.cc @@ -49,6 +49,10 @@ using namespace Kernel; CALL_4_FILL_ARG_REGS \ register Call_arg arg_4_reg asm("a4") = arg_4; +#define CALL_6_FILL_ARG_REGS \ + CALL_5_FILL_ARG_REGS \ + register Call_arg arg_5_reg asm("a5") = arg_5; + extern Genode::addr_t _kernel_entry; /* @@ -75,6 +79,7 @@ extern Genode::addr_t _kernel_entry; #define CALL_3_SWI CALL_2_SWI, "r" (arg_2_reg) #define CALL_4_SWI CALL_3_SWI, "r" (arg_3_reg) #define CALL_5_SWI CALL_4_SWI, "r" (arg_4_reg) +#define CALL_6_SWI CALL_5_SWI, "r" (arg_5_reg) /****************** @@ -137,3 +142,16 @@ Call_ret Kernel::call(Call_arg arg_0, asm volatile(CALL_5_SWI : "ra"); return arg_0_reg; } + + +Call_ret Kernel::call(Call_arg arg_0, + Call_arg arg_1, + Call_arg arg_2, + Call_arg arg_3, + Call_arg arg_4, + Call_arg arg_5) +{ + CALL_6_FILL_ARG_REGS + asm volatile(CALL_6_SWI : "ra"); + return arg_0_reg; +} diff --git a/repos/base-hw/src/core/spec/riscv/kernel/thread.cc b/repos/base-hw/src/core/spec/riscv/kernel/thread.cc index fbbd300cc6..1683581262 100644 --- a/repos/base-hw/src/core/spec/riscv/kernel/thread.cc +++ b/repos/base-hw/src/core/spec/riscv/kernel/thread.cc @@ -25,21 +25,21 @@ void Thread::Tlb_invalidation::execute(Cpu &) { } void Thread::Flush_and_stop_cpu::execute(Cpu &) { } -void Cpu::Halt_job::proceed(Kernel::Cpu &) { } +void Cpu::Halt_job::proceed() { } -void Thread::exception(Cpu & cpu) +void Thread::exception() { using Context = Core::Cpu::Context; using Stval = Core::Cpu::Stval; if (regs->is_irq()) { /* cpu-local timer interrupt */ - if (regs->irq() == cpu.timer().interrupt_id()) { - cpu.handle_if_cpu_local_interrupt(cpu.timer().interrupt_id()); + if (regs->irq() == _cpu().timer().interrupt_id()) { + _cpu().handle_if_cpu_local_interrupt(_cpu().timer().interrupt_id()); } else { /* interrupt controller */ - _interrupt(_user_irq_pool, 0); + _interrupt(_user_irq_pool); } return; } @@ -113,7 +113,7 @@ void Kernel::Thread::_call_cache_line_size() } -void Kernel::Thread::proceed(Cpu & cpu) +void Kernel::Thread::proceed() { /* * The sstatus register defines to which privilege level @@ -123,8 +123,8 @@ void Kernel::Thread::proceed(Cpu & cpu) 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); + if (!_cpu().active(pd().mmu_regs) && type() != CORE) + _cpu().switch_to(_pd->mmu_regs); asm volatile("csrw sscratch, %1 \n" "mv x31, %0 \n" diff --git a/repos/base-hw/src/core/spec/x86_64/cpu.cc b/repos/base-hw/src/core/spec/x86_64/cpu.cc index 249b53e5ab..eb70a0e69a 100644 --- a/repos/base-hw/src/core/spec/x86_64/cpu.cc +++ b/repos/base-hw/src/core/spec/x86_64/cpu.cc @@ -37,6 +37,27 @@ struct Pseudo_descriptor } __attribute__((packed)); +void Cpu::Context::print(Output &output) const +{ + using namespace Genode; + using Genode::print; + + print(output, "\n"); + print(output, " ip = ", Hex(ip), "\n"); + print(output, " sp = ", Hex(sp), "\n"); + print(output, " cs = ", Hex(cs), "\n"); + print(output, " ss = ", Hex(ss), "\n"); + print(output, " eflags = ", Hex(eflags), "\n"); + print(output, " rax = ", Hex(rax), "\n"); + print(output, " rbx = ", Hex(rbx), "\n"); + print(output, " rcx = ", Hex(rcx), "\n"); + print(output, " rdx = ", Hex(rdx), "\n"); + print(output, " rdi = ", Hex(rdi), "\n"); + print(output, " rsi = ", Hex(rsi), "\n"); + print(output, " rbp = ", Hex(rbp)); +} + + Cpu::Context::Context(bool core) { eflags = EFLAGS_IF_SET; diff --git a/repos/base-hw/src/core/spec/x86_64/cpu.h b/repos/base-hw/src/core/spec/x86_64/cpu.h index e612cc0321..71b4a6dc38 100644 --- a/repos/base-hw/src/core/spec/x86_64/cpu.h +++ b/repos/base-hw/src/core/spec/x86_64/cpu.h @@ -100,6 +100,18 @@ class Core::Cpu : public Hw::X86_64_cpu }; Context(bool privileged); + + void print(Output &output) const; + + void for_each_return_address(Const_byte_range_ptr const &stack, + auto const &fn) + { + void **fp = (void**)rbp; + while (stack.contains(fp) && stack.contains(fp + 1) && fp[1]) { + fn(fp + 1); + fp = (void **) fp[0]; + } + } } __attribute__((packed)); diff --git a/repos/base-hw/src/core/spec/x86_64/fpu.h b/repos/base-hw/src/core/spec/x86_64/fpu.h index 817a26b716..1a610e4c4f 100644 --- a/repos/base-hw/src/core/spec/x86_64/fpu.h +++ b/repos/base-hw/src/core/spec/x86_64/fpu.h @@ -60,6 +60,7 @@ class Genode::Fpu_context } addr_t fpu_context() const { return _fxsave_addr; } + addr_t fpu_size() const { return sizeof(_fxsave_area); } }; #endif /* _CORE__SPEC__X86_64__FPU_H_ */ diff --git a/repos/base-hw/src/core/spec/x86_64/kernel/thread.cc b/repos/base-hw/src/core/spec/x86_64/kernel/thread.cc index 89d87ad049..057bb229e7 100644 --- a/repos/base-hw/src/core/spec/x86_64/kernel/thread.cc +++ b/repos/base-hw/src/core/spec/x86_64/kernel/thread.cc @@ -55,9 +55,9 @@ void Kernel::Thread::Flush_and_stop_cpu::execute(Cpu &cpu) } -void Kernel::Cpu::Halt_job::Halt_job::proceed(Kernel::Cpu &cpu) +void Kernel::Cpu::Halt_job::Halt_job::proceed() { - switch (cpu.state()) { + switch (_cpu().state()) { case HALT: while (true) { asm volatile ("hlt"); } @@ -83,7 +83,7 @@ void Kernel::Cpu::Halt_job::Halt_job::proceed(Kernel::Cpu &cpu) /* adhere to ACPI specification */ asm volatile ("wbinvd" : : : "memory"); - fadt.suspend(cpu.suspend.typ_a, cpu.suspend.typ_b); + fadt.suspend(_cpu().suspend.typ_a, _cpu().suspend.typ_b); Genode::raw("kernel: unexpected resume"); }); @@ -143,7 +143,7 @@ void Kernel::Thread::_call_suspend() /* single core CPU case */ if (cpu_count == 1) { /* current CPU triggers final ACPI suspend outside kernel lock */ - _cpu->next_state_suspend(); + _cpu().next_state_suspend(); return; } @@ -176,12 +176,12 @@ void Kernel::Thread::_call_cache_line_size() } -void Kernel::Thread::proceed(Cpu & cpu) +void Kernel::Thread::proceed() { - if (!cpu.active(pd().mmu_regs) && type() != CORE) - cpu.switch_to(pd().mmu_regs); + if (!_cpu().active(pd().mmu_regs) && type() != CORE) + _cpu().switch_to(pd().mmu_regs); - cpu.switch_to(*regs); + _cpu().switch_to(*regs); asm volatile("fxrstor (%1) \n" "mov %0, %%rsp \n" diff --git a/repos/base-hw/src/core/spec/x86_64/kernel/thread_exception.cc b/repos/base-hw/src/core/spec/x86_64/kernel/thread_exception.cc index 7551a62f10..0f52cada1f 100644 --- a/repos/base-hw/src/core/spec/x86_64/kernel/thread_exception.cc +++ b/repos/base-hw/src/core/spec/x86_64/kernel/thread_exception.cc @@ -20,7 +20,7 @@ using namespace Kernel; -void Thread::exception(Cpu & cpu) +void Thread::exception() { using Genode::Cpu_state; @@ -45,7 +45,7 @@ void Thread::exception(Cpu & cpu) if (regs->trapno >= Cpu_state::INTERRUPTS_START && regs->trapno <= Cpu_state::INTERRUPTS_END) { - _interrupt(_user_irq_pool, cpu.id()); + _interrupt(_user_irq_pool); return; } diff --git a/repos/base-hw/src/core/spec/x86_64/pic.cc b/repos/base-hw/src/core/spec/x86_64/pic.cc index c4e9073c43..9f5c64a83a 100644 --- a/repos/base-hw/src/core/spec/x86_64/pic.cc +++ b/repos/base-hw/src/core/spec/x86_64/pic.cc @@ -47,6 +47,8 @@ Local_interrupt_controller(Global_interrupt_controller &global_irq_ctrl) void Local_interrupt_controller::init() { + using Hw::outb; + /* Start initialization sequence in cascade mode */ outb(PIC_CMD_MASTER, 0x11); outb(PIC_CMD_SLAVE, 0x11); diff --git a/repos/base-hw/src/core/spec/x86_64/pit.h b/repos/base-hw/src/core/spec/x86_64/pit.h deleted file mode 100644 index 026e293d9a..0000000000 --- a/repos/base-hw/src/core/spec/x86_64/pit.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * \brief Timer driver for core - * \author Adrian-Ken Rueegsegger - * \author Reto Buerki - * \date 2015-02-06 - */ - -/* - * Copyright (C) 2015-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _SRC__CORE__SPEC__ARM__PIT_H_ -#define _SRC__CORE__SPEC__ARM__PIT_H_ - -/* Genode includes */ -#include -#include - -/* core includes */ -#include - -namespace Board { class Timer; } - - -/** - * LAPIC-based timer driver for core - */ -struct Board::Timer: Genode::Mmio -{ - enum { - /* PIT constants */ - PIT_TICK_RATE = 1193182ul, - PIT_SLEEP_MS = 50, - PIT_SLEEP_TICS = (PIT_TICK_RATE / 1000) * PIT_SLEEP_MS, - PIT_CH0_DATA = 0x40, - PIT_CH2_DATA = 0x42, - PIT_CH2_GATE = 0x61, - PIT_MODE = 0x43, - }; - - /* Timer registers */ - struct Tmr_lvt : Register<0x320, 32> - { - struct Vector : Bitfield<0, 8> { }; - struct Delivery : Bitfield<8, 3> { }; - struct Mask : Bitfield<16, 1> { }; - struct Timer_mode : Bitfield<17, 2> { }; - }; - - struct Tmr_initial : Register <0x380, 32> { }; - struct Tmr_current : Register <0x390, 32> { }; - - struct Divide_configuration : Register <0x03e0, 32> - { - struct Divide_value_0_2 : Bitfield<0, 2> { }; - struct Divide_value_2_1 : Bitfield<3, 1> { }; - struct Divide_value : - Genode::Bitset_2 - { - enum { MAX = 6 }; - }; - }; - - struct Calibration_failed : Genode::Exception { }; - - Divide_configuration::access_t divider = 0; - Genode::uint32_t ticks_per_ms = 0; - - /* Measure LAPIC timer frequency using PIT channel 2 */ - Genode::uint32_t pit_calc_timer_freq(void); - - Timer(unsigned); - - void init(); -}; - -#endif /* _SRC__CORE__SPEC__ARM__PIT_H_ */ diff --git a/repos/base-hw/src/core/spec/x86_64/platform_support.cc b/repos/base-hw/src/core/spec/x86_64/platform_support.cc index d7dcb4528c..7778f15010 100644 --- a/repos/base-hw/src/core/spec/x86_64/platform_support.cc +++ b/repos/base-hw/src/core/spec/x86_64/platform_support.cc @@ -59,8 +59,8 @@ void Platform::_init_additional_platform_info(Xml_generator &xml) xml.attribute("vmx", Hw::Virtualization_support::has_vmx()); }); xml.node("tsc", [&] { - xml.attribute("invariant", Hw::Lapic::invariant_tsc()); - xml.attribute("freq_khz", Hw::Lapic::tsc_freq()); + xml.attribute("invariant", Hw::Tsc::invariant_tsc()); + xml.attribute("freq_khz", _boot_info().plat_info.tsc_freq_khz); }); }); } diff --git a/repos/base-hw/src/core/spec/x86_64/pit.cc b/repos/base-hw/src/core/spec/x86_64/timer.cc similarity index 51% rename from repos/base-hw/src/core/spec/x86_64/pit.cc rename to repos/base-hw/src/core/spec/x86_64/timer.cc index bb895b9084..100a6535a9 100644 --- a/repos/base-hw/src/core/spec/x86_64/pit.cc +++ b/repos/base-hw/src/core/spec/x86_64/timer.cc @@ -15,9 +15,6 @@ #include -/* Genode includes */ -#include - /* core includes */ #include #include @@ -25,37 +22,9 @@ using namespace Core; using namespace Kernel; - -uint32_t Board::Timer::pit_calc_timer_freq(void) -{ - uint32_t t_start, t_end; - - /* set channel gate high and disable speaker */ - outb(PIT_CH2_GATE, (uint8_t)((inb(0x61) & ~0x02) | 0x01)); - - /* set timer counter (mode 0, binary count) */ - outb(PIT_MODE, 0xb0); - outb(PIT_CH2_DATA, PIT_SLEEP_TICS & 0xff); - outb(PIT_CH2_DATA, PIT_SLEEP_TICS >> 8); - - write(~0U); - - t_start = read(); - while ((inb(PIT_CH2_GATE) & 0x20) == 0) - { - asm volatile("pause" : : : "memory"); - } - t_end = read(); - - write(0); - - return (t_start - t_end) / PIT_SLEEP_MS; -} - - Board::Timer::Timer(unsigned) : - Mmio({(char *)Platform::mmio_to_virt(Hw::Cpu_memory_map::lapic_phys_base()), Mmio::SIZE}) + Local_apic(Platform::mmio_to_virt(Hw::Cpu_memory_map::lapic_phys_base())) { init(); } @@ -75,28 +44,10 @@ void Board::Timer::init() return; } - /* calibrate LAPIC frequency to fullfill our requirements */ - for (Divide_configuration::access_t div = Divide_configuration::Divide_value::MAX; - div && ticks_per_ms < TIMER_MIN_TICKS_PER_MS; div--) - { - if (!div){ - raw("Failed to calibrate timer frequency"); - throw Calibration_failed(); - } - write((uint8_t)div); - - /* Calculate timer frequency */ - ticks_per_ms = pit_calc_timer_freq(); - divider = div; - } - - /** - * Disable PIT timer channel. This is necessary since BIOS sets up - * channel 0 to fire periodically. - */ - outb(Board::Timer::PIT_MODE, 0x30); - outb(Board::Timer::PIT_CH0_DATA, 0); - outb(Board::Timer::PIT_CH0_DATA, 0); + Platform::apply_with_boot_info([&](auto const &boot_info) { + ticks_per_ms = boot_info.plat_info.lapic_freq_khz; + divider = boot_info.plat_info.lapic_div; + }); } diff --git a/repos/base-hw/src/core/spec/x86_64/timer.h b/repos/base-hw/src/core/spec/x86_64/timer.h new file mode 100644 index 0000000000..a92b6e39d7 --- /dev/null +++ b/repos/base-hw/src/core/spec/x86_64/timer.h @@ -0,0 +1,40 @@ +/* + * \brief Timer driver for core + * \author Adrian-Ken Rueegsegger + * \author Reto Buerki + * \date 2015-02-06 + */ + +/* + * Copyright (C) 2015-2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _SRC__CORE__SPEC__ARM__PIT_H_ +#define _SRC__CORE__SPEC__ARM__PIT_H_ + +/* Genode includes */ +#include + +/* hw includes */ +#include + +namespace Board { class Timer; } + + +/** + * LAPIC-based timer driver for core + */ +struct Board::Timer: public Hw::Local_apic +{ + Divide_configuration::access_t divider = 0; + Genode::uint32_t ticks_per_ms = 0; + + Timer(unsigned); + + void init(); +}; + +#endif /* _SRC__CORE__SPEC__ARM__PIT_H_ */ diff --git a/repos/base-hw/src/core/spec/x86_64/vcpu.h b/repos/base-hw/src/core/spec/x86_64/vcpu.h new file mode 100644 index 0000000000..0d82da6e34 --- /dev/null +++ b/repos/base-hw/src/core/spec/x86_64/vcpu.h @@ -0,0 +1,128 @@ +/* + * \brief Vm_session vCPU + * \author Stefan Kalkowski + * \author Benjamin Lamowski + * \date 2024-11-26 + */ + +/* + * Copyright (C) 2015-2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CORE__VCPU_H_ +#define _CORE__VCPU_H_ + +/* base includes */ +#include +#include + +/* base-hw includes */ +#include +#include + +/* core includes */ +#include +#include + +namespace Core { struct Vcpu; } + + +class Core::Vcpu : public Rpc_object +{ + private: + struct Data_pages { + uint8_t _[Vcpu_data::size()]; + }; + + Kernel::Vm::Identity &_id; + Rpc_entrypoint &_ep; + Vcpu_data _vcpu_data { }; + Kernel_object _kobj { }; + Constrained_ram_allocator &_ram; + Ram_dataspace_capability _ds_cap { }; + Region_map &_region_map; + Affinity::Location _location; + Phys_allocated _vcpu_data_pages; + + constexpr size_t vcpu_state_size() + { + return align_addr(sizeof(Board::Vcpu_state), + get_page_size_log2()); + } + + public: + + Vcpu(Kernel::Vm::Identity &id, + Rpc_entrypoint &ep, + Constrained_ram_allocator &constrained_ram_alloc, + Region_map ®ion_map, + Affinity::Location location) + : + _id(id), + _ep(ep), + _ram(constrained_ram_alloc), + _ds_cap( {_ram.alloc(vcpu_state_size(), Cache::UNCACHED)} ), + _region_map(region_map), + _location(location), + _vcpu_data_pages(ep, constrained_ram_alloc, region_map) + { + Region_map::Attr attr { }; + attr.writeable = true; + _vcpu_data.vcpu_state = _region_map.attach(_ds_cap, attr).convert( + [&] (Region_map::Range range) { return (Vcpu_state *)range.start; }, + [&] (Region_map::Attach_error) -> Vcpu_state * { + error("failed to attach VCPU data within core"); + return nullptr; + }); + + if (!_vcpu_data.vcpu_state) { + _ram.free(_ds_cap); + + throw Attached_dataspace::Region_conflict(); + } + + _vcpu_data.virt_area = &_vcpu_data_pages.obj; + _vcpu_data.phys_addr = _vcpu_data_pages.phys_addr(); + + ep.manage(this); + } + + ~Vcpu() + { + _region_map.detach((addr_t)_vcpu_data.vcpu_state); + _ram.free(_ds_cap); + _ep.dissolve(this); + } + + /******************************* + ** Native_vcpu RPC interface ** + *******************************/ + + Capability state() const { return _ds_cap; } + Native_capability native_vcpu() { return _kobj.cap(); } + + void exception_handler(Signal_context_capability handler) + { + using Genode::warning; + if (!handler.valid()) { + warning("invalid signal"); + return; + } + + if (_kobj.constructed()) { + warning("Cannot register vcpu handler twice"); + return; + } + + unsigned const cpu = _location.xpos(); + + if (!_kobj.create(cpu, (void *)&_vcpu_data, + Capability_space::capid(handler), _id)) + warning("Cannot instantiate vm kernel object, invalid signal context?"); + } +}; + +#endif /* _CORE__VCPU_H_ */ diff --git a/repos/base-hw/src/core/spec/x86_64/virtualization/board.h b/repos/base-hw/src/core/spec/x86_64/virtualization/board.h index 889c6cd2d1..82bae483b7 100644 --- a/repos/base-hw/src/core/spec/x86_64/virtualization/board.h +++ b/repos/base-hw/src/core/spec/x86_64/virtualization/board.h @@ -22,7 +22,6 @@ #include #include #include -#include #include #include @@ -34,10 +33,6 @@ namespace Board { using Vcpu_data = Genode::Vcpu_data; using Vcpu_state = Genode::Vcpu_state; - enum { - VCPU_MAX = 16 - }; - enum Platform_exitcodes : uint64_t { EXIT_NPF = 0xfc, EXIT_INIT = 0xfd, diff --git a/repos/base-hw/src/core/spec/x86_64/virtualization/kernel/svm.cc b/repos/base-hw/src/core/spec/x86_64/virtualization/kernel/svm.cc index 2b5099b415..3e75e67933 100644 --- a/repos/base-hw/src/core/spec/x86_64/virtualization/kernel/svm.cc +++ b/repos/base-hw/src/core/spec/x86_64/virtualization/kernel/svm.cc @@ -267,7 +267,7 @@ void Vmcb::write_vcpu_state(Vcpu_state &state) /* Guest activity state (actv) not used by SVM */ state.actv_state.set_charged(); - state.tsc.charge(Hw::Lapic::rdtsc()); + state.tsc.charge(Hw::Tsc::rdtsc()); state.tsc_offset.charge(v.read()); state.efer.charge(v.read()); diff --git a/repos/base-hw/src/core/spec/x86_64/virtualization/kernel/vm.cc b/repos/base-hw/src/core/spec/x86_64/virtualization/kernel/vm.cc index 750d8f2d5f..3b26635afd 100644 --- a/repos/base-hw/src/core/spec/x86_64/virtualization/kernel/vm.cc +++ b/repos/base-hw/src/core/spec/x86_64/virtualization/kernel/vm.cc @@ -41,15 +41,12 @@ Vm::Vm(Irq::Pool & user_irq_pool, Identity & id) : Kernel::Object { *this }, - Cpu_job(Scheduler::Priority::min(), 0), + Cpu_context(cpu, Scheduler::Priority::min(), 0), _user_irq_pool(user_irq_pool), _state(*data.vcpu_state), _context(context), _id(id), - _vcpu_context(id.id, data) -{ - affinity(cpu); -} + _vcpu_context(id.id, data) { } Vm::~Vm() @@ -57,10 +54,10 @@ Vm::~Vm() } -void Vm::proceed(Cpu & cpu) +void Vm::proceed() { using namespace Board; - cpu.switch_to(*_vcpu_context.regs); + _cpu().switch_to(*_vcpu_context.regs); if (_vcpu_context.exit_reason == EXIT_INIT) { _vcpu_context.regs->trapno = TRAP_VMSKIP; @@ -83,7 +80,7 @@ void Vm::proceed(Cpu & cpu) } -void Vm::exception(Cpu & cpu) +void Vm::exception() { using namespace Board; @@ -121,18 +118,18 @@ void Vm::exception(Cpu & cpu) * it needs to handle an exit. */ if (_vcpu_context.exit_reason == EXIT_PAUSED) - _interrupt(_user_irq_pool, cpu.id()); + _interrupt(_user_irq_pool); else pause = true; break; case Cpu_state::INTERRUPTS_START ... Cpu_state::INTERRUPTS_END: - _interrupt(_user_irq_pool, cpu.id()); + _interrupt(_user_irq_pool); break; case TRAP_VMSKIP: /* vCPU is running for the first time */ - _vcpu_context.initialize(cpu, + _vcpu_context.initialize(_cpu(), reinterpret_cast(_id.table)); - _vcpu_context.tsc_aux_host = cpu.id(); + _vcpu_context.tsc_aux_host = _cpu().id(); /* * We set the artificial startup exit code, stop the * vCPU thread and ask the VMM to handle it. @@ -222,7 +219,7 @@ void Board::Vcpu_context::read_vcpu_state(Vcpu_state &state) if (state.fpu.charged()) { state.fpu.with_state( [&](Vcpu_state::Fpu::State const &fpu) { - memcpy((void *) regs->fpu_context(), &fpu, sizeof(fpu)); + memcpy((void *) regs->fpu_context(), &fpu, regs->fpu_size()); }); } } @@ -233,7 +230,8 @@ void Board::Vcpu_context::write_vcpu_state(Vcpu_state &state) state.exit_reason = (unsigned) exit_reason; state.fpu.charge([&](Vcpu_state::Fpu::State &fpu) { - memcpy(&fpu, (void *) regs->fpu_context(), sizeof(fpu)); + memcpy(&fpu, (void *) regs->fpu_context(), regs->fpu_size()); + return regs->fpu_size(); }); /* SVM will overwrite rax but VMX doesn't. */ @@ -255,7 +253,7 @@ void Board::Vcpu_context::write_vcpu_state(Vcpu_state &state) state.r14.charge(regs->r14); state.r15.charge(regs->r15); - state.tsc.charge(Hw::Lapic::rdtsc()); + state.tsc.charge(Hw::Tsc::rdtsc()); tsc_aux_guest = Cpu::Ia32_tsc_aux::read(); state.tsc_aux.charge(tsc_aux_guest); diff --git a/repos/base-hw/src/core/spec/x86_64/virtualization/kernel/vmx.cc b/repos/base-hw/src/core/spec/x86_64/virtualization/kernel/vmx.cc index 83900e6df4..1fca997910 100644 --- a/repos/base-hw/src/core/spec/x86_64/virtualization/kernel/vmx.cc +++ b/repos/base-hw/src/core/spec/x86_64/virtualization/kernel/vmx.cc @@ -599,7 +599,7 @@ void Vmcs::write_vcpu_state(Genode::Vcpu_state &state) state.actv_state.charge( static_cast(read(E_GUEST_ACTIVITY_STATE))); - state.tsc.charge(Hw::Lapic::rdtsc()); + state.tsc.charge(Hw::Tsc::rdtsc()); state.tsc_offset.charge(read(E_TSC_OFFSET)); state.efer.charge(read(E_GUEST_IA32_EFER)); diff --git a/repos/base-hw/src/core/spec/x86_64/virtualization/platform_services.cc b/repos/base-hw/src/core/spec/x86_64/virtualization/platform_services.cc index 094e10f65f..2cd111f391 100644 --- a/repos/base-hw/src/core/spec/x86_64/virtualization/platform_services.cc +++ b/repos/base-hw/src/core/spec/x86_64/virtualization/platform_services.cc @@ -16,7 +16,6 @@ #include /* core includes */ -#include #include #include #include @@ -27,18 +26,18 @@ * Add x86 specific ioport and virtualization service */ void Core::platform_add_local_services(Rpc_entrypoint &ep, - Sliced_heap &sliced_heap, - Registry &local_services, - Trace::Source_registry &trace_sources) + Sliced_heap &sliced_heap, + Registry &local_services, + Trace::Source_registry &trace_sources, + Ram_allocator &core_ram, + Region_map &core_rm, + Range_allocator &io_port_ranges) { - static Io_port_root io_port_root(*core_env().pd_session(), - platform().io_port_alloc(), sliced_heap); + static Io_port_root io_port_root(io_port_ranges, sliced_heap); - static Vm_root vm_root(ep, sliced_heap, core_env().ram_allocator(), - core_env().local_rm(), trace_sources); + static Vm_root vm_root(ep, sliced_heap, core_ram, core_rm, trace_sources); - static Core_service vm_service(local_services, vm_root); + static Core_service> vm_service(local_services, vm_root); - static Core_service - io_port_ls(local_services, io_port_root); + static Core_service io_port_ls(local_services, io_port_root); } diff --git a/repos/base-hw/src/core/spec/x86_64/virtualization/svm_session_component.h b/repos/base-hw/src/core/spec/x86_64/virtualization/svm_session_component.h new file mode 100644 index 0000000000..5e631f76bd --- /dev/null +++ b/repos/base-hw/src/core/spec/x86_64/virtualization/svm_session_component.h @@ -0,0 +1,234 @@ +/* + * \brief SVM VM session component for 'base-hw' + * \author Stefan Kalkowski + * \author Benjamin Lamowski + * \date 2024-09-20 + */ + +/* + * Copyright (C) 2015-2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CORE__SVM_VM_SESSION_COMPONENT_H_ +#define _CORE__SVM_VM_SESSION_COMPONENT_H_ + +/* base includes */ +#include +#include +#include +#include +#include + +/* base-hw includes */ +#include + +/* core includes */ +#include +#include +#include +#include + +#include +#include +#include +#include + + +namespace Core { class Svm_session_component; } + + +class Core::Svm_session_component +: + public Session_object +{ + private: + + using Vm_page_table = Hw::Hpt; + + using Vm_page_table_array = + Vm_page_table::Allocator::Array; + + + /* + * Noncopyable + */ + Svm_session_component(Svm_session_component const &); + Svm_session_component &operator = (Svm_session_component const &); + + struct Detach : Region_map_detach + { + Svm_session_component &_session; + + Detach(Svm_session_component &session) : _session(session) + { } + + void detach_at(addr_t at) override + { + _session._detach_at(at); + } + + void reserve_and_flush(addr_t at) override + { + _session._reserve_and_flush(at); + } + + void unmap_region(addr_t base, size_t size) override + { + Genode::error(__func__, " unimplemented ", base, " ", size); + } + } _detach { *this }; + + Registry> _vcpus { }; + + Rpc_entrypoint &_ep; + Constrained_ram_allocator _constrained_ram_alloc; + Region_map &_region_map; + Heap _heap; + Phys_allocated _table; + Phys_allocated _table_array; + Guest_memory _memory; + Vmid_allocator &_vmid_alloc; + Kernel::Vm::Identity _id; + uint8_t _remaining_print_count { 10 }; + + void _detach_at(addr_t addr) + { + _memory.detach_at(addr, + [&](addr_t vm_addr, size_t size) { + _table.obj.remove_translation(vm_addr, size, _table_array.obj.alloc()); }); + } + + void _reserve_and_flush(addr_t addr) + { + _memory.reserve_and_flush(addr, [&](addr_t vm_addr, size_t size) { + _table.obj.remove_translation(vm_addr, size, _table_array.obj.alloc()); }); + } + + public: + + Svm_session_component(Vmid_allocator & vmid_alloc, + Rpc_entrypoint &ds_ep, + Resources resources, + Label const &label, + Diag diag, + Ram_allocator &ram_alloc, + Region_map ®ion_map, + Trace::Source_registry &) + : + Session_object(ds_ep, resources, label, diag), + _ep(ds_ep), + _constrained_ram_alloc(ram_alloc, _ram_quota_guard(), _cap_quota_guard()), + _region_map(region_map), + _heap(_constrained_ram_alloc, region_map), + _table(_ep, _constrained_ram_alloc, _region_map), + _table_array(_ep, _constrained_ram_alloc, _region_map, + [] (Phys_allocated &table_array, auto *obj_ptr) { + construct_at(obj_ptr, [&] (void *virt) { + return table_array.phys_addr() + ((addr_t) obj_ptr - (addr_t)virt); + }); + }), + _memory(_constrained_ram_alloc, region_map), + _vmid_alloc(vmid_alloc), + _id({(unsigned)_vmid_alloc.alloc(), (void *)_table.phys_addr()}) + { } + + ~Svm_session_component() + { + _vcpus.for_each([&] (Registered &vcpu) { + destroy(_heap, &vcpu); }); + + _vmid_alloc.free(_id.id); + } + + + /************************** + ** Vm session interface ** + **************************/ + + void attach(Dataspace_capability cap, addr_t guest_phys, Attach_attr attr) override + { + bool out_of_tables = false; + bool invalid_mapping = false; + + auto const &map_fn = [&](addr_t vm_addr, addr_t phys_addr, size_t size) { + Page_flags const pflags { RW, EXEC, USER, NO_GLOBAL, RAM, CACHED }; + + try { + _table.obj.insert_translation(vm_addr, phys_addr, size, pflags, _table_array.obj.alloc()); + } catch(Hw::Out_of_tables &) { + if (_remaining_print_count) { + Genode::error("Translation table needs too much RAM"); + _remaining_print_count--; + } + out_of_tables = true; + } catch(...) { + if (_remaining_print_count) { + Genode::error("Invalid mapping ", Genode::Hex(phys_addr), " -> ", + Genode::Hex(vm_addr), " (", size, ")"); + } + invalid_mapping = true; + } + }; + + if (!cap.valid()) + throw Invalid_dataspace(); + + /* check dataspace validity */ + _ep.apply(cap, [&] (Dataspace_component *ptr) { + if (!ptr) + throw Invalid_dataspace(); + + Dataspace_component &dsc = *ptr; + + Guest_memory::Attach_result result = + _memory.attach(_detach, dsc, guest_phys, attr, map_fn); + + if (out_of_tables) + throw Out_of_ram(); + + if (invalid_mapping) + throw Invalid_dataspace(); + + switch (result) { + case Guest_memory::Attach_result::OK : break; + case Guest_memory::Attach_result::INVALID_DS : throw Invalid_dataspace(); break; + case Guest_memory::Attach_result::OUT_OF_RAM : throw Out_of_ram(); break; + case Guest_memory::Attach_result::OUT_OF_CAPS : throw Out_of_caps(); break; + case Guest_memory::Attach_result::REGION_CONFLICT: throw Region_conflict(); break; + } + }); + } + + void attach_pic(addr_t) override + { } + + void detach(addr_t guest_phys, size_t size) override + { + _memory.detach(guest_phys, size, [&](addr_t vm_addr, size_t size) { + _table.obj.remove_translation(vm_addr, size, _table_array.obj.alloc()); }); + } + + Capability create_vcpu(Thread_capability tcap) override + { + Affinity::Location vcpu_location; + _ep.apply(tcap, [&] (Cpu_thread_component *ptr) { + if (!ptr) return; + vcpu_location = ptr->platform_thread().affinity(); + }); + + Vcpu &vcpu = *new (_heap) + Registered(_vcpus, + _id, + _ep, + _constrained_ram_alloc, + _region_map, + vcpu_location); + + return vcpu.cap(); + } +}; + +#endif /* _CORE__SVM_VM_SESSION_COMPONENT_H_ */ diff --git a/repos/base-hw/src/core/spec/x86_64/virtualization/vm_page_table.h b/repos/base-hw/src/core/spec/x86_64/virtualization/vm_page_table.h deleted file mode 100644 index 96c60ef8f7..0000000000 --- a/repos/base-hw/src/core/spec/x86_64/virtualization/vm_page_table.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * \brief VM page table abstraction between VMX and SVM for x86 - * \author Benjamin Lamowski - * \date 2024-04-23 - */ - -/* - * Copyright (C) 2024 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _CORE__SPEC__PC__VIRTUALIZATION__VM_PAGE_TABLE_H_ -#define _CORE__SPEC__PC__VIRTUALIZATION__VM_PAGE_TABLE_H_ - -#include -#include -#include -#include - -namespace Board { - using namespace Genode; - - struct Vm_page_table - { - /* Both Ept and Hpt need to actually use this allocator */ - using Allocator = Genode::Page_table_allocator<1UL << SIZE_LOG2_4KB>; - - template - struct is_same { - static const bool value = false; - }; - - template - struct is_same { - static const bool value = true; - }; - - static_assert(is_same::value, - "Ept uses different allocator"); - static_assert(is_same::value, - "Hpt uses different allocator"); - - static constexpr size_t ALIGNM_LOG2 = Hw::SIZE_LOG2_4KB; - - enum Virt_type { - VIRT_TYPE_NONE, - VIRT_TYPE_VMX, - VIRT_TYPE_SVM - }; - - union { - Hw::Ept ept; - Hw::Hpt hpt; - }; - - void insert_translation(addr_t vo, - addr_t pa, - size_t size, - Page_flags const & flags, - Allocator & alloc) - { - if (virt_type() == VIRT_TYPE_VMX) - ept.insert_translation(vo, pa, size, flags, alloc); - else if (virt_type() == VIRT_TYPE_SVM) - hpt.insert_translation(vo, pa, size, flags, alloc); - } - - void remove_translation(addr_t vo, size_t size, Allocator & alloc) - { - if (virt_type() == VIRT_TYPE_VMX) - ept.remove_translation(vo, size, alloc); - else if (virt_type() == VIRT_TYPE_SVM) - hpt.remove_translation(vo, size, alloc); - } - - static Virt_type virt_type() { - static Virt_type virt_type { VIRT_TYPE_NONE }; - - if (virt_type == VIRT_TYPE_NONE) { - if (Hw::Virtualization_support::has_vmx()) - virt_type = VIRT_TYPE_VMX; - else if (Hw::Virtualization_support::has_svm()) - virt_type = VIRT_TYPE_SVM; - else - error("Failed to detect Virtualization technology"); - } - - return virt_type; - } - - Vm_page_table() - { - if (virt_type() == VIRT_TYPE_VMX) - Genode::construct_at(this); - else if (virt_type() == VIRT_TYPE_SVM) - Genode::construct_at(this); - } - }; - - using Vm_page_table_array = - Vm_page_table::Allocator::Array; -}; - -#endif /* _CORE__SPEC__PC__VIRTUALIZATION__VM_PAGE_TABLE_H_ */ diff --git a/repos/base-hw/src/core/spec/x86_64/virtualization/vm_session_component.cc b/repos/base-hw/src/core/spec/x86_64/virtualization/vm_session_component.cc deleted file mode 100644 index 1265959696..0000000000 --- a/repos/base-hw/src/core/spec/x86_64/virtualization/vm_session_component.cc +++ /dev/null @@ -1,196 +0,0 @@ -/* - * \brief VM session component for 'base-hw' - * \author Stefan Kalkowski - * \author Benjamin Lamowski - * \date 2015-02-17 - */ - -/* - * Copyright (C) 2015-2024 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -/* Genode includes */ -#include - -/* base internal includes */ -#include - -/* core includes */ -#include -#include -#include -#include -#include - -using namespace Core; - - -static Core_mem_allocator & cma() { - return static_cast(platform().core_mem_alloc()); } - - -void Vm_session_component::_attach(addr_t phys_addr, addr_t vm_addr, size_t size) -{ - using namespace Hw; - - Page_flags pflags { RW, EXEC, USER, NO_GLOBAL, RAM, CACHED }; - - try { - _table.insert_translation(vm_addr, phys_addr, size, pflags, - _table_array.alloc()); - return; - } catch(Hw::Out_of_tables &) { - Genode::error("Translation table needs to much RAM"); - } catch(...) { - Genode::error("Invalid mapping ", Genode::Hex(phys_addr), " -> ", - Genode::Hex(vm_addr), " (", size, ")"); - } -} - - -void Vm_session_component::_attach_vm_memory(Dataspace_component &dsc, - addr_t const vm_addr, - Attach_attr const attribute) -{ - _attach(dsc.phys_addr() + attribute.offset, vm_addr, attribute.size); -} - - -void Vm_session_component::attach_pic(addr_t ) -{ } - - -void Vm_session_component::_detach_vm_memory(addr_t vm_addr, size_t size) -{ - _table.remove_translation(vm_addr, size, _table_array.alloc()); -} - - -void * Vm_session_component::_alloc_table() -{ - /* get some aligned space for the translation table */ - return cma().alloc_aligned(sizeof(Board::Vm_page_table), - Board::Vm_page_table::ALIGNM_LOG2).convert( - [&] (void *table_ptr) { - return table_ptr; }, - - [&] (Range_allocator::Alloc_error) -> void * { - /* XXX handle individual error conditions */ - error("failed to allocate kernel object"); - throw Insufficient_ram_quota(); } - ); -} - - -using Vmid_allocator = Genode::Bit_allocator<256>; - -static Vmid_allocator &alloc() -{ - static Vmid_allocator * allocator = nullptr; - if (!allocator) { - allocator = unmanaged_singleton(); - - /* reserve VM ID 0 for the hypervisor */ - addr_t id = allocator->alloc(); - assert (id == 0); - } - return *allocator; -} - - -Genode::addr_t Vm_session_component::_alloc_vcpu_data(Genode::addr_t ds_addr) -{ - /* - * XXX these allocations currently leak memory on VM Session - * destruction. This cannot be easily fixed because the - * Core Mem Allocator does not implement free(). - * - * Normally we would use constrained_md_ram_alloc to make the allocation, - * but to get the physical address of the pages in virt_area, we need - * to use the Core Mem Allocator. - */ - - Vcpu_data * vcpu_data = (Vcpu_data *) cma() - .try_alloc(sizeof(Board::Vcpu_data)) - .convert( - [&](void *ptr) { return ptr; }, - [&](Range_allocator::Alloc_error) -> void * { - /* XXX handle individual error conditions */ - error("failed to allocate kernel object"); - throw Insufficient_ram_quota(); - }); - - vcpu_data->virt_area = cma() - .alloc_aligned(Vcpu_data::size(), 12) - .convert( - [&](void *ptr) { return ptr; }, - [&](Range_allocator::Alloc_error) -> void * { - /* XXX handle individual error conditions */ - error("failed to allocate kernel object"); - throw Insufficient_ram_quota(); - }); - - vcpu_data->vcpu_state = (Vcpu_state *) ds_addr; - vcpu_data->phys_addr = (addr_t)cma().phys_addr(vcpu_data->virt_area); - - return (Genode::addr_t) vcpu_data; -} - - -Vm_session_component::Vm_session_component(Rpc_entrypoint &ds_ep, - Resources resources, - Label const &, - Diag, - Ram_allocator &ram_alloc, - Region_map ®ion_map, - unsigned, - Trace::Source_registry &) -: - Ram_quota_guard(resources.ram_quota), - Cap_quota_guard(resources.cap_quota), - _ep(ds_ep), - _constrained_md_ram_alloc(ram_alloc, _ram_quota_guard(), _cap_quota_guard()), - _sliced_heap(_constrained_md_ram_alloc, region_map), - _region_map(region_map), - _table(*construct_at(_alloc_table())), - _table_array(*(new (cma()) Board::Vm_page_table_array([] (void * virt) { - return (addr_t)cma().phys_addr(virt);}))), - _id({(unsigned)alloc().alloc(), cma().phys_addr(&_table)}) -{ - /* configure managed VM area */ - _map.add_range(0UL, ~0UL); -} - - -Vm_session_component::~Vm_session_component() -{ - /* detach all regions */ - while (true) { - addr_t out_addr = 0; - - if (!_map.any_block_addr(&out_addr)) - break; - - detach_at(out_addr); - } - - /* free region in allocator */ - for (unsigned i = 0; i < _vcpu_id_alloc; i++) { - if (!_vcpus[i].constructed()) - continue; - - Vcpu & vcpu = *_vcpus[i]; - if (vcpu.ds_cap.valid()) { - _region_map.detach(vcpu.ds_addr); - _constrained_md_ram_alloc.free(vcpu.ds_cap); - } - } - - /* free guest-to-host page tables */ - destroy(platform().core_mem_alloc(), &_table); - destroy(platform().core_mem_alloc(), &_table_array); - alloc().free(_id.id); -} diff --git a/repos/base-hw/src/core/spec/x86_64/virtualization/vmx_session_component.h b/repos/base-hw/src/core/spec/x86_64/virtualization/vmx_session_component.h new file mode 100644 index 0000000000..66538e11bd --- /dev/null +++ b/repos/base-hw/src/core/spec/x86_64/virtualization/vmx_session_component.h @@ -0,0 +1,234 @@ +/* + * \brief VMX VM session component for 'base-hw' + * \author Stefan Kalkowski + * \author Benjamin Lamowski + * \date 2024-09-20 + */ + +/* + * Copyright (C) 2015-2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CORE__VMX_VM_SESSION_COMPONENT_H_ +#define _CORE__VMX_VM_SESSION_COMPONENT_H_ + +/* base includes */ +#include +#include +#include +#include +#include + +/* base-hw includes */ +#include + +/* core includes */ +#include +#include +#include +#include + +#include +#include +#include +#include + + +namespace Core { class Vmx_session_component; } + + +class Core::Vmx_session_component +: + public Session_object +{ + private: + + using Vm_page_table = Hw::Ept; + + using Vm_page_table_array = + Vm_page_table::Allocator::Array; + + + /* + * Noncopyable + */ + Vmx_session_component(Vmx_session_component const &); + Vmx_session_component &operator = (Vmx_session_component const &); + + struct Detach : Region_map_detach + { + Vmx_session_component &_session; + + Detach(Vmx_session_component &session) : _session(session) + { } + + void detach_at(addr_t at) override + { + _session._detach_at(at); + } + + void reserve_and_flush(addr_t at) override + { + _session._reserve_and_flush(at); + } + + void unmap_region(addr_t base, size_t size) override + { + Genode::error(__func__, " unimplemented ", base, " ", size); + } + } _detach { *this }; + + Registry> _vcpus { }; + + Rpc_entrypoint &_ep; + Constrained_ram_allocator _constrained_ram_alloc; + Region_map &_region_map; + Heap _heap; + Phys_allocated _table; + Phys_allocated _table_array; + Guest_memory _memory; + Vmid_allocator &_vmid_alloc; + Kernel::Vm::Identity _id; + uint8_t _remaining_print_count { 10 }; + + void _detach_at(addr_t addr) + { + _memory.detach_at(addr, + [&](addr_t vm_addr, size_t size) { + _table.obj.remove_translation(vm_addr, size, _table_array.obj.alloc()); }); + } + + void _reserve_and_flush(addr_t addr) + { + _memory.reserve_and_flush(addr, [&](addr_t vm_addr, size_t size) { + _table.obj.remove_translation(vm_addr, size, _table_array.obj.alloc()); }); + } + + public: + + Vmx_session_component(Vmid_allocator & vmid_alloc, + Rpc_entrypoint &ds_ep, + Resources resources, + Label const &label, + Diag diag, + Ram_allocator &ram_alloc, + Region_map ®ion_map, + Trace::Source_registry &) + : + Session_object(ds_ep, resources, label, diag), + _ep(ds_ep), + _constrained_ram_alloc(ram_alloc, _ram_quota_guard(), _cap_quota_guard()), + _region_map(region_map), + _heap(_constrained_ram_alloc, region_map), + _table(_ep, _constrained_ram_alloc, _region_map), + _table_array(_ep, _constrained_ram_alloc, _region_map, + [] (Phys_allocated &table_array, auto *obj_ptr) { + construct_at(obj_ptr, [&] (void *virt) { + return table_array.phys_addr() + ((addr_t) obj_ptr - (addr_t)virt); + }); + }), + _memory(_constrained_ram_alloc, region_map), + _vmid_alloc(vmid_alloc), + _id({(unsigned)_vmid_alloc.alloc(), (void *)_table.phys_addr()}) + { } + + ~Vmx_session_component() + { + _vcpus.for_each([&] (Registered &vcpu) { + destroy(_heap, &vcpu); }); + + _vmid_alloc.free(_id.id); + } + + + /************************** + ** Vm session interface ** + **************************/ + + void attach(Dataspace_capability cap, addr_t guest_phys, Attach_attr attr) override + { + bool out_of_tables = false; + bool invalid_mapping = false; + + auto const &map_fn = [&](addr_t vm_addr, addr_t phys_addr, size_t size) { + Page_flags const pflags { RW, EXEC, USER, NO_GLOBAL, RAM, CACHED }; + + try { + _table.obj.insert_translation(vm_addr, phys_addr, size, pflags, _table_array.obj.alloc()); + } catch(Hw::Out_of_tables &) { + if (_remaining_print_count) { + Genode::error("Translation table needs too much RAM"); + _remaining_print_count--; + } + out_of_tables = true; + } catch(...) { + if (_remaining_print_count) { + Genode::error("Invalid mapping ", Genode::Hex(phys_addr), " -> ", + Genode::Hex(vm_addr), " (", size, ")"); + } + invalid_mapping = true; + } + }; + + if (!cap.valid()) + throw Invalid_dataspace(); + + /* check dataspace validity */ + _ep.apply(cap, [&] (Dataspace_component *ptr) { + if (!ptr) + throw Invalid_dataspace(); + + Dataspace_component &dsc = *ptr; + + Guest_memory::Attach_result result = + _memory.attach(_detach, dsc, guest_phys, attr, map_fn); + + if (out_of_tables) + throw Out_of_ram(); + + if (invalid_mapping) + throw Invalid_dataspace(); + + switch (result) { + case Guest_memory::Attach_result::OK : break; + case Guest_memory::Attach_result::INVALID_DS : throw Invalid_dataspace(); break; + case Guest_memory::Attach_result::OUT_OF_RAM : throw Out_of_ram(); break; + case Guest_memory::Attach_result::OUT_OF_CAPS : throw Out_of_caps(); break; + case Guest_memory::Attach_result::REGION_CONFLICT: throw Region_conflict(); break; + } + }); + } + + void attach_pic(addr_t) override + { } + + void detach(addr_t guest_phys, size_t size) override + { + _memory.detach(guest_phys, size, [&](addr_t vm_addr, size_t size) { + _table.obj.remove_translation(vm_addr, size, _table_array.obj.alloc()); }); + } + + Capability create_vcpu(Thread_capability tcap) override + { + Affinity::Location vcpu_location; + _ep.apply(tcap, [&] (Cpu_thread_component *ptr) { + if (!ptr) return; + vcpu_location = ptr->platform_thread().affinity(); + }); + + Vcpu &vcpu = *new (_heap) + Registered(_vcpus, + _id, + _ep, + _constrained_ram_alloc, + _region_map, + vcpu_location); + + return vcpu.cap(); + } +}; + +#endif /* _CORE__VMX_VM_SESSION_COMPONENT_H_ */ diff --git a/repos/base-hw/src/core/spec/x86_64/vm_root.h b/repos/base-hw/src/core/spec/x86_64/vm_root.h new file mode 100644 index 0000000000..ab87d40881 --- /dev/null +++ b/repos/base-hw/src/core/spec/x86_64/vm_root.h @@ -0,0 +1,99 @@ +/* + * \brief x86_64 specific Vm root interface + * \author Stefan Kalkowski + * \author Benjamin Lamowski + * \date 2012-10-08 + */ + +/* + * Copyright (C) 2012-2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CORE__INCLUDE__VM_ROOT_H_ +#define _CORE__INCLUDE__VM_ROOT_H_ + +/* Genode includes */ +#include + +/* Hw includes */ + #include + +/* core includes */ +#include +#include + +#include + +namespace Core { class Vm_root; } + + +class Core::Vm_root : public Root_component> +{ + private: + + Ram_allocator &_ram_allocator; + Region_map &_local_rm; + Trace::Source_registry &_trace_sources; + Vmid_allocator _vmid_alloc { }; + + protected: + + Session_object *_create_session(const char *args) override + { + Session::Resources resources = session_resources_from_args(args); + + if (Hw::Virtualization_support::has_svm()) + return new (md_alloc()) + Svm_session_component(_vmid_alloc, + *ep(), + resources, + session_label_from_args(args), + session_diag_from_args(args), + _ram_allocator, _local_rm, + _trace_sources); + + if (Hw::Virtualization_support::has_vmx()) + return new (md_alloc()) + Vmx_session_component(_vmid_alloc, + *ep(), + session_resources_from_args(args), + session_label_from_args(args), + session_diag_from_args(args), + _ram_allocator, _local_rm, + _trace_sources); + + Genode::error( "No virtualization support detected."); + throw Core::Service_denied(); + } + + void _upgrade_session(Session_object *vm, const char *args) override + { + vm->upgrade(ram_quota_from_args(args)); + vm->upgrade(cap_quota_from_args(args)); + } + + public: + + /** + * Constructor + * + * \param session_ep entrypoint managing vm_session components + * \param md_alloc meta-data allocator to be used by root component + */ + Vm_root(Rpc_entrypoint &session_ep, + Allocator &md_alloc, + Ram_allocator &ram_alloc, + Region_map &local_rm, + Trace::Source_registry &trace_sources) + : + Root_component>(&session_ep, &md_alloc), + _ram_allocator(ram_alloc), + _local_rm(local_rm), + _trace_sources(trace_sources) + { } +}; + +#endif /* _CORE__INCLUDE__VM_ROOT_H_ */ diff --git a/repos/base-hw/src/core/vm_root.h b/repos/base-hw/src/core/vm_root.h new file mode 100644 index 0000000000..ecf7ee509f --- /dev/null +++ b/repos/base-hw/src/core/vm_root.h @@ -0,0 +1,87 @@ +/* + * \brief base-hw specific Vm root interface + * \author Stefan Kalkowski + * \author Benjamin Lamowski + * \date 2012-10-08 + */ + +/* + * Copyright (C) 2012-2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CORE__INCLUDE__VM_ROOT_H_ +#define _CORE__INCLUDE__VM_ROOT_H_ + +/* Genode includes */ +#include + +/* core includes */ +#include + +#include + +namespace Core { class Vm_root; } + +class Core::Vm_root : public Root_component +{ + private: + + Ram_allocator &_ram_allocator; + Region_map &_local_rm; + Trace::Source_registry &_trace_sources; + Vmid_allocator _vmid_alloc { }; + + protected: + + Vm_session_component *_create_session(const char *args) override + { + unsigned priority = 0; + Arg a = Arg_string::find_arg(args, "priority"); + if (a.valid()) { + priority = (unsigned)a.ulong_value(0); + + /* clamp priority value to valid range */ + priority = min((unsigned)Cpu_session::PRIORITY_LIMIT - 1, priority); + } + + return new (md_alloc()) + Vm_session_component(_vmid_alloc, + *ep(), + session_resources_from_args(args), + session_label_from_args(args), + session_diag_from_args(args), + _ram_allocator, _local_rm, priority, + _trace_sources); + } + + void _upgrade_session(Vm_session_component *vm, const char *args) override + { + vm->upgrade(ram_quota_from_args(args)); + vm->upgrade(cap_quota_from_args(args)); + } + + public: + + /** + * Constructor + * + * \param session_ep entrypoint managing vm_session components + * \param md_alloc meta-data allocator to be used by root component + */ + Vm_root(Rpc_entrypoint &session_ep, + Allocator &md_alloc, + Ram_allocator &ram_alloc, + Region_map &local_rm, + Trace::Source_registry &trace_sources) + : + Root_component(&session_ep, &md_alloc), + _ram_allocator(ram_alloc), + _local_rm(local_rm), + _trace_sources(trace_sources) + { } +}; + +#endif /* _CORE__INCLUDE__VM_ROOT_H_ */ diff --git a/repos/base-hw/src/core/vm_session_component.cc b/repos/base-hw/src/core/vm_session_component.cc index a1f4b781f9..064d7eb3a4 100644 --- a/repos/base-hw/src/core/vm_session_component.cc +++ b/repos/base-hw/src/core/vm_session_component.cc @@ -19,7 +19,6 @@ #include #include #include -#include using namespace Core; diff --git a/repos/base-hw/src/core/vm_session_component.h b/repos/base-hw/src/core/vm_session_component.h index 2eea4e9282..2eb6d2e2a9 100644 --- a/repos/base-hw/src/core/vm_session_component.h +++ b/repos/base-hw/src/core/vm_session_component.h @@ -30,6 +30,9 @@ #include #include +#include + + namespace Core { class Vm_session_component; } @@ -88,6 +91,7 @@ class Core::Vm_session_component Region_map &_region_map; Board::Vm_page_table &_table; Board::Vm_page_table_array &_table_array; + Vmid_allocator &_vmid_alloc; Kernel::Vm::Identity _id; unsigned _vcpu_id_alloc { 0 }; @@ -113,8 +117,9 @@ class Core::Vm_session_component using Cap_quota_guard::upgrade; using Rpc_object::cap; - Vm_session_component(Rpc_entrypoint &, Resources, Label const &, - Diag, Ram_allocator &ram, Region_map &, unsigned, + Vm_session_component(Vmid_allocator &, Rpc_entrypoint &, + Resources, Label const &, Diag, + Ram_allocator &ram, Region_map &, unsigned, Trace::Source_registry &); ~Vm_session_component(); @@ -136,7 +141,7 @@ class Core::Vm_session_component void attach_pic(addr_t) override; void detach(addr_t, size_t) override; - Capability create_vcpu(Thread_capability); + Capability create_vcpu(Thread_capability) override; }; #endif /* _CORE__VM_SESSION_COMPONENT_H_ */ diff --git a/repos/base-hw/src/core/vmid_allocator.h b/repos/base-hw/src/core/vmid_allocator.h new file mode 100644 index 0000000000..f6b05eadf5 --- /dev/null +++ b/repos/base-hw/src/core/vmid_allocator.h @@ -0,0 +1,33 @@ +/* + * \brief VM ID allocator + * \author Stefan Kalkowski + * \author Benjamin Lamowski + * \date 2024-11-21 + */ + +/* + * Copyright (C) 2015-2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CORE__VMID_ALLOCATOR_H_ +#define _CORE__VMID_ALLOCATOR_H_ + +#include + +namespace Core { struct Vmid_allocator; } + +struct Core::Vmid_allocator +: Genode::Bit_allocator<256> +{ + Vmid_allocator() + { + /* reserve VM ID 0 for the hypervisor */ + addr_t id = alloc(); + assert (id == 0); + } +}; + +#endif /* _CORE__VMID_ALLOCATOR_H_ */ diff --git a/repos/base-hw/src/include/hw/spec/x86_64/acpi.h b/repos/base-hw/src/include/hw/spec/x86_64/acpi.h index fc261db406..16d65892ad 100644 --- a/repos/base-hw/src/include/hw/spec/x86_64/acpi.h +++ b/repos/base-hw/src/include/hw/spec/x86_64/acpi.h @@ -94,6 +94,8 @@ struct Hw::Acpi_fadt : Genode::Mmio<276> struct Smi_cmd : Register<0x30, 32> { }; struct Acpi_enable : Register<0x34, 8> { }; + struct Pm_tmr_len : Register< 91, 8> { }; + struct Pm1a_cnt_blk : Register < 64, 32> { struct Slp_typ : Bitfield < 10, 3> { }; struct Slp_ena : Bitfield < 13, 1> { }; @@ -123,6 +125,13 @@ struct Hw::Acpi_fadt : Genode::Mmio<276> }; struct Pm1b_cnt_blk_ext_addr : Register < 184 + 4, 64> { }; + struct X_pm_tmr_blk : Register < 208, 32> { + struct Addressspace : Bitfield < 0, 8> { }; + struct Width : Bitfield < 8, 8> { }; + }; + + struct X_pm_tmr_blk_addr : Register < 208 + 4, 64> { }; + struct Gpe0_blk_ext : Register < 220, 32> { struct Addressspace : Bitfield < 0, 8> { }; struct Width : Bitfield < 8, 8> { }; @@ -232,6 +241,45 @@ struct Hw::Acpi_fadt : Genode::Mmio<276> return pm1_a | pm1_b; } + /* see ACPI spec version 6.5 4.8.3.3. Power Management Timer (PM_TMR) */ + uint32_t read_pm_tmr() + { + if (read() != 4) + return 0; + + addr_t const tmr_addr = read(); + + if (!tmr_addr) + return 0; + + uint8_t const tmr_addr_type = + read(); + + /* I/O port address, most likely */ + if (tmr_addr_type == 1) return inl((uint16_t)tmr_addr); + + /* System Memory space address */ + if (tmr_addr_type == 0) return *(uint32_t *)tmr_addr; + + return 0; + } + + uint32_t calibrate_freq_khz(uint32_t sleep_ms, auto get_value_fn, bool reverse = false) + { + unsigned const acpi_timer_freq = 3'579'545; + + uint32_t const initial = read_pm_tmr(); + + if (!initial) return 0; + + uint64_t const t1 = get_value_fn(); + while ((read_pm_tmr() - initial) < (acpi_timer_freq * sleep_ms / 1000)) + asm volatile ("pause":::"memory"); + uint64_t const t2 = get_value_fn(); + + return (uint32_t)((reverse ? (t1 - t2) : (t2 - t1)) / sleep_ms); + } + void write_cnt_blk(unsigned value_a, unsigned value_b) { _write +/* Genode includes */ +#include + struct Hw::Local_apic : Genode::Mmio { struct Id : Register<0x020, 32> { }; @@ -58,6 +61,57 @@ struct Hw::Local_apic : Genode::Mmio struct Destination : Bitfield<24, 8> { }; }; + /* Timer registers */ + struct Tmr_lvt : Register<0x320, 32> + { + struct Vector : Bitfield<0, 8> { }; + struct Delivery : Bitfield<8, 3> { }; + struct Mask : Bitfield<16, 1> { }; + struct Timer_mode : Bitfield<17, 2> { }; + }; + + struct Tmr_initial : Register <0x380, 32> { }; + struct Tmr_current : Register <0x390, 32> { }; + + struct Divide_configuration : Register <0x03e0, 32> + { + struct Divide_value_0_2 : Bitfield<0, 2> { }; + struct Divide_value_2_1 : Bitfield<3, 1> { }; + struct Divide_value : + Genode::Bitset_2 + { + enum { MAX = 6 }; + }; + }; + + struct Calibration { uint32_t freq_khz; uint32_t div; }; + + Calibration calibrate_divider(auto calibration_fn) + { + Calibration result { }; + + /* calibrate LAPIC frequency to fullfill our requirements */ + for (Divide_configuration::access_t div = Divide_configuration::Divide_value::MAX; + div && result.freq_khz < TIMER_MIN_TICKS_PER_MS; div--) { + + if (!div) { + raw("Failed to calibrate Local APIC frequency"); + return { 0, 1 }; + } + write((uint8_t)div); + + write(~0U); + + /* Calculate timer frequency */ + result.freq_khz = calibration_fn(); + result.div = div; + + write(0); + } + + return result; + } + Local_apic(addr_t const addr) : Mmio({(char*)addr, Mmio::SIZE}) {} }; diff --git a/repos/base-hw/src/include/hw/spec/x86_64/cpu.h b/repos/base-hw/src/include/hw/spec/x86_64/cpu.h index 324f37af67..f538c9e65d 100644 --- a/repos/base-hw/src/include/hw/spec/x86_64/cpu.h +++ b/repos/base-hw/src/include/hw/spec/x86_64/cpu.h @@ -118,6 +118,12 @@ struct Hw::X86_64_cpu /* AMD host save physical address */ X86_64_MSR_REGISTER(Amd_vm_hsavepa, 0xC0010117); + + /* Non-architectural MSR used to make lfence serializing */ + X86_64_MSR_REGISTER(Amd_lfence, 0xC0011029, + struct Enable_dispatch_serializing : Bitfield<1, 1> { }; /* Enable lfence dispatch serializing */ + ) + X86_64_MSR_REGISTER(Platform_id, 0x17, struct Bus_ratio : Bitfield<8, 5> { }; /* Bus ratio on Core 2, see SDM 19.7.3 */ ); diff --git a/repos/base-hw/src/include/hw/spec/x86_64/pc_board.h b/repos/base-hw/src/include/hw/spec/x86_64/pc_board.h index be21f64a89..eb39a11c3f 100644 --- a/repos/base-hw/src/include/hw/spec/x86_64/pc_board.h +++ b/repos/base-hw/src/include/hw/spec/x86_64/pc_board.h @@ -40,10 +40,13 @@ struct Hw::Pc_board::Serial : Genode::X86_uart struct Hw::Pc_board::Boot_info { - Acpi_rsdp acpi_rsdp { }; - Framebuffer framebuffer { }; - Genode::addr_t efi_system_table { 0 }; - Genode::addr_t acpi_fadt { 0 }; + Acpi_rsdp acpi_rsdp { }; + Framebuffer framebuffer { }; + Genode::addr_t efi_system_table { 0 }; + Genode::addr_t acpi_fadt { 0 }; + Genode::uint32_t tsc_freq_khz { 0 }; + Genode::uint32_t lapic_freq_khz { 0 }; + Genode::uint32_t lapic_div { 0 }; Boot_info() {} Boot_info(Acpi_rsdp const &acpi_rsdp, diff --git a/repos/base-hw/src/include/hw/spec/x86_64/x86_64.h b/repos/base-hw/src/include/hw/spec/x86_64/x86_64.h index c3a53eacb9..6bca48fe9a 100644 --- a/repos/base-hw/src/include/hw/spec/x86_64/x86_64.h +++ b/repos/base-hw/src/include/hw/spec/x86_64/x86_64.h @@ -22,8 +22,8 @@ namespace Hw { struct Cpu_memory_map; struct Virtualization_support; - class Vendor; - class Lapic; + class Vendor; + struct Tsc; } @@ -107,172 +107,34 @@ public: }; -class Hw::Lapic +struct Hw::Tsc { - private: - static bool _has_tsc_dl() - { - using Cpu = Hw::X86_64_cpu; - - Cpu::Cpuid_1_ecx::access_t ecx = Cpu::Cpuid_1_ecx::read(); - return (bool)Cpu::Cpuid_1_ecx::Tsc_deadline::get(ecx); - } - /* - * Adapted from Christian Prochaska's and Alexander Boettcher's - * implementation for Nova. + * Provide serialized access to the Timestamp Counter * - * For details, see Vol. 3B of the Intel SDM (September 2023): - * 20.7.3 Determining the Processor Base Frequency + * See #5430 for more information. */ - static unsigned _read_tsc_freq() + static Genode::uint64_t rdtsc() + { + Genode::uint32_t low, high; + asm volatile( + "lfence;" + "rdtsc;" + "lfence;" + : "=a"(low), "=d"(high) + : + : "memory" + ); + return (Genode::uint64_t)(high) << 32 | low; + } + + static bool invariant_tsc() { using Cpu = Hw::X86_64_cpu; - if (Vendor::get_vendor_id() != Vendor::INTEL) - return 0; - - unsigned const model = Vendor::get_model(); - unsigned const family = Vendor::get_family(); - - enum - { - Cpu_id_clock = 0x15, - Cpu_id_base_freq = 0x16 - }; - - Cpu::Cpuid_0_eax::access_t eax_0 = Cpu::Cpuid_0_eax::read(); - - /* - * If CPUID leaf 15 is available, return the frequency reported there. - */ - if (eax_0 >= Cpu_id_clock) { - Cpu::Cpuid_15_eax::access_t eax_15 = Cpu::Cpuid_15_eax::read(); - Cpu::Cpuid_15_ebx::access_t ebx_15 = Cpu::Cpuid_15_ebx::read(); - Cpu::Cpuid_15_ecx::access_t ecx_15 = Cpu::Cpuid_15_ecx::read(); - - if (eax_15 && ebx_15) { - if (ecx_15) - return static_cast( - ((Genode::uint64_t)(ecx_15) * ebx_15) / eax_15 / 1000 - ); - - if (family == 6) { - if (model == 0x5c) /* Goldmont */ - return static_cast((19200ull * ebx_15) / eax_15); - if (model == 0x55) /* Xeon */ - return static_cast((25000ull * ebx_15) / eax_15); - } - - if (family >= 6) - return static_cast((24000ull * ebx_15) / eax_15); - } - } - - - /* - * Specific methods for family 6 models - */ - if (family == 6) { - unsigned freq_tsc = 0U; - - if (model == 0x2a || - model == 0x2d || /* Sandy Bridge */ - model >= 0x3a) /* Ivy Bridge and later */ - { - Cpu::Platform_info::access_t platform_info = Cpu::Platform_info::read(); - Genode::uint64_t ratio = Cpu::Platform_info::Ratio::get(platform_info); - freq_tsc = static_cast(ratio * 100000); - } else if (model == 0x1a || - model == 0x1e || - model == 0x1f || - model == 0x2e || /* Nehalem */ - model == 0x25 || - model == 0x2c || - model == 0x2f) /* Xeon Westmere */ - { - Cpu::Platform_info::access_t platform_info = Cpu::Platform_info::read(); - Genode::uint64_t ratio = Cpu::Platform_info::Ratio::get(platform_info); - freq_tsc = static_cast(ratio * 133330); - } else if (model == 0x17 || model == 0xf) { /* Core 2 */ - Cpu::Fsb_freq::access_t fsb_freq = Cpu::Fsb_freq::read(); - Genode::uint64_t freq_bus = Cpu::Fsb_freq::Speed::get(fsb_freq); - - switch (freq_bus) { - case 0b101: freq_bus = 100000; break; - case 0b001: freq_bus = 133330; break; - case 0b011: freq_bus = 166670; break; - case 0b010: freq_bus = 200000; break; - case 0b000: freq_bus = 266670; break; - case 0b100: freq_bus = 333330; break; - case 0b110: freq_bus = 400000; break; - default: freq_bus = 0; break; - } - - Cpu::Platform_id::access_t platform_id = Cpu::Platform_id::read(); - Genode::uint64_t ratio = Cpu::Platform_id::Bus_ratio::get(platform_id); - - freq_tsc = static_cast(freq_bus * ratio); - } - - if (!freq_tsc) - Genode::warning("TSC: family 6 Intel platform info reports bus frequency of 0"); - else - return freq_tsc; - } - - - /* - * Finally, using Processor Frequency Information for a rough estimate - */ - if (eax_0 >= Cpu_id_base_freq) { - Cpu::Cpuid_16_eax::access_t base_mhz = Cpu::Cpuid_16_eax::read(); - - if (base_mhz) { - Genode::warning("TSC: using processor base frequency: ", base_mhz, " MHz"); - return base_mhz * 1000; - } else { - Genode::warning("TSC: CPUID reported processor base frequency of 0"); - } - } - - return 0; + Cpu::Cpuid_80000007_eax::access_t eax = Cpu::Cpuid_80000007_eax::read(); + return Cpu::Cpuid_80000007_eax::Invariant_tsc::get(eax); } - - static unsigned _measure_tsc_freq() - { - const unsigned Tsc_fixed_value = 2400; - - Genode::warning("TSC: calibration not yet implemented, using fixed value of ", Tsc_fixed_value, " MHz"); - /* TODO: implement TSC calibration on AMD */ - return Tsc_fixed_value * 1000; - } - - public: - static Genode::uint64_t rdtsc() - { - Genode::uint32_t low, high; - asm volatile("rdtsc" : "=a"(low), "=d"(high)); - return (Genode::uint64_t)(high) << 32 | low; - } - - static bool invariant_tsc() - { - using Cpu = Hw::X86_64_cpu; - - Cpu::Cpuid_80000007_eax::access_t eax = - Cpu::Cpuid_80000007_eax::read(); - return Cpu::Cpuid_80000007_eax::Invariant_tsc::get(eax); - } - - static unsigned tsc_freq() - { - unsigned freq = _read_tsc_freq(); - if (freq) - return freq; - else - return _measure_tsc_freq(); - } }; struct Hw::Virtualization_support diff --git a/repos/base-hw/src/include/hw/util.h b/repos/base-hw/src/include/hw/util.h index 8774123321..e00cf2f56f 100644 --- a/repos/base-hw/src/include/hw/util.h +++ b/repos/base-hw/src/include/hw/util.h @@ -21,6 +21,7 @@ namespace Hw { using Genode::addr_t; using Genode::size_t; + using Genode::uint32_t; using Genode::get_page_size; using Genode::get_page_size_log2; diff --git a/repos/base-hw/src/lib/base/vm.cc b/repos/base-hw/src/lib/base/vm.cc index e519056b77..0938448c92 100644 --- a/repos/base-hw/src/lib/base/vm.cc +++ b/repos/base-hw/src/lib/base/vm.cc @@ -27,7 +27,6 @@ using namespace Genode; using Exit_config = Vm_connection::Exit_config; -using Call_with_state = Vm_connection::Call_with_state; /**************************** @@ -56,8 +55,7 @@ struct Hw_vcpu : Rpc_client, Noncopyable Hw_vcpu(Env &, Vm_connection &, Vcpu_handler_base &); - - void with_state(Call_with_state &); + void with_state(auto const &); }; @@ -72,7 +70,7 @@ Hw_vcpu::Hw_vcpu(Env &env, Vm_connection &vm, Vcpu_handler_base &handler) } -void Hw_vcpu::with_state(Call_with_state &cw) +void Hw_vcpu::with_state(auto const &fn) { if (Thread::myself() != _ep_handler) { error("vCPU state requested outside of vcpu_handler EP"); @@ -80,7 +78,7 @@ void Hw_vcpu::with_state(Call_with_state &cw) } Kernel::pause_vm(Capability_space::capid(_kernel_vcpu)); - if (cw.call_with_state(_local_state())) + if (fn(_local_state())) Kernel::run_vm(Capability_space::capid(_kernel_vcpu)); } @@ -90,8 +88,7 @@ Capability Hw_vcpu::_create_vcpu(Vm_connection &vm, { Thread &tep { *reinterpret_cast(&handler.rpc_ep()) }; - return vm.with_upgrade([&] { - return vm.call(tep.cap()); }); + return vm.create_vcpu(tep.cap()); } @@ -99,7 +96,10 @@ Capability Hw_vcpu::_create_vcpu(Vm_connection &vm, ** vCPU API ** **************/ -void Vm_connection::Vcpu::_with_state(Call_with_state &cw) { static_cast(_native_vcpu).with_state(cw); } +void Vm_connection::Vcpu::_with_state(With_state::Ft const &fn) +{ + static_cast(_native_vcpu).with_state(fn); +} Vm_connection::Vcpu::Vcpu(Vm_connection &vm, Allocator &alloc, diff --git a/repos/base-hw/src/lib/base/x86_64/vm.cc b/repos/base-hw/src/lib/base/x86_64/vm.cc index eb20d519af..41f5004f96 100644 --- a/repos/base-hw/src/lib/base/x86_64/vm.cc +++ b/repos/base-hw/src/lib/base/x86_64/vm.cc @@ -29,7 +29,6 @@ using namespace Genode; using Exit_config = Vm_connection::Exit_config; -using Call_with_state = Vm_connection::Call_with_state; /**************************** @@ -58,7 +57,7 @@ struct Hw_vcpu : Rpc_client, Noncopyable Hw_vcpu(Env &, Vm_connection &, Vcpu_handler_base &); - void with_state(Call_with_state &); + void with_state(auto const &fn); }; @@ -84,7 +83,7 @@ void Hw_vcpu::_run() } -void Hw_vcpu::with_state(Call_with_state &cw) +void Hw_vcpu::with_state(auto const &fn) { if (Thread::myself() != _ep_handler) { error("vCPU state requested outside of vcpu_handler EP"); @@ -92,7 +91,7 @@ void Hw_vcpu::with_state(Call_with_state &cw) } Kernel::pause_vm(Capability_space::capid(_kernel_vcpu)); - if(cw.call_with_state(_local_state())) + if (fn(_local_state())) _run(); } @@ -102,8 +101,7 @@ Capability Hw_vcpu::_create_vcpu(Vm_connection &vm, { Thread &tep { *reinterpret_cast(&handler.rpc_ep()) }; - return vm.with_upgrade([&] { - return vm.call(tep.cap()); }); + return vm.create_vcpu(tep.cap()); } @@ -111,7 +109,10 @@ Capability Hw_vcpu::_create_vcpu(Vm_connection &vm, ** vCPU API ** **************/ -void Vm_connection::Vcpu::_with_state(Call_with_state &cw) { static_cast(_native_vcpu).with_state(cw); } +void Vm_connection::Vcpu::_with_state(With_state::Ft const &fn) +{ + static_cast(_native_vcpu).with_state(fn); +} Vm_connection::Vcpu::Vcpu(Vm_connection &vm, Allocator &alloc, diff --git a/repos/base-linux/lib/import/import-syscall-linux.mk b/repos/base-linux/lib/import/import-syscall-linux.mk index f873dafb99..93495c4363 100644 --- a/repos/base-linux/lib/import/import-syscall-linux.mk +++ b/repos/base-linux/lib/import/import-syscall-linux.mk @@ -25,3 +25,7 @@ HOST_INC_DIR += /usr/include/aarch64-linux-gnu # CC_OPT += -D_GNU_SOURCE +# +# Enable definition of __STDC_HOSTED__ +# +CC_OPT_FREESTANDING = diff --git a/repos/base-linux/recipes/src/base-linux/hash b/repos/base-linux/recipes/src/base-linux/hash index 1e53e310e6..086788f3a4 100644 --- a/repos/base-linux/recipes/src/base-linux/hash +++ b/repos/base-linux/recipes/src/base-linux/hash @@ -1 +1 @@ -2024-08-28 cbea0285f523b6943841f460fb1dab4471cb72f5 +2024-12-10 bcad5355367be159df49abba05f4975f8391ef4b diff --git a/repos/base-linux/src/core/include/core_region_map.h b/repos/base-linux/src/core/include/core_region_map.h index 98954ef094..a132e3beab 100644 --- a/repos/base-linux/src/core/include/core_region_map.h +++ b/repos/base-linux/src/core/include/core_region_map.h @@ -25,7 +25,9 @@ namespace Core { class Core_region_map; } struct Core::Core_region_map : Region_map_mmap { - Core_region_map(Rpc_entrypoint &) : Region_map_mmap(false) { } + static void init(Rpc_entrypoint &); + + Core_region_map(Rpc_entrypoint &ep) : Region_map_mmap(false) { init(ep); } }; #endif /* _CORE__INCLUDE__CORE_REGION_MAP_H_ */ diff --git a/repos/base-linux/src/core/include/pager.h b/repos/base-linux/src/core/include/pager.h index e41adf9ced..6677181e63 100644 --- a/repos/base-linux/src/core/include/pager.h +++ b/repos/base-linux/src/core/include/pager.h @@ -29,6 +29,8 @@ namespace Core { struct Pager_entrypoint; using Pager_capability = Capability; + + extern void init_page_fault_handling(Rpc_entrypoint &); } diff --git a/repos/base-linux/src/core/include/platform_thread.h b/repos/base-linux/src/core/include/platform_thread.h index c9f2f7e78d..c8c072055d 100644 --- a/repos/base-linux/src/core/include/platform_thread.h +++ b/repos/base-linux/src/core/include/platform_thread.h @@ -69,7 +69,8 @@ class Core::Platform_thread : Noncopyable /** * Constructor */ - Platform_thread(Platform_pd &, size_t, auto const &name, auto...) + Platform_thread(Platform_pd &, Rpc_entrypoint &, Ram_allocator &, Region_map &, + size_t, auto const &name, auto...) : _name(name) { } /** diff --git a/repos/base-linux/src/core/platform.cc b/repos/base-linux/src/core/platform.cc index 12c7849a1b..84b2055a7d 100644 --- a/repos/base-linux/src/core/platform.cc +++ b/repos/base-linux/src/core/platform.cc @@ -20,9 +20,9 @@ #include /* local includes */ -#include "platform.h" -#include "core_env.h" -#include "resource_path.h" +#include +#include +#include /* Linux includes */ #include @@ -160,25 +160,48 @@ void Core::Platform::wait_for_exit() } +void Core::init_page_fault_handling(Rpc_entrypoint &) { } + + /********************************* ** Support for Region_map_mmap ** *********************************/ +static Rpc_entrypoint *_core_ep_ptr; + + +void Core_region_map::init(Rpc_entrypoint &ep) { _core_ep_ptr = &ep; } + + +static auto with_linux_dataspace(Capability ds, + auto const &fn, auto const &missing_fn) -> decltype(missing_fn()) +{ + if (!_core_ep_ptr) + error("missing call of Core_region_map::init"); + + Capability lx_ds = static_cap_cast(ds); + + if (_core_ep_ptr) + return _core_ep_ptr->apply(lx_ds, [&] (Linux_dataspace *ds_ptr) { + return ds_ptr ? fn(*ds_ptr) : missing_fn(); }); + + return missing_fn(); +} + + size_t Region_map_mmap::_dataspace_size(Capability ds_cap) { if (!ds_cap.valid()) return Local_capability::deref(ds_cap)->size(); - /* use local function call if called from the entrypoint */ - return core_env().entrypoint().apply(ds_cap, [] (Dataspace *ds) { - return ds ? ds->size() : 0; }); + return with_linux_dataspace(ds_cap, + [&] (Linux_dataspace &ds) -> size_t { return ds.size(); }, + [&] () /* missing */ -> size_t { return 0; }); } int Region_map_mmap::_dataspace_fd(Capability ds_cap) { - Capability lx_ds_cap = static_cap_cast(ds_cap); - /* * Return a duplicate of the dataspace file descriptor, which will be freed * immediately after mmap'ing the file (see 'Region_map_mmap'). @@ -188,13 +211,19 @@ int Region_map_mmap::_dataspace_fd(Capability ds_cap) * socket descriptor during the RPC handling). When later destroying the * dataspace, the descriptor would unexpectedly be closed again. */ - return core_env().entrypoint().apply(lx_ds_cap, [] (Linux_dataspace *ds) { - return ds ? lx_dup(Capability_space::ipc_cap_data(ds->fd()).dst.socket.value) : -1; }); + + return with_linux_dataspace(ds_cap, + [&] (Linux_dataspace &ds) + { + return lx_dup(Capability_space::ipc_cap_data(ds.fd()).dst.socket.value); + }, + [&] /* missing */ { return -1; }); } bool Region_map_mmap::_dataspace_writeable(Dataspace_capability ds_cap) { - return core_env().entrypoint().apply(ds_cap, [] (Dataspace *ds) { - return ds ? ds->writeable() : false; }); + return with_linux_dataspace(ds_cap, + [&] (Linux_dataspace &ds) { return ds.writeable(); }, + [&] /* missing */ { return false; }); } diff --git a/repos/base-linux/src/core/spec/linux/platform_services.cc b/repos/base-linux/src/core/spec/linux/platform_services.cc index 700f0c1248..db4cff0880 100644 --- a/repos/base-linux/src/core/spec/linux/platform_services.cc +++ b/repos/base-linux/src/core/spec/linux/platform_services.cc @@ -22,5 +22,8 @@ void Core::platform_add_local_services(Rpc_entrypoint &, Sliced_heap &, Registry &, - Trace::Source_registry &) + Trace::Source_registry &, + Ram_allocator &, + Region_map &, + Range_allocator &) { } diff --git a/repos/base-linux/src/core/spec/pc/platform_services.cc b/repos/base-linux/src/core/spec/pc/platform_services.cc index 2a9dae0ddd..825f458d30 100644 --- a/repos/base-linux/src/core/spec/pc/platform_services.cc +++ b/repos/base-linux/src/core/spec/pc/platform_services.cc @@ -14,9 +14,9 @@ /* Genode includes */ #include +#include /* core includes */ -#include #include #include #include @@ -25,17 +25,17 @@ using namespace Core; -void Core::platform_add_local_services(Rpc_entrypoint &, - Sliced_heap &md, - Registry ®, - Core::Trace::Source_registry &) +void Core::platform_add_local_services(Rpc_entrypoint &, + Sliced_heap &md, + Registry &services, + Trace::Source_registry &, + Ram_allocator &, + Region_map &, + Range_allocator &io_port_ranges) { if (!lx_iopl(3)) { - static Io_port_root io_port_root(*core_env().pd_session(), - platform().io_port_alloc(), md); + static Io_port_root io_port_root(io_port_ranges, md); - static Core_service - - io_port_ls(reg, io_port_root); + static Core_service io_port_ls(services, io_port_root); } } diff --git a/repos/base-nova/include/nova/syscall-generic.h b/repos/base-nova/include/nova/syscall-generic.h index 8210e31b7b..0190c1df58 100644 --- a/repos/base-nova/include/nova/syscall-generic.h +++ b/repos/base-nova/include/nova/syscall-generic.h @@ -694,7 +694,7 @@ namespace Nova { } gdtr, idtr; unsigned long long tsc_val, tsc_off, tsc_aux; unsigned long long exit_reason; - uint8_t fpu[512]; + uint8_t fpu[2560]; } __attribute__((packed)); mword_t mr[(4096 - 4 * sizeof(mword_t)) / sizeof(mword_t)]; }; diff --git a/repos/base-nova/patches/allow_ioapic_access.patch b/repos/base-nova/patches/allow_ioapic_access.patch new file mode 100644 index 0000000000..888fe1705a --- /dev/null +++ b/repos/base-nova/patches/allow_ioapic_access.patch @@ -0,0 +1,14 @@ +diff --git a/src/ioapic.cpp b/src/ioapic.cpp +index d3c7991..d357cf3 100644 +--- a/src/ioapic.cpp ++++ b/src/ioapic.cpp +@@ -29,7 +29,8 @@ Ioapic *Ioapic::list; + + Ioapic::Ioapic (Paddr p, unsigned i, unsigned g) : List (list), reg_base ((hwdev_addr -= PAGE_SIZE) | (p & PAGE_MASK)), gsi_base (g), id (i), rid (0) + { +- Pd::kern.Space_mem::delreg (Pd::kern.quota, Pd::kern.mdb_cache, p & ~PAGE_MASK); ++// XXX allow Genode platform driver to access device and take over control ++// Pd::kern.Space_mem::delreg (Pd::kern.quota, Pd::kern.mdb_cache, p & ~PAGE_MASK); + Pd::kern.Space_mem::insert (Pd::kern.quota, reg_base, 0, Hpt::HPT_NX | Hpt::HPT_G | Hpt::HPT_UC | Hpt::HPT_W | Hpt::HPT_P, p & ~PAGE_MASK); + + trace (TRACE_APIC, "APIC:%#lx ID:%#x VER:%#x IRT:%#x PRQ:%u GSI:%u", diff --git a/repos/base-nova/ports/nova.hash b/repos/base-nova/ports/nova.hash index 321dbd6073..fb2c200b86 100644 --- a/repos/base-nova/ports/nova.hash +++ b/repos/base-nova/ports/nova.hash @@ -1 +1 @@ -e8997fb0870b6f8bdcb6da34a9b333ed4a304305 +a807a373a599ea40bebfc36790cf695d5cf89812 diff --git a/repos/base-nova/ports/nova.port b/repos/base-nova/ports/nova.port index 736a144c68..f54be6711e 100644 --- a/repos/base-nova/ports/nova.port +++ b/repos/base-nova/ports/nova.port @@ -4,7 +4,7 @@ DOWNLOADS := nova.git # r10 branch URL(nova) := https://github.com/alex-ab/NOVA.git -REV(nova) := bca1aa3553d8c5df4f4b6ed5a2ee72f69bdf7a7f +REV(nova) := 62420ca0cc6e648946bab553045e9334a408b982 DIR(nova) := src/kernel/nova PATCHES := $(sort $(wildcard $(REP_DIR)/patches/*.patch)) diff --git a/repos/base-nova/recipes/api/base-nova/hash b/repos/base-nova/recipes/api/base-nova/hash index e82c972d7e..9c9994f2f2 100644 --- a/repos/base-nova/recipes/api/base-nova/hash +++ b/repos/base-nova/recipes/api/base-nova/hash @@ -1 +1 @@ -2024-08-28 80901e07dc386b2dcc259a85ea60fdd2bb4c1b6a +2024-10-07 d1a751a3b41d145c3a97b3431ae1f006050fee10 diff --git a/repos/base-nova/recipes/src/base-nova/hash b/repos/base-nova/recipes/src/base-nova/hash index 9957562e69..02d5a1981a 100644 --- a/repos/base-nova/recipes/src/base-nova/hash +++ b/repos/base-nova/recipes/src/base-nova/hash @@ -1 +1 @@ -2024-08-28 2bdb13a64a152f7cb2601222245eb6f132d5325b +2024-12-10 bb446406fbb1173c3f243fe323d5cad8423ff958 diff --git a/repos/base-nova/src/core/include/pager.h b/repos/base-nova/src/core/include/pager.h index db18f28bcd..5a07f48b1d 100644 --- a/repos/base-nova/src/core/include/pager.h +++ b/repos/base-nova/src/core/include/pager.h @@ -36,6 +36,8 @@ namespace Core { class Exception_handlers; using Pager_capability = Capability; + + extern void init_page_fault_handling(Rpc_entrypoint &); } @@ -91,7 +93,6 @@ class Core::Pager_object : public Object_pool::Entry DEAD = 0x2U, SINGLESTEP = 0x4U, SIGNAL_SM = 0x8U, - DISSOLVED = 0x10U, SUBMIT_SIGNAL = 0x20U, BLOCKED_PAUSE_SM = 0x40U, MIGRATE = 0x80U @@ -115,9 +116,6 @@ class Core::Pager_object : public Object_pool::Entry inline void mark_signal_sm() { _status |= SIGNAL_SM; } inline bool has_signal_sm() { return _status & SIGNAL_SM; } - inline void mark_dissolved() { _status |= DISSOLVED; } - inline bool dissolved() { return _status & DISSOLVED; } - inline bool to_submit() { return _status & SUBMIT_SIGNAL; } inline void submit_signal() { _status |= SUBMIT_SIGNAL; } inline void reset_submit() { _status &= (uint8_t)(~SUBMIT_SIGNAL); } diff --git a/repos/base-nova/src/core/include/platform_thread.h b/repos/base-nova/src/core/include/platform_thread.h index 2d0bb4ae41..49428a89b8 100644 --- a/repos/base-nova/src/core/include/platform_thread.h +++ b/repos/base-nova/src/core/include/platform_thread.h @@ -93,10 +93,9 @@ class Core::Platform_thread /** * Constructor */ - Platform_thread(Platform_pd &, size_t quota, char const *name, - unsigned priority, - Affinity::Location affinity, - addr_t utcb); + Platform_thread(Platform_pd &, Rpc_entrypoint &, Ram_allocator &, Region_map &, + size_t quota, char const *name, unsigned priority, + Affinity::Location affinity, addr_t utcb); /** * Destructor diff --git a/repos/base-nova/src/core/include/vm_session_component.h b/repos/base-nova/src/core/include/vm_session_component.h index e86e6636b7..c2eb55a54a 100644 --- a/repos/base-nova/src/core/include/vm_session_component.h +++ b/repos/base-nova/src/core/include/vm_session_component.h @@ -24,6 +24,7 @@ /* core includes */ #include +#include namespace Core { class Vm_session_component; } @@ -173,7 +174,7 @@ class Core::Vm_session_component ** Vm session interface ** **************************/ - Capability create_vcpu(Thread_capability); + Capability create_vcpu(Thread_capability) override; void attach_pic(addr_t) override { /* unused on NOVA */ } void attach(Dataspace_capability, addr_t, Attach_attr) override; diff --git a/repos/base-nova/src/core/io_mem_session_support.cc b/repos/base-nova/src/core/io_mem_session_support.cc index 4bba83ebdc..d249d0368e 100644 --- a/repos/base-nova/src/core/io_mem_session_support.cc +++ b/repos/base-nova/src/core/io_mem_session_support.cc @@ -23,4 +23,7 @@ using namespace Core; void Io_mem_session_component::_unmap_local(addr_t, size_t, addr_t) { } -addr_t Io_mem_session_component::_map_local(addr_t, size_t) { return 0; } +Io_mem_session_component::Map_local_result Io_mem_session_component::_map_local(addr_t, size_t) +{ + return { .core_local_addr = 0, .success = true }; +} diff --git a/repos/base-nova/src/core/pager.cc b/repos/base-nova/src/core/pager.cc index 1f8c4c7820..12e4ada647 100644 --- a/repos/base-nova/src/core/pager.cc +++ b/repos/base-nova/src/core/pager.cc @@ -25,7 +25,6 @@ #include #include #include -#include /* NOVA includes */ #include @@ -38,6 +37,11 @@ using namespace Core; using namespace Nova; +static Rpc_entrypoint *_core_ep_ptr; + +void Core::init_page_fault_handling(Rpc_entrypoint &ep) { _core_ep_ptr = &ep; } + + /** * Pager threads - one thread per CPU */ @@ -397,9 +401,8 @@ void Pager_object::_invoke_handler(Pager_object &obj) Nova::Crd const cap(item.crd); /* valid item which got translated ? */ - if (!cap.is_null() && !item.is_del()) { - Rpc_entrypoint &e = core_env().entrypoint(); - e.apply(cap.base(), + if (!cap.is_null() && !item.is_del() && _core_ep_ptr) { + _core_ep_ptr->apply(cap.base(), [&] (Cpu_thread_component *source) { if (!source) return; @@ -523,8 +526,6 @@ uint8_t Pager_object::_unsynchronized_client_recall(bool get_state_and_block) void Pager_object::cleanup_call() { - _state.mark_dissolved(); - /* revoke ec and sc cap of client before the sm cap */ if (_state.sel_client_ec != Native_thread::INVALID_INDEX) revoke(Obj_crd(_state.sel_client_ec, 2)); @@ -750,10 +751,6 @@ void Pager_object::migrate(Affinity::Location location) Pager_object::~Pager_object() { - /* sanity check that object got dissolved already - otherwise bug */ - if (!_state.dissolved()) - nova_die(); - /* revoke portal used for the cleanup call and sm cap for blocking state */ revoke(Obj_crd(_selectors, 2)); cap_map().remove(_selectors, 2, false); @@ -993,13 +990,6 @@ const char * Pager_object::client_pd() const Pager_entrypoint::Pager_entrypoint(Rpc_cap_factory &) { - /* sanity check for pager threads */ - if (kernel_hip().cpu_max() > PAGER_CPUS) { - error("kernel supports more CPUs (", kernel_hip().cpu_max(), ") " - "than Genode (", (unsigned)PAGER_CPUS, ")"); - nova_die(); - } - /* detect enabled CPUs and create per CPU a pager thread */ platform_specific().for_each_location([&](Affinity::Location &location) { unsigned const pager_index = platform_specific().pager_index(location); @@ -1008,6 +998,12 @@ Pager_entrypoint::Pager_entrypoint(Rpc_cap_factory &) if (!kernel_hip().is_cpu_enabled(kernel_cpu_id)) return; + /* sanity check for pager threads */ + if (pager_index >= PAGER_CPUS) { + error("too many CPUs for pager"); + return; + } + pager_threads[pager_index].construct(location); }); } diff --git a/repos/base-nova/src/core/platform_services.cc b/repos/base-nova/src/core/platform_services.cc index f0df7a79a5..cc53dc48c0 100644 --- a/repos/base-nova/src/core/platform_services.cc +++ b/repos/base-nova/src/core/platform_services.cc @@ -12,7 +12,6 @@ */ /* core includes */ -#include #include #include #include @@ -23,14 +22,15 @@ void Core::platform_add_local_services(Rpc_entrypoint &ep, Sliced_heap &heap, Registry &services, - Trace::Source_registry &trace_sources) + Trace::Source_registry &trace_sources, + Ram_allocator &core_ram, + Region_map &core_rm, + Range_allocator &io_port_ranges) { - static Vm_root vm_root(ep, heap, core_env().ram_allocator(), - core_env().local_rm(), trace_sources); + static Vm_root vm_root(ep, heap, core_ram, core_rm, trace_sources); static Core_service vm(services, vm_root); - static Io_port_root io_root(*core_env().pd_session(), - platform().io_port_alloc(), heap); + static Io_port_root io_root(io_port_ranges, heap); static Core_service io_port(services, io_root); } diff --git a/repos/base-nova/src/core/platform_thread.cc b/repos/base-nova/src/core/platform_thread.cc index 5175812aae..e367f7741c 100644 --- a/repos/base-nova/src/core/platform_thread.cc +++ b/repos/base-nova/src/core/platform_thread.cc @@ -343,7 +343,8 @@ void Platform_thread::thread_type(Cpu_session::Native_cpu::Thread_type thread_ty } -Platform_thread::Platform_thread(Platform_pd &pd, size_t, const char *name, +Platform_thread::Platform_thread(Platform_pd &pd, Rpc_entrypoint &, Ram_allocator &, + Region_map &, size_t, const char *name, unsigned prio, Affinity::Location affinity, addr_t) : _pd(pd), _pager(0), _id_base(cap_map().insert(2)), diff --git a/repos/base-nova/src/core/vm_session_component.cc b/repos/base-nova/src/core/vm_session_component.cc index b137080ecd..1ae8882ebf 100644 --- a/repos/base-nova/src/core/vm_session_component.cc +++ b/repos/base-nova/src/core/vm_session_component.cc @@ -19,7 +19,6 @@ #include /* core includes */ -#include #include #include #include diff --git a/repos/base-nova/src/lib/base/vm.cc b/repos/base-nova/src/lib/base/vm.cc index bd2c407ded..6f57fba4ea 100644 --- a/repos/base-nova/src/lib/base/vm.cc +++ b/repos/base-nova/src/lib/base/vm.cc @@ -35,7 +35,6 @@ using namespace Genode; using Exit_config = Vm_connection::Exit_config; -using Call_with_state = Vm_connection::Call_with_state; /****************************** @@ -163,7 +162,7 @@ struct Nova_vcpu : Rpc_client, Noncopyable call(); } - void with_state(Call_with_state &cw); + void with_state(auto const &fn); }; @@ -177,7 +176,10 @@ void Nova_vcpu::_read_nova_state(Nova::Utcb &utcb) if (utcb.mtd & Nova::Mtd::FPU) { _vcpu_state.fpu.charge([&] (Vcpu_state::Fpu::State &fpu) { - memcpy(&fpu, utcb.fpu, sizeof(fpu)); + auto const fpu_size = unsigned(min(_vcpu_state.fpu.size(), + sizeof(utcb.fpu))); + memcpy(&fpu, utcb.fpu, fpu_size); + return fpu_size; }); } @@ -598,7 +600,7 @@ void Nova_vcpu::_handle_exit(Nova::Utcb &utcb) } -void Nova_vcpu::with_state(Call_with_state &cw) +void Nova_vcpu::with_state(auto const &fn) { Thread *myself = Thread::myself(); bool remote = (_dispatching != myself); @@ -623,7 +625,7 @@ void Nova_vcpu::with_state(Call_with_state &cw) _read_nova_state(utcb); } - _resume = cw.call_with_state(_vcpu_state); + _resume = fn(_vcpu_state); if (remote) { _write_nova_state(utcb); @@ -716,8 +718,7 @@ Capability Nova_vcpu::_create_vcpu(Vm_connection &v { Thread &tep { *reinterpret_cast(&handler.rpc_ep()) }; - return vm.with_upgrade([&] { - return vm.call(tep.cap()); }); + return vm.create_vcpu(tep.cap()); } @@ -760,7 +761,10 @@ Nova_vcpu::Nova_vcpu(Env &env, Vm_connection &vm, Allocator &alloc, ** vCPU API ** **************/ -void Vm_connection::Vcpu::_with_state(Call_with_state &cw) { static_cast(_native_vcpu).with_state(cw); } +void Vm_connection::Vcpu::_with_state(With_state::Ft const &fn) +{ + static_cast(_native_vcpu).with_state(fn); +} Vm_connection::Vcpu::Vcpu(Vm_connection &vm, Allocator &alloc, diff --git a/repos/base-nova/src/test/nova/main.cc b/repos/base-nova/src/test/nova/main.cc index 2408639b82..060b5ce4c3 100644 --- a/repos/base-nova/src/test/nova/main.cc +++ b/repos/base-nova/src/test/nova/main.cc @@ -297,27 +297,27 @@ void test_pat(Genode::Env &env) Xml_node const hardware = platform_info.xml().sub_node("hardware"); uint64_t const tsc_freq = hardware.sub_node("tsc").attribute_value("freq_khz", 1ULL); - enum { DS_ORDER = 12, PAGE_4K = 12 }; + enum { DS_ORDER = 12, PAGE_4K = 12, DS_SIZE = 1ul << (DS_ORDER + PAGE_4K) }; - Attached_dataspace ds { env.rm(), env.ram().alloc (1 << (DS_ORDER + PAGE_4K), - WRITE_COMBINED) }; - addr_t const map_addr = addr_t(ds.local_addr()); + Genode::Rm_connection rm(env); + Genode::Region_map_client rm_unused(rm.create(DS_SIZE)); - enum { STACK_SIZE = 4096 }; + Attached_dataspace ds_wc { env.rm(), env.ram().alloc (DS_SIZE, WRITE_COMBINED) }; + Attached_dataspace ds { env.rm(), env.ram().alloc (DS_SIZE) }; + Attached_dataspace remap { env.rm(), rm_unused.dataspace() }; - static Rpc_entrypoint ep(&env.pd(), STACK_SIZE, "rpc_ep_pat", + auto const memory = addr_t(ds .local_addr()); + auto const memory_wc = addr_t(ds_wc.local_addr()); + auto const memory_remap = addr_t(remap.local_addr()); + + static Rpc_entrypoint ep(&env.pd(), 4096 /* STACK */, "rpc_ep_pat", Affinity::Location()); - Genode::Rm_connection rm(env); - Genode::Region_map_client rm_free_area(rm.create(1 << (DS_ORDER + PAGE_4K))); - - Attached_dataspace remap { env.rm(), rm_free_area.dataspace() }; - - addr_t const remap_addr = addr_t(remap.local_addr()); - /* trigger mapping of whole area */ - for (addr_t i = map_addr; i < map_addr + (1 << (DS_ORDER + PAGE_4K)); i += (1 << PAGE_4K)) - touch_read(reinterpret_cast(map_addr)); + for (auto offset = 0; offset < DS_SIZE; offset += (1u << PAGE_4K)) { + touch_read_write(reinterpret_cast(memory_wc + offset)); + touch_read_write(reinterpret_cast( memory + offset)); + } /* * Establish memory mapping with evilly wrong mapping attributes @@ -331,8 +331,8 @@ void test_pat(Genode::Env &env) native_pd.alloc_rpc_cap(thread_cap, (addr_t)portal_entry, 0 /* MTD */); Nova::Rights const all(true, true, true); - Nova::Mem_crd const rcv_crd(remap_addr >> PAGE_4K, DS_ORDER, all); - Nova::Mem_crd const snd_crd(map_addr >> PAGE_4K, DS_ORDER, all); + Nova::Mem_crd const rcv_crd(memory_remap >> PAGE_4K, DS_ORDER, all); + Nova::Mem_crd const snd_crd(memory_wc >> PAGE_4K, DS_ORDER, all); Nova::Crd const old_crd = utcb.crd_rcv; utcb.crd_rcv = rcv_crd; @@ -348,36 +348,45 @@ void test_pat(Genode::Env &env) } /* sanity check - touch re-mapped area */ - for (addr_t i = remap_addr; i < remap_addr + (1 << (DS_ORDER + PAGE_4K)); i += (1 << PAGE_4K)) - touch_read(reinterpret_cast(remap_addr)); + for (auto offset = 0; offset < DS_SIZE; offset += (1 << PAGE_4K)) + touch_read_write(reinterpret_cast(memory_remap + offset)); /* * measure time to write to the memory */ - memset(reinterpret_cast(map_addr), 0, 1 << (DS_ORDER + PAGE_4K)); + memset(reinterpret_cast(memory), 0, DS_SIZE); + Trace::Timestamp normal_start = Trace::timestamp(); + memset(reinterpret_cast(memory), 0, DS_SIZE); + Trace::Timestamp normal_end = Trace::timestamp(); + + memset(reinterpret_cast(memory_wc), 0, DS_SIZE); Trace::Timestamp map_start = Trace::timestamp(); - memset(reinterpret_cast(map_addr), 0, 1 << (DS_ORDER + PAGE_4K)); + memset(reinterpret_cast(memory_wc), 0, DS_SIZE); Trace::Timestamp map_end = Trace::timestamp(); - memset(reinterpret_cast(remap_addr), 0, 1 << (DS_ORDER + PAGE_4K)); + memset(reinterpret_cast(memory_remap), 0, DS_SIZE); Trace::Timestamp remap_start = Trace::timestamp(); - memset(reinterpret_cast(remap_addr), 0, 1 << (DS_ORDER + PAGE_4K)); + memset(reinterpret_cast(memory_remap), 0, DS_SIZE); Trace::Timestamp remap_end = Trace::timestamp(); - Trace::Timestamp map_run = map_end - map_start; - Trace::Timestamp remap_run = remap_end - remap_start; + auto normal_run = normal_end - normal_start; + auto map_run = map_end - map_start; + auto remap_run = remap_end - remap_start; - Trace::Timestamp diff_run = map_run > remap_run ? map_run - remap_run : remap_run - map_run; + auto diff_run = map_run > remap_run ? map_run - remap_run : remap_run - map_run; - if (check_pat && diff_run * 100 / tsc_freq) { + log("memory non writecombined ", normal_run * 1000 / tsc_freq, " us"); + log("memory writecombined ", map_run * 1000 / tsc_freq, " us"); + log("memory writecombined remapped ", remap_run * 1000 / tsc_freq, " us"); + log("variance writecombined tests ", diff_run * 1000 / tsc_freq, " us"); + + if (check_pat && diff_run * 10 / tsc_freq) { failed ++; - error("map=", Hex(map_run), " remap=", Hex(remap_run), " --> " - "diff=", Hex(diff_run), " freq_tsc=", tsc_freq, " ", - diff_run * 1000 / tsc_freq, " us"); + error("PAT test considered failed - time difference above 100us"); } - Nova::revoke(Nova::Mem_crd(remap_addr >> PAGE_4K, DS_ORDER, all)); + Nova::revoke(Nova::Mem_crd(memory_remap >> PAGE_4K, DS_ORDER, all)); } void test_server_oom(Genode::Env &env) diff --git a/repos/base-okl4/recipes/src/base-okl4/hash b/repos/base-okl4/recipes/src/base-okl4/hash index 30faaab6bc..596a952b40 100644 --- a/repos/base-okl4/recipes/src/base-okl4/hash +++ b/repos/base-okl4/recipes/src/base-okl4/hash @@ -1 +1 @@ -2024-08-28 4b22e47966d13c2de61a2d7349bd8fa83520fd1c +2024-12-10 ed00306cd3e097b95bf2cbd0e9238ccb22d1f0c2 diff --git a/repos/base-okl4/src/core/include/platform_thread.h b/repos/base-okl4/src/core/include/platform_thread.h index b0a47f8982..e515e24ab8 100644 --- a/repos/base-okl4/src/core/include/platform_thread.h +++ b/repos/base-okl4/src/core/include/platform_thread.h @@ -42,14 +42,14 @@ class Core::Platform_thread int _thread_id = THREAD_INVALID; /* plain thread number */ - Okl4::L4_ThreadId_t _l4_thread_id; /* L4 thread ID */ + Okl4::L4_ThreadId_t _l4_thread_id = Okl4::L4_nilthread; char _name[32]; /* thread name that will be registered at the kernel debugger */ Platform_pd &_pd; - unsigned _priority; /* thread priority */ - Pager_object *_pager; + unsigned _priority = 0; /* thread priority */ + Pager_object *_pager = nullptr; bool _bound_to_pd = false; @@ -61,16 +61,24 @@ class Core::Platform_thread /** * Constructor */ - Platform_thread(Platform_pd &pd, size_t, const char *name, - unsigned priority, - Affinity::Location, - addr_t utcb); + Platform_thread(Platform_pd &pd, Rpc_entrypoint &, Ram_allocator &, + Region_map &, size_t, const char *name, + unsigned prio, Affinity::Location, addr_t) + : + _pd(pd), _priority(prio) + { + copy_cstring(_name, name, sizeof(_name)); + _bound_to_pd = pd.bind_thread(*this); + } /** * Constructor used for core-internal threads */ - Platform_thread(Platform_pd &pd, char const *name) - : Platform_thread(pd, 0, name, 0, Affinity::Location(), 0) { } + Platform_thread(Platform_pd &pd, char const *name) : _pd(pd) + { + copy_cstring(_name, name, sizeof(_name)); + _bound_to_pd = pd.bind_thread(*this); + } /** * Destructor diff --git a/repos/base-okl4/src/core/io_mem_session_support.cc b/repos/base-okl4/src/core/io_mem_session_support.cc index 6b0422ea42..b552e88f5b 100644 --- a/repos/base-okl4/src/core/io_mem_session_support.cc +++ b/repos/base-okl4/src/core/io_mem_session_support.cc @@ -22,4 +22,7 @@ using namespace Core; void Io_mem_session_component::_unmap_local(addr_t, size_t, addr_t) { } -addr_t Io_mem_session_component::_map_local(addr_t, size_t) { return 0; } +Io_mem_session_component::Map_local_result Io_mem_session_component::_map_local(addr_t, size_t) +{ + return { .core_local_addr = 0, .success = true }; +} diff --git a/repos/base-okl4/src/core/pager.cc b/repos/base-okl4/src/core/pager.cc index f2549d8b68..148bb1003c 100644 --- a/repos/base-okl4/src/core/pager.cc +++ b/repos/base-okl4/src/core/pager.cc @@ -146,3 +146,6 @@ Untyped_capability Pager_entrypoint::_pager_object_cap(unsigned long badge) { return Capability_space::import(native_thread().l4id, Rpc_obj_key(badge)); } + + +void Core::init_page_fault_handling(Rpc_entrypoint &) { } diff --git a/repos/base-okl4/src/core/platform_thread.cc b/repos/base-okl4/src/core/platform_thread.cc index c95ac8b6df..7ea322e69e 100644 --- a/repos/base-okl4/src/core/platform_thread.cc +++ b/repos/base-okl4/src/core/platform_thread.cc @@ -139,17 +139,6 @@ unsigned long Platform_thread::pager_object_badge() const } -Platform_thread::Platform_thread(Platform_pd &pd, size_t, const char *name, - unsigned prio, Affinity::Location, addr_t) -: - _l4_thread_id(L4_nilthread), _pd(pd), _priority(prio), _pager(0) -{ - copy_cstring(_name, name, sizeof(_name)); - - _bound_to_pd = pd.bind_thread(*this); -} - - Platform_thread::~Platform_thread() { /* diff --git a/repos/base-okl4/src/core/thread_start.cc b/repos/base-okl4/src/core/thread_start.cc index c37fc08f3b..ec27f499e1 100644 --- a/repos/base-okl4/src/core/thread_start.cc +++ b/repos/base-okl4/src/core/thread_start.cc @@ -20,7 +20,6 @@ /* core includes */ #include -#include using namespace Genode; diff --git a/repos/base-pistachio/recipes/src/base-pistachio/hash b/repos/base-pistachio/recipes/src/base-pistachio/hash index 993b9b9441..2aed2d2c75 100644 --- a/repos/base-pistachio/recipes/src/base-pistachio/hash +++ b/repos/base-pistachio/recipes/src/base-pistachio/hash @@ -1 +1 @@ -2024-08-28 ef60eabef7b6a62cb0ca9844e76dcaa0d5fd9032 +2024-12-10 d6f79e327a46e48890b32d90d2eb8be604a8534d diff --git a/repos/base-pistachio/src/core/include/platform_thread.h b/repos/base-pistachio/src/core/include/platform_thread.h index 98f241d177..0b3a27cfa6 100644 --- a/repos/base-pistachio/src/core/include/platform_thread.h +++ b/repos/base-pistachio/src/core/include/platform_thread.h @@ -86,7 +86,8 @@ class Core::Platform_thread : Interface /** * Constructor */ - Platform_thread(Platform_pd &pd, size_t, char const *name, unsigned priority, + Platform_thread(Platform_pd &pd, Rpc_entrypoint &, Ram_allocator &, + Region_map &, size_t, char const *name, unsigned priority, Affinity::Location location, addr_t) : _name(name), _pd(pd), _priority(priority), _location(location) diff --git a/repos/base-pistachio/src/core/io_mem_session_support.cc b/repos/base-pistachio/src/core/io_mem_session_support.cc index f0763ab1e7..29adba2149 100644 --- a/repos/base-pistachio/src/core/io_mem_session_support.cc +++ b/repos/base-pistachio/src/core/io_mem_session_support.cc @@ -56,15 +56,18 @@ static inline bool can_use_super_page(addr_t base, size_t size) } -addr_t Io_mem_session_component::_map_local(addr_t base, size_t size) +Io_mem_session_component::Map_local_result Io_mem_session_component::_map_local(addr_t const phys_base, + size_t const size_in) { using namespace Pistachio; + auto size = size_in; + auto alloc_virt_range = [&] { /* special case for the null page */ - if (is_conventional_memory(base)) - return base; + if (is_conventional_memory(phys_base)) + return phys_base; /* align large I/O dataspaces to super page size, otherwise to size */ size_t const align = (size >= get_super_page_size()) @@ -81,16 +84,16 @@ addr_t Io_mem_session_component::_map_local(addr_t base, size_t size) addr_t const local_base = (addr_t)alloc_virt_range(); if (!local_base) - return 0; + return Map_local_result (); for (unsigned offset = 0; size; ) { size_t page_size = get_page_size(); - if (can_use_super_page(base + offset, size)) + if (can_use_super_page(phys_base + offset, size)) page_size = get_super_page_size(); L4_Sigma0_GetPage_RcvWindow(get_sigma0(), - L4_Fpage(base + offset, page_size), + L4_Fpage(phys_base + offset, page_size), L4_Fpage(local_base + offset, page_size)); if (_cacheable == WRITE_COMBINED) { @@ -104,5 +107,5 @@ addr_t Io_mem_session_component::_map_local(addr_t base, size_t size) size -= page_size; } - return local_base; + return { .core_local_addr = local_base, .success = true }; } diff --git a/repos/base-pistachio/src/core/pager.cc b/repos/base-pistachio/src/core/pager.cc index 636417bd1b..1fd1bb210b 100644 --- a/repos/base-pistachio/src/core/pager.cc +++ b/repos/base-pistachio/src/core/pager.cc @@ -132,3 +132,6 @@ Untyped_capability Pager_entrypoint::_pager_object_cap(unsigned long badge) { return Capability_space::import(native_thread().l4id, Rpc_obj_key(badge)); } + + +void Core::init_page_fault_handling(Rpc_entrypoint &) { } diff --git a/repos/base-pistachio/src/core/thread_start.cc b/repos/base-pistachio/src/core/thread_start.cc index d31662b446..6232548265 100644 --- a/repos/base-pistachio/src/core/thread_start.cc +++ b/repos/base-pistachio/src/core/thread_start.cc @@ -18,7 +18,6 @@ /* core includes */ #include #include -#include /* base-internal includes */ #include diff --git a/repos/base-sel4/recipes/src/base-sel4-imx6q_sabrelite/hash b/repos/base-sel4/recipes/src/base-sel4-imx6q_sabrelite/hash index 7fc8d755b8..e5c807bc0c 100644 --- a/repos/base-sel4/recipes/src/base-sel4-imx6q_sabrelite/hash +++ b/repos/base-sel4/recipes/src/base-sel4-imx6q_sabrelite/hash @@ -1 +1 @@ -2024-08-28 6a6ef31c10a65d90eaba97c45324b4e6835f14db +2024-12-10 4f6772b2b52b10c6462c2be4460981484d2f413f diff --git a/repos/base-sel4/recipes/src/base-sel4-x86/hash b/repos/base-sel4/recipes/src/base-sel4-x86/hash index 7f91bc2faf..6a1cac443f 100644 --- a/repos/base-sel4/recipes/src/base-sel4-x86/hash +++ b/repos/base-sel4/recipes/src/base-sel4-x86/hash @@ -1 +1 @@ -2024-08-28 5656ef6d7282894b67b9aab50364f12f42aded49 +2024-12-10 e10d664cb493e322f029ef8a4bb22dabb3276137 diff --git a/repos/base-sel4/src/core/include/irq_object.h b/repos/base-sel4/src/core/include/irq_object.h index e5fa51aad7..38f1a3e803 100644 --- a/repos/base-sel4/src/core/include/irq_object.h +++ b/repos/base-sel4/src/core/include/irq_object.h @@ -23,6 +23,7 @@ /* core includes */ #include +#include namespace Core { class Irq_object; } @@ -41,11 +42,12 @@ class Core::Irq_object : public Thread { void entry() override; - long _associate(Irq_session::Trigger const &irq_trigger, - Irq_session::Polarity const &irq_polarity); + long _associate(Irq_args const &); public: + enum { MSI_OFFSET = 64 }; + Irq_object(unsigned irq); void sigh(Signal_context_capability cap) { _sig_cap = cap; } @@ -53,7 +55,9 @@ class Core::Irq_object : public Thread { void ack_irq(); Start_result start() override; - bool associate(Irq_session::Trigger const, Irq_session::Polarity const); + bool associate(Irq_args const &); + + bool msi() const { return _irq >= MSI_OFFSET; } }; #endif /* _CORE__INCLUDE__IRQ_OBJECT_H_ */ diff --git a/repos/base-sel4/src/core/include/pager.h b/repos/base-sel4/src/core/include/pager.h index 3c90bc8f19..5dd2dff1a6 100644 --- a/repos/base-sel4/src/core/include/pager.h +++ b/repos/base-sel4/src/core/include/pager.h @@ -46,6 +46,8 @@ namespace Core { using Pager_capability = Capability; enum { PAGER_EP_STACK_SIZE = sizeof(addr_t) * 2048 }; + + extern void init_page_fault_handling(Rpc_entrypoint &); } diff --git a/repos/base-sel4/src/core/include/platform_thread.h b/repos/base-sel4/src/core/include/platform_thread.h index 447ac953a2..d6416451d3 100644 --- a/repos/base-sel4/src/core/include/platform_thread.h +++ b/repos/base-sel4/src/core/include/platform_thread.h @@ -88,7 +88,8 @@ class Core::Platform_thread : public List::Element /** * Constructor */ - Platform_thread(Platform_pd &pd, size_t, const char *name, unsigned priority, + Platform_thread(Platform_pd &pd, Rpc_entrypoint &, Ram_allocator &, + Region_map &, size_t, const char *name, unsigned priority, Affinity::Location, addr_t utcb); /** diff --git a/repos/base-sel4/src/core/include/untyped_memory.h b/repos/base-sel4/src/core/include/untyped_memory.h index 53c916d1b4..9f89803af8 100644 --- a/repos/base-sel4/src/core/include/untyped_memory.h +++ b/repos/base-sel4/src/core/include/untyped_memory.h @@ -98,9 +98,11 @@ struct Core::Untyped_memory /** * Create page frames from untyped memory */ - static inline void convert_to_page_frames(addr_t phys_addr, + static inline bool convert_to_page_frames(addr_t phys_addr, size_t num_pages) { + auto const phys_addr_base = phys_addr; + for (size_t i = 0; i < num_pages; i++, phys_addr += get_page_size()) { seL4_Untyped const service = untyped_sel(phys_addr).value(); @@ -121,14 +123,21 @@ struct Core::Untyped_memory node_offset, num_objects); - if (ret != seL4_NoError) { - error(__FUNCTION__, ": seL4_Untyped_RetypeAtOffset " - "returned ", ret, " - physical_range=", - Hex_range(node_offset << get_page_size_log2(), - (num_pages - i) * get_page_size())); - return; - } + if (ret == seL4_NoError) + continue; + + error(__FUNCTION__, ": seL4_Untyped_RetypeAtOffset " + "returned ", ret, " - physical_range=", + Hex_range(node_offset << get_page_size_log2(), + (num_pages - i) * get_page_size())); + + /* revert already converted memory */ + convert_to_untyped_frames(phys_addr_base, get_page_size() * i); + + return false; } + + return true; } diff --git a/repos/base-sel4/src/core/include/vm_session_component.h b/repos/base-sel4/src/core/include/vm_session_component.h index 094da243cf..c1046fdd60 100644 --- a/repos/base-sel4/src/core/include/vm_session_component.h +++ b/repos/base-sel4/src/core/include/vm_session_component.h @@ -16,9 +16,11 @@ /* Genode includes */ #include +#include #include /* core includes */ +#include #include #include @@ -117,7 +119,7 @@ class Core::Vm_session_component ** Vm session interface ** **************************/ - Capability create_vcpu(Thread_capability); + Capability create_vcpu(Thread_capability) override; void attach_pic(addr_t) override { /* unused on seL4 */ } void attach(Dataspace_capability, addr_t, Attach_attr) override; diff --git a/repos/base-sel4/src/core/io_mem_session_support.cc b/repos/base-sel4/src/core/io_mem_session_support.cc index 008746945c..e93e0ccb3e 100644 --- a/repos/base-sel4/src/core/io_mem_session_support.cc +++ b/repos/base-sel4/src/core/io_mem_session_support.cc @@ -25,10 +25,11 @@ void Io_mem_session_component::_unmap_local(addr_t, size_t size, addr_t phys) } -addr_t Io_mem_session_component::_map_local(addr_t phys, size_t size) +Io_mem_session_component::Map_local_result Io_mem_session_component::_map_local(addr_t const phys, + size_t const size) { size_t const num_pages = size >> get_page_size_log2(); - Untyped_memory::convert_to_page_frames(phys, num_pages); - return 0; + return { .core_local_addr = 0, + .success = Untyped_memory::convert_to_page_frames(phys, num_pages) }; } diff --git a/repos/base-sel4/src/core/irq_session_component.cc b/repos/base-sel4/src/core/irq_session_component.cc index 108f8f9940..be5beeb975 100644 --- a/repos/base-sel4/src/core/irq_session_component.cc +++ b/repos/base-sel4/src/core/irq_session_component.cc @@ -22,12 +22,11 @@ using namespace Core; -bool Irq_object::associate(Irq_session::Trigger const irq_trigger, - Irq_session::Polarity const irq_polarity) +bool Irq_object::associate(Irq_args const &args) { /* allocate notification object within core's CNode */ - Platform &platform = platform_specific(); - Range_allocator &phys_alloc = platform.ram_alloc(); + auto &platform = platform_specific(); + auto &phys_alloc = platform.ram_alloc(); { addr_t const phys_addr = Untyped_memory::alloc_page(phys_alloc); @@ -38,7 +37,7 @@ bool Irq_object::associate(Irq_session::Trigger const irq_trigger, } /* setup IRQ platform specific */ - long res = _associate(irq_trigger, irq_polarity); + long res = _associate(args); if (res != seL4_NoError) return false; @@ -100,22 +99,20 @@ Irq_object::Irq_object(unsigned irq) Irq_session_component::Irq_session_component(Range_allocator &irq_alloc, const char *args) : - _irq_number((unsigned)Arg_string::find_arg(args, "irq_number").long_value(-1)), + _irq_number(unsigned(Irq_args(args).type() == TYPE_LEGACY ? + Irq_args(args).irq_number() : + Irq_args(args).irq_number() + Irq_object::MSI_OFFSET)), _irq_alloc(irq_alloc), _irq_object(_irq_number) { Irq_args const irq_args(args); - bool msi { irq_args.type() != Irq_session::TYPE_LEGACY }; - if (msi) - throw Service_denied(); if (irq_alloc.alloc_addr(1, _irq_number).failed()) { error("unavailable IRQ ", _irq_number, " requested"); throw Service_denied(); } - - if (!_irq_object.associate(irq_args.trigger(), irq_args.polarity())) { + if (!_irq_object.associate(irq_args)) { error("could not associate with IRQ ", irq_args.irq_number()); throw Service_denied(); } @@ -144,6 +141,13 @@ void Irq_session_component::sigh(Signal_context_capability cap) Irq_session::Info Irq_session_component::info() { - /* no MSI support */ - return { .type = Info::Type::INVALID, .address = 0, .value = 0 }; + if (!_irq_object.msi()) + return { .type = Info::Type::INVALID, .address = 0, .value = 0 }; + + // see include/plat/pc99/plat/machine.h + enum { PIC_IRQ_LINES = 16, IRQ_INT_OFFSET = 0x20 }; + + return { .type = Info::Type::MSI, + .address = 0xfee00000ul, + .value = IRQ_INT_OFFSET + PIC_IRQ_LINES + _irq_number }; } diff --git a/repos/base-sel4/src/core/pager.cc b/repos/base-sel4/src/core/pager.cc index 36f3313c8c..f2eded3b7c 100644 --- a/repos/base-sel4/src/core/pager.cc +++ b/repos/base-sel4/src/core/pager.cc @@ -31,6 +31,9 @@ using namespace Core; void Mapping::prepare_map_operation() const { } +void Core::init_page_fault_handling(Rpc_entrypoint &) { } + + /*************** ** IPC pager ** ***************/ diff --git a/repos/base-sel4/src/core/platform.cc b/repos/base-sel4/src/core/platform.cc index 25b68940cb..2bd987fdbc 100644 --- a/repos/base-sel4/src/core/platform.cc +++ b/repos/base-sel4/src/core/platform.cc @@ -380,6 +380,7 @@ void Core::Platform::_init_rom_modules() xml.node("kernel", [&] { xml.attribute("name", "sel4"); xml.attribute("acpi", true); + xml.attribute("msi" , true); }); xml.node("hardware", [&] { xml.node("features", [&] { diff --git a/repos/base-sel4/src/core/platform_thread.cc b/repos/base-sel4/src/core/platform_thread.cc index 6b97b81bd4..ecb302ba1d 100644 --- a/repos/base-sel4/src/core/platform_thread.cc +++ b/repos/base-sel4/src/core/platform_thread.cc @@ -209,7 +209,8 @@ bool Platform_thread::install_mapping(Mapping const &mapping) } -Platform_thread::Platform_thread(Platform_pd &pd, size_t, const char *name, +Platform_thread::Platform_thread(Platform_pd &pd, Rpc_entrypoint &, Ram_allocator &, + Region_map &, size_t, const char *name, unsigned priority, Affinity::Location location, addr_t utcb) : diff --git a/repos/base-sel4/src/core/spec/arm/irq.cc b/repos/base-sel4/src/core/spec/arm/irq.cc index a16be9edd6..2e2df4ac53 100644 --- a/repos/base-sel4/src/core/spec/arm/irq.cc +++ b/repos/base-sel4/src/core/spec/arm/irq.cc @@ -11,8 +11,7 @@ using namespace Core; -long Irq_object::_associate(Irq_session::Trigger const &, - Irq_session::Polarity const &) +long Irq_object::_associate(Irq_args const &) { seL4_CNode const root = seL4_CapInitThreadCNode; seL4_Word const index = _kernel_irq_sel.value(); diff --git a/repos/base-sel4/src/core/spec/x86/irq.cc b/repos/base-sel4/src/core/spec/x86/irq.cc index e0f6c9715c..39830a735c 100644 --- a/repos/base-sel4/src/core/spec/x86/irq.cc +++ b/repos/base-sel4/src/core/spec/x86/irq.cc @@ -12,8 +12,7 @@ using namespace Core; -long Irq_object::_associate(Irq_session::Trigger const &irq_trigger, - Irq_session::Polarity const &irq_polarity) +long Irq_object::_associate(Irq_args const & args) { enum { IRQ_EDGE = 0, IRQ_LEVEL = 1 }; enum { IRQ_HIGH = 0, IRQ_LOW = 1 }; @@ -21,11 +20,11 @@ long Irq_object::_associate(Irq_session::Trigger const &irq_trigger, seL4_Word level = (_irq < 16) ? IRQ_EDGE : IRQ_LEVEL; seL4_Word polarity = (_irq < 16) ? IRQ_HIGH : IRQ_LOW; - if (irq_trigger != Irq_session::TRIGGER_UNCHANGED) - level = (irq_trigger == Irq_session::TRIGGER_LEVEL) ? IRQ_LEVEL : IRQ_EDGE; + if (args.trigger() != Irq_session::TRIGGER_UNCHANGED) + level = (args.trigger() == Irq_session::TRIGGER_LEVEL) ? IRQ_LEVEL : IRQ_EDGE; - if (irq_polarity != Irq_session::POLARITY_UNCHANGED) - polarity = (irq_polarity == Irq_session::POLARITY_HIGH) ? IRQ_HIGH : IRQ_LOW; + if (args.polarity() != Irq_session::POLARITY_UNCHANGED) + polarity = (args.polarity() == Irq_session::POLARITY_HIGH) ? IRQ_HIGH : IRQ_LOW; seL4_CNode const root = seL4_CapInitThreadCNode; seL4_Word const index = _kernel_irq_sel.value(); @@ -33,6 +32,18 @@ long Irq_object::_associate(Irq_session::Trigger const &irq_trigger, seL4_Word const ioapic = 0; seL4_Word const pin = _irq ? _irq : 2; seL4_Word const vector = _irq; - return seL4_IRQControl_GetIOAPIC(seL4_CapIRQControl, root, index, depth, - ioapic, pin, level, polarity, vector); + seL4_Word const handle = 0; + + switch (args.type()) { + case Irq_session::TYPE_LEGACY: + return seL4_IRQControl_GetIOAPIC(seL4_CapIRQControl, root, index, depth, + ioapic, pin, level, polarity, vector); + case Irq_session::TYPE_MSI: + case Irq_session::TYPE_MSIX: + return seL4_IRQControl_GetMSI(seL4_CapIRQControl, root, index, depth, + args.pci_bus(), args.pci_dev(), + args.pci_func(), handle, vector); + default: + return seL4_InvalidArgument; + } } diff --git a/repos/base-sel4/src/core/spec/x86/platform_services.cc b/repos/base-sel4/src/core/spec/x86/platform_services.cc index 2e779a438d..2f768b8663 100644 --- a/repos/base-sel4/src/core/spec/x86/platform_services.cc +++ b/repos/base-sel4/src/core/spec/x86/platform_services.cc @@ -12,7 +12,6 @@ */ /* core includes */ -#include #include #include #include @@ -20,17 +19,19 @@ /* * Add x86 specific services */ -void Core::platform_add_local_services(Rpc_entrypoint &ep, - Sliced_heap &heap, - Registry &services, - Core::Trace::Source_registry &trace_sources) +void Core::platform_add_local_services(Rpc_entrypoint &ep, + Sliced_heap &heap, + Registry &services, + Trace::Source_registry &trace_sources, + Ram_allocator &core_ram, + Region_map &core_rm, + Range_allocator &io_port_ranges) { - static Vm_root vm_root(ep, heap, core_env().ram_allocator(), - core_env().local_rm(), trace_sources); + static Vm_root vm_root(ep, heap, core_ram, core_rm, trace_sources); + static Core_service vm(services, vm_root); - static Io_port_root io_root(*core_env().pd_session(), - platform().io_port_alloc(), heap); + static Io_port_root io_root(io_port_ranges, heap); static Core_service io_port(services, io_root); } diff --git a/repos/base-sel4/src/core/spec/x86/vm_session_component.cc b/repos/base-sel4/src/core/spec/x86/vm_session_component.cc index 510f59cd1f..f703de8aff 100644 --- a/repos/base-sel4/src/core/spec/x86/vm_session_component.cc +++ b/repos/base-sel4/src/core/spec/x86/vm_session_component.cc @@ -16,7 +16,6 @@ #include /* core includes */ -#include #include #include #include diff --git a/repos/base-sel4/src/lib/base/x86/vm.cc b/repos/base-sel4/src/lib/base/x86/vm.cc index e263ef9b9a..a0119d8db5 100644 --- a/repos/base-sel4/src/lib/base/x86/vm.cc +++ b/repos/base-sel4/src/lib/base/x86/vm.cc @@ -38,7 +38,6 @@ using namespace Genode; using Exit_config = Vm_connection::Exit_config; -using Call_with_state = Vm_connection::Call_with_state; struct Sel4_vcpu; @@ -49,8 +48,7 @@ struct Sel4_native_rpc : Rpc_client, Noncopyable Capability _create_vcpu(Vm_connection &vm, Thread_capability &cap) { - return vm.with_upgrade([&] { - return vm.call(cap); }); + return vm.create_vcpu(cap); } public: @@ -811,7 +809,7 @@ struct Sel4_vcpu : Genode::Thread, Noncopyable _wake_up.up(); } - void with_state(Call_with_state &cw) + void with_state(auto const &fn) { if (!_dispatching) { if (Thread::myself() != _ep_handler) { @@ -840,7 +838,7 @@ struct Sel4_vcpu : Genode::Thread, Noncopyable _state_ready.down(); } - if (cw.call_with_state(_state) + if (fn(_state) || _extra_dispatch_up) resume(); @@ -860,11 +858,15 @@ struct Sel4_vcpu : Genode::Thread, Noncopyable Sel4_native_rpc * rpc() { return &*_rpc; } }; + /************** ** vCPU API ** **************/ -void Vm_connection::Vcpu::_with_state(Call_with_state &cw) { static_cast(_native_vcpu).vcpu.with_state(cw); } +void Vm_connection::Vcpu::_with_state(With_state::Ft const &fn) +{ + static_cast(_native_vcpu).vcpu.with_state(fn); +} Vm_connection::Vcpu::Vcpu(Vm_connection &vm, Allocator &alloc, diff --git a/repos/base/include/base/attached_dataspace.h b/repos/base/include/base/attached_dataspace.h index 8adaba4d48..98ef92b3dd 100644 --- a/repos/base/include/base/attached_dataspace.h +++ b/repos/base/include/base/attached_dataspace.h @@ -54,12 +54,6 @@ class Genode::Attached_dataspace : Noncopyable [&] (Region_map::Attach_error) { return nullptr; }); } - /* - * Noncopyable - */ - Attached_dataspace(Attached_dataspace const &); - Attached_dataspace &operator = (Attached_dataspace const &); - public: /** @@ -118,6 +112,11 @@ class Genode::Attached_dataspace : Noncopyable [&] (Region_map::Attach_error) { return 0UL; }); } + /** + * Return byte range of locally mapped dataspace + */ + Byte_range_ptr bytes() const { return { _ptr(), size() }; } + /** * Forget dataspace, thereby skipping the detachment on destruction * diff --git a/repos/base/include/base/attached_ram_dataspace.h b/repos/base/include/base/attached_ram_dataspace.h index f6b316ef94..1f641f06e9 100644 --- a/repos/base/include/base/attached_ram_dataspace.h +++ b/repos/base/include/base/attached_ram_dataspace.h @@ -139,6 +139,8 @@ class Genode::Attached_ram_dataspace */ size_t size() const { return _size; } + void clear() { if (_at) memset((void *)_at, 0, _size); } + void swap(Attached_ram_dataspace &other) { _swap(_size, other._size); @@ -163,6 +165,11 @@ class Genode::Attached_ram_dataspace _alloc_and_attach(); } + + /** + * Return byte range of locally mapped dataspace + */ + Byte_range_ptr bytes() const { return { local_addr(), size() }; } }; #endif /* _INCLUDE__BASE__ATTACHED_RAM_DATASPACE_H_ */ diff --git a/repos/base/include/base/child.h b/repos/base/include/base/child.h index 7c70c369bd..d1e4d63549 100644 --- a/repos/base/include/base/child.h +++ b/repos/base/include/base/child.h @@ -118,18 +118,18 @@ struct Genode::Child_policy } /** - * Reference PD session + * Reference PD-sesson account * - * The PD session returned by this method is used for session cap-quota + * The PD account returned by this method is used for session cap-quota * and RAM-quota transfers. */ - virtual Pd_session &ref_pd() = 0; - virtual Pd_session_capability ref_pd_cap() const = 0; + virtual Pd_account &ref_account() = 0; + virtual Capability ref_account_cap() const = 0; /** * RAM allocator used as backing store for '_session_md_alloc' */ - virtual Ram_allocator &session_md_ram() { return ref_pd(); } + virtual Ram_allocator &session_md_ram() = 0; /** * Respond to the release of resources by the child @@ -459,10 +459,10 @@ class Genode::Child : protected Rpc_object, Cap_quota const cap_quota { CONNECTION::CAP_QUOTA }; if (cap(ram_quota).valid()) - _child._policy.ref_pd().transfer_quota(cap(ram_quota), ram_quota); + _child._policy.ref_account().transfer_quota(cap(ram_quota), ram_quota); if (cap(cap_quota).valid()) - _child._policy.ref_pd().transfer_quota(cap(cap_quota), cap_quota); + _child._policy.ref_account().transfer_quota(cap(cap_quota), cap_quota); _first_request = false; } @@ -489,13 +489,12 @@ class Genode::Child : protected Rpc_object, _child._try_construct_env_dependent_members(); } - using Transfer_ram_quota_result = Pd_session::Transfer_ram_quota_result; - using Transfer_cap_quota_result = Pd_session::Transfer_ram_quota_result; + using Transfer_result = Pd_session::Transfer_result; /** * Service (Ram_transfer::Account) interface */ - Ram_transfer_result transfer(Pd_session_capability to, Ram_quota amount) override + Transfer_result transfer(Capability to, Ram_quota amount) override { Ram_transfer::Account &from = _service; return from.transfer(to, amount); @@ -504,7 +503,7 @@ class Genode::Child : protected Rpc_object, /** * Service (Ram_transfer::Account) interface */ - Pd_session_capability cap(Ram_quota) const override + Capability cap(Ram_quota) const override { Ram_transfer::Account &to = _service; return to.cap(Ram_quota()); @@ -513,7 +512,7 @@ class Genode::Child : protected Rpc_object, /** * Service (Cap_transfer::Account) interface */ - Cap_transfer_result transfer(Pd_session_capability to, Cap_quota amount) override + Transfer_result transfer(Capability to, Cap_quota amount) override { Cap_transfer::Account &from = _service; return from.transfer(to, amount); @@ -522,7 +521,7 @@ class Genode::Child : protected Rpc_object, /** * Service (Cap_transfer::Account) interface */ - Pd_session_capability cap(Cap_quota) const override + Capability cap(Cap_quota) const override { Cap_transfer::Account &to = _service; return to.cap(Cap_quota()); diff --git a/repos/base/include/base/connection.h b/repos/base/include/base/connection.h index 1798d84906..9e6c915d5e 100644 --- a/repos/base/include/base/connection.h +++ b/repos/base/include/base/connection.h @@ -107,13 +107,14 @@ class Genode::Connection : public Connection_base Client_id const &id, Session_label const &label, Ram_quota const &ram_quota, + Cap_quota const &cap_quota, Affinity const &affinity, Args const &args) { /* supplement session quotas and label as session arguments */ Args const complete_args("label=\"", label, "\", " "ram_quota=", ram_quota, ", " - "cap_quota=", unsigned(SESSION_TYPE::CAP_QUOTA), ", ", + "cap_quota=", cap_quota, ", ", args); if (complete_args.length() == Args::capacity()) @@ -138,12 +139,26 @@ class Genode::Connection : public Connection_base Connection(Env &env, Session_label const &label, Ram_quota const &ram_quota, + Cap_quota const &cap_quota, Affinity const &affinity, Args const &args) : Connection_base(env), _cap(_request(env, _id_space_element.id(), - label, ram_quota, affinity, args)) + label, ram_quota, cap_quota, affinity, args)) + { } + + /** + * Constructor using the cap quota declared in as SESSION_TYPE::CAP_QUOTA + */ + Connection(Env &env, + Session_label const &label, + Ram_quota const &ram_quota, + Affinity const &affinity, + Args const &args) + : + Connection(env, label, ram_quota, Cap_quota { unsigned(SESSION_TYPE::CAP_QUOTA) }, + affinity, args) { } /** diff --git a/repos/base/include/base/heap.h b/repos/base/include/base/heap.h index f67918e10a..1abd508bdb 100644 --- a/repos/base/include/base/heap.h +++ b/repos/base/include/base/heap.h @@ -119,7 +119,7 @@ class Genode::Heap : public Allocator public: - enum { UNLIMITED = ~0 }; + static constexpr size_t UNLIMITED = ~0; Heap(Ram_allocator *ram_allocator, Region_map *region_map, diff --git a/repos/base/include/base/quota_transfer.h b/repos/base/include/base/quota_transfer.h index 50bac4d24a..8bfe02efe4 100644 --- a/repos/base/include/base/quota_transfer.h +++ b/repos/base/include/base/quota_transfer.h @@ -21,8 +21,8 @@ namespace Genode { template class Quota_transfer; - using Ram_transfer = Quota_transfer; - using Cap_transfer = Quota_transfer; + using Ram_transfer = Quota_transfer; + using Cap_transfer = Quota_transfer; } @@ -107,9 +107,6 @@ class Genode::Quota_transfer Account &_from; Account &_to; - static bool _exceeded(Ram_quota, RESULT r) { return (r == RESULT::OUT_OF_RAM); } - static bool _exceeded(Cap_quota, RESULT r) { return (r == RESULT::OUT_OF_CAPS); } - public: class Quota_exceeded : Exception { }; @@ -129,7 +126,7 @@ class Genode::Quota_transfer if (!_from.cap(UNIT()).valid() || !_to.cap(UNIT()).valid()) return; - if (_exceeded(UNIT{}, _from.transfer(_to.cap(UNIT()), amount))) + if (_from.transfer(_to.cap(UNIT()), amount) == RESULT::EXCEEDED) throw Quota_exceeded(); } diff --git a/repos/base/include/base/ram_allocator.h b/repos/base/include/base/ram_allocator.h index a11d3f6a4d..f61add9709 100644 --- a/repos/base/include/base/ram_allocator.h +++ b/repos/base/include/base/ram_allocator.h @@ -19,6 +19,7 @@ #include #include #include +#include namespace Genode { @@ -32,7 +33,7 @@ namespace Genode { } -struct Genode::Ram_allocator : Interface +struct Genode::Ram_allocator : Interface, Noncopyable { enum class Alloc_error { OUT_OF_RAM, OUT_OF_CAPS, DENIED }; diff --git a/repos/base/include/base/service.h b/repos/base/include/base/service.h index 93275a6c51..f25897cb24 100644 --- a/repos/base/include/base/service.h +++ b/repos/base/include/base/service.h @@ -476,7 +476,7 @@ class Genode::Child_service : public Async_service /** * Ram_transfer::Account interface */ - Ram_transfer_result transfer(Pd_session_capability to, Ram_quota amount) override + Ram_transfer_result transfer(Capability to, Ram_quota amount) override { return to.valid() ? _pd.transfer_quota(to, amount) : Ram_transfer_result::OK; @@ -485,12 +485,12 @@ class Genode::Child_service : public Async_service /** * Ram_transfer::Account interface */ - Pd_session_capability cap(Ram_quota) const override { return _pd.rpc_cap(); } + Capability cap(Ram_quota) const override { return _pd.rpc_cap(); } /** * Cap_transfer::Account interface */ - Cap_transfer_result transfer(Pd_session_capability to, Cap_quota amount) override + Cap_transfer_result transfer(Capability to, Cap_quota amount) override { return to.valid() ? _pd.transfer_quota(to, amount) : Cap_transfer_result::OK; @@ -499,7 +499,7 @@ class Genode::Child_service : public Async_service /** * Cap_transfer::Account interface */ - Pd_session_capability cap(Cap_quota) const override { return _pd.rpc_cap(); } + Capability cap(Cap_quota) const override { return _pd.rpc_cap(); } }; #endif /* _INCLUDE__BASE__SERVICE_H_ */ diff --git a/repos/base/include/base/thread.h b/repos/base/include/base/thread.h index af3c86d929..0ae686895d 100644 --- a/repos/base/include/base/thread.h +++ b/repos/base/include/base/thread.h @@ -151,6 +151,12 @@ class Genode::Thread */ static Trace::Logger *_logger(); + static void _with_logger(auto const &fn) + { + Trace::Logger * const ptr = _logger(); + if (ptr) fn(*ptr); + } + /** * Hook for platform-specific constructor supplements * @@ -397,14 +403,6 @@ class Genode::Thread */ void join(); - /** - * Log null-terminated string as trace event - */ - static void trace(char const *cstring) - { - _logger()->log(cstring, strlen(cstring)); - } - /** * Log null-terminated string as trace event using log_output policy * @@ -412,7 +410,10 @@ class Genode::Thread */ static bool trace_captured(char const *cstring) { - return _logger()->log_captured(cstring, strlen(cstring)); + bool result = false; + _with_logger([&] (Trace::Logger &l) { + result = l.log_captured(cstring, strlen(cstring)); }); + return result; } /** @@ -420,13 +421,21 @@ class Genode::Thread */ static void trace(char const *data, size_t len) { - _logger()->log(data, len); + _with_logger([&] (Trace::Logger &l) { l.log(data, len); }); } + /** + * Log null-terminated string as trace event + */ + static void trace(char const *cstring) { trace(cstring, strlen(cstring)); } + /** * Log trace event as defined in base/trace/events.h */ - static void trace(auto const *event) { _logger()->log(event); } + static void trace(auto const *event) + { + _with_logger([&] (Trace::Logger &l) { l.log(event); }); + } /** * Thread affinity diff --git a/repos/base/include/cpu/string.h b/repos/base/include/cpu/string.h index 898b0a9b57..ea6b100227 100644 --- a/repos/base/include/cpu/string.h +++ b/repos/base/include/cpu/string.h @@ -25,7 +25,10 @@ namespace Genode { * \param size number of bytes to copy * * \return number of bytes not copied + * + * The compiler attribute prevents array-bounds warnings with gcc 12.3. */ + __attribute((optimize("no-tree-loop-distribute-patterns"))) inline size_t memcpy_cpu(void * dst, const void * src, size_t size) { using word_t = unsigned long; diff --git a/repos/base/include/irq_session/connection.h b/repos/base/include/irq_session/connection.h index 5ad4784e5a..9491d156f4 100644 --- a/repos/base/include/irq_session/connection.h +++ b/repos/base/include/irq_session/connection.h @@ -46,17 +46,20 @@ struct Genode::Irq_connection : Connection, Irq_session_client * Constructor * * \param label (virtual) interrupt number - * \param device_config_phys config-space physical address + * \param device_config_phys PCI config-space physical address * \param type interrupt type (e.g., msi/msi-x) + * \param bdf PCI bdf of device */ Irq_connection(Env &env, Label const &label, addr_t device_config_phys, - Type type = Irq_session::TYPE_MSI) + Type type, + unsigned bdf = 0x10000 /* invalid */) : Connection(env, label, Ram_quota { RAM_QUOTA }, Args("irq_number=", label, ", " "device_config_phys=", Hex(device_config_phys), ", " + "bdf=", Hex(bdf), ", " "irq_type=", unsigned(type))), Irq_session_client(cap()) { } diff --git a/repos/base/include/pd_session/client.h b/repos/base/include/pd_session/client.h index 5c8007d10a..d7dfc82ca2 100644 --- a/repos/base/include/pd_session/client.h +++ b/repos/base/include/pd_session/client.h @@ -64,11 +64,10 @@ struct Genode::Pd_session_client : Rpc_client Capability linker_area() override { return call(); } - Ref_account_result ref_account(Capability pd) override { + Ref_account_result ref_account(Capability pd) override { return call(pd); } - Transfer_cap_quota_result transfer_quota(Capability pd, - Cap_quota amount) override + Transfer_result transfer_quota(Capability pd, Cap_quota amount) override { return call(pd, amount); } @@ -88,10 +87,9 @@ struct Genode::Pd_session_client : Rpc_client return ds.valid() ? Dataspace_client(ds).size() : 0; } - Transfer_ram_quota_result transfer_quota(Pd_session_capability pd_session, - Ram_quota amount) override + Transfer_result transfer_quota(Capability pd, Ram_quota amount) override { - return call(pd_session, amount); + return call(pd, amount); } Ram_quota ram_quota() const override { return call(); } diff --git a/repos/base/include/pd_session/pd_session.h b/repos/base/include/pd_session/pd_session.h index c487129690..16bb325c73 100644 --- a/repos/base/include/pd_session/pd_session.h +++ b/repos/base/include/pd_session/pd_session.h @@ -23,6 +23,7 @@ #include namespace Genode { + struct Pd_account; struct Pd_session; struct Pd_session_client; struct Parent; @@ -30,13 +31,28 @@ namespace Genode { } -struct Genode::Pd_session : Session, Ram_allocator +struct Genode::Pd_account : Interface, Noncopyable { /** * \noapi */ static const char *service_name() { return "PD"; } + enum class Transfer_result { OK, EXCEEDED, INVALID }; + + virtual Transfer_result transfer_quota(Capability, Cap_quota) = 0; + virtual Transfer_result transfer_quota(Capability, Ram_quota) = 0; + + GENODE_RPC(Rpc_transfer_cap_quota, Transfer_result, transfer_quota, + Capability, Cap_quota); + GENODE_RPC(Rpc_transfer_ram_quota, Transfer_result, transfer_quota, + Capability, Ram_quota); + GENODE_RPC_INTERFACE(Rpc_transfer_ram_quota, Rpc_transfer_cap_quota); +}; + + +struct Genode::Pd_session : Session, Pd_account, Ram_allocator +{ /* * A PD session consumes a dataspace capability for the session-object * allocation, a capability for the 'Native_pd' RPC interface, its @@ -200,21 +216,7 @@ struct Genode::Pd_session : Session, Ram_allocator /** * Define reference account for the PD session */ - virtual Ref_account_result ref_account(Capability) = 0; - - enum class Transfer_cap_quota_result { OK, OUT_OF_CAPS, INVALID_SESSION, NO_REF_ACCOUNT }; - - /** - * Transfer capability quota to another PD session - * - * \param to receiver of quota donation - * \param amount amount of quota to donate - * - * Quota can only be transfered if the specified PD session is either the - * reference account for this session or vice versa. - */ - virtual Transfer_cap_quota_result transfer_quota(Capability to, - Cap_quota amount) = 0; + virtual Ref_account_result ref_account(Capability) = 0; /** * Return current capability-quota limit @@ -244,20 +246,6 @@ struct Genode::Pd_session : Session, Ram_allocator * which comprises the actual allocation and deallocation operations. */ - enum class Transfer_ram_quota_result { OK, OUT_OF_RAM, INVALID_SESSION, NO_REF_ACCOUNT }; - - /** - * Transfer quota to another RAM session - * - * \param to receiver of quota donation - * \param amount amount of quota to donate - * - * Quota can only be transfered if the specified PD session is either the - * reference account for this session or vice versa. - */ - virtual Transfer_ram_quota_result transfer_quota(Capability to, - Ram_quota amount) = 0; - /** * Return current quota limit */ @@ -364,15 +352,11 @@ struct Genode::Pd_session : Session, Ram_allocator GENODE_RPC(Rpc_address_space, Capability, address_space); GENODE_RPC(Rpc_stack_area, Capability, stack_area); GENODE_RPC(Rpc_linker_area, Capability, linker_area); - GENODE_RPC(Rpc_ref_account, Ref_account_result, ref_account, Capability); - GENODE_RPC(Rpc_transfer_cap_quota, Transfer_cap_quota_result, transfer_quota, - Capability, Cap_quota); + GENODE_RPC(Rpc_ref_account, Ref_account_result, ref_account, Capability); GENODE_RPC(Rpc_cap_quota, Cap_quota, cap_quota); GENODE_RPC(Rpc_used_caps, Cap_quota, used_caps); GENODE_RPC(Rpc_try_alloc, Alloc_result, try_alloc, size_t, Cache); GENODE_RPC(Rpc_free, void, free, Ram_dataspace_capability); - GENODE_RPC(Rpc_transfer_ram_quota, Transfer_ram_quota_result, transfer_quota, - Capability, Ram_quota); GENODE_RPC(Rpc_ram_quota, Ram_quota, ram_quota); GENODE_RPC(Rpc_used_ram, Ram_quota, used_ram); GENODE_RPC(Rpc_native_pd, Capability, native_pd); @@ -382,16 +366,16 @@ struct Genode::Pd_session : Session, Ram_allocator GENODE_RPC(Rpc_attach_dma, Attach_dma_result, attach_dma, Dataspace_capability, addr_t); - GENODE_RPC_INTERFACE(Rpc_assign_parent, Rpc_assign_pci, Rpc_map, - Rpc_signal_source, Rpc_free_signal_source, - Rpc_alloc_context, Rpc_free_context, Rpc_submit, - Rpc_alloc_rpc_cap, Rpc_free_rpc_cap, Rpc_address_space, - Rpc_stack_area, Rpc_linker_area, Rpc_ref_account, - Rpc_transfer_cap_quota, Rpc_cap_quota, Rpc_used_caps, - Rpc_try_alloc, Rpc_free, - Rpc_transfer_ram_quota, Rpc_ram_quota, Rpc_used_ram, - Rpc_native_pd, Rpc_system_control_cap, - Rpc_dma_addr, Rpc_attach_dma); + GENODE_RPC_INTERFACE_INHERIT(Pd_account, + Rpc_assign_parent, Rpc_assign_pci, Rpc_map, + Rpc_signal_source, Rpc_free_signal_source, + Rpc_alloc_context, Rpc_free_context, Rpc_submit, + Rpc_alloc_rpc_cap, Rpc_free_rpc_cap, Rpc_address_space, + Rpc_stack_area, Rpc_linker_area, Rpc_ref_account, + Rpc_cap_quota, Rpc_used_caps, Rpc_try_alloc, Rpc_free, + Rpc_ram_quota, Rpc_used_ram, + Rpc_native_pd, Rpc_system_control_cap, + Rpc_dma_addr, Rpc_attach_dma); }; #endif /* _INCLUDE__PD_SESSION__PD_SESSION_H_ */ diff --git a/repos/base/include/spec/x86/bios_data_area.h b/repos/base/include/spec/x86/bios_data_area.h index 8d67fd72c9..562abc7fa4 100644 --- a/repos/base/include/spec/x86/bios_data_area.h +++ b/repos/base/include/spec/x86/bios_data_area.h @@ -17,15 +17,11 @@ /* Genode includes */ #include -/* base-internal includes */ -#include - namespace Genode { class Bios_data_area; } + class Genode::Bios_data_area : Mmio<0x12> { - friend Unmanaged_singleton_constructor; - private: struct Serial_base_com1 : Register<0x0, 16> { }; @@ -52,8 +48,11 @@ class Genode::Bios_data_area : Mmio<0x12> /** * Return BDA singleton */ - static Bios_data_area * singleton() { - return unmanaged_singleton(); } + static Bios_data_area * singleton() + { + static Bios_data_area bda { }; + return &bda; + } }; #endif /* _INCLUDE__SPEC__X86__BIOS_DATA_AREA_H_ */ diff --git a/repos/base/include/spec/x86/cpu/vcpu_state.h b/repos/base/include/spec/x86/cpu/vcpu_state.h index 6141e566b1..f943a75283 100644 --- a/repos/base/include/spec/x86/cpu/vcpu_state.h +++ b/repos/base/include/spec/x86/cpu/vcpu_state.h @@ -206,15 +206,16 @@ class Genode::Vcpu_state struct State { - uint8_t _buffer[512] { }; - } __attribute__((aligned(16))); + uint8_t _buffer[2560] { }; + } __attribute__((aligned(64))); private: friend class Vcpu_state; - State _state { }; - bool _charged { false }; + State _state { }; + bool _charged { false }; + uint64_t _state_size { }; /* see comment for Register::operator=() */ Fpu & operator = (Fpu const &) @@ -232,12 +233,14 @@ class Genode::Vcpu_state void charge(auto const &fn) { - _charged = true; - fn(_state); + _charged = true; + _state_size = fn(_state); } + + auto size() const { return _state_size; } }; - Fpu fpu __attribute__((aligned(16))) { }; + Fpu fpu __attribute__((aligned(64))) { }; /* * Registers transfered by hypervisor from guest on VM exit are charged. diff --git a/repos/base/include/util/callable.h b/repos/base/include/util/callable.h new file mode 100644 index 0000000000..f28ab40e62 --- /dev/null +++ b/repos/base/include/util/callable.h @@ -0,0 +1,95 @@ +/* + * \brief Utility for passing lambda arguments to non-template functions + * \author Norman Feske + * \date 2025-01-14 + */ + +/* + * Copyright (C) 2025 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _INCLUDE__UTIL__CALLABLE_H_ +#define _INCLUDE__UTIL__CALLABLE_H_ + +#include + +namespace Genode { template struct Callable; }; + + +/** + * Utility for passing lambda arguments to non-template functions + * + * A function or method taking a lambda as argument must always be a template + * because the captured state is known only at the caller site. For example, + * within a display driver, the following function is meant to call 'fn' for + * each 'Connector const &' that is currently known. + * + * ! void for_each_connector(auto const &fn); + * + * The type of 'fn' as template parameter stands in the way in two situations. + * First, 'for_each_connector' must be implemented in a header because it is a + * template. But its inner working might be complex and better be hidden inside + * a compilation unit. Second, 'for_each_connector' cannot be part of an + * abstract interface because template methods cannot be virtual functions. + * + * The 'Callable' utility addresses both situations by introducing an abstract + * function type 'Ft' for the plain signature (arguments, return type) of a + * lambda, and an 'Fn' type implementing the abstract function for a concrete + * lambda argument. E.g., the following 'With_connector' type defines a + * signature for a lambda that takes a 'Connector const &' argument. + * + * ! With_connector = Callable; + * + * The 'With_connector' definition now allows for defining a pure virtual + * function by referring to the signature's function type 'Ft'. It is a good + * practice to use a '_' prefix because this method is not meant to be the API. + * + * ! virtual void _for_each_connector(With_connector::Ft const &) = 0; + * + * The user-facing API should best accept a regular 'auto const &fn' argument + * and call the virtual function with a concrete implementation of the function + * type, which is accomplished via the 'Fn' type. + * + * ! void for_each_connector(auto const &fn) + * ! { + * ! _for_each_connector( With_connector::Fn { fn } ); + * ! } + * + * At the implementation site of '_for_each_connector', the 'Ft' argument + * can be called like a regular lambda argument. At the caller site, + * 'for_each_connector' accepts a regular lambda argument naturally expecting + * a 'Connector const &'. + */ +template +struct Genode::Callable +{ + struct Ft : Interface { virtual RET operator () (ARGS &&...) const = 0; }; + + template + struct Fn : Ft + { + FN const &_fn; + Fn(FN const &fn) : _fn(fn) { }; + RET operator () (ARGS &&... args) const override { return _fn(args...); } + }; +}; + + +template +struct Genode::Callable +{ + struct Ft : Interface { virtual void operator () (ARGS &&...) const = 0; }; + + template + struct Fn : Ft + { + FN const &_fn; + Fn(FN const &fn) : _fn(fn) { }; + void operator () (ARGS &&... args) const override { _fn(args...); } + }; +}; + +#endif /* _INCLUDE__UTIL__CALLABLE_H_ */ diff --git a/repos/base/include/util/construct_at.h b/repos/base/include/util/construct_at.h index 20387900c9..9282d62376 100644 --- a/repos/base/include/util/construct_at.h +++ b/repos/base/include/util/construct_at.h @@ -72,6 +72,8 @@ static inline T * Genode::construct_at(void *at, ARGS &&... args) } }; + static_assert(sizeof(Placeable) == sizeof(T)); + /* * If the args input to this function contains rvalues, the compiler would * use the according rvalue references as lvalues at the following call if diff --git a/repos/base/include/util/geometry.h b/repos/base/include/util/geometry.h index 0266ef6be9..4f362ef239 100644 --- a/repos/base/include/util/geometry.h +++ b/repos/base/include/util/geometry.h @@ -224,10 +224,26 @@ struct Genode::Rect */ Point center(Area const area) const { - return Point((CT(w()) - CT(area.w))/2, - (CT(h()) - CT(area.h))/2) + at; + return Point { .x = (CT(w()) - CT(area.w))/2, + .y = (CT(h()) - CT(area.h))/2 } + at; } + Point clamp(Point const p) const + { + return Point { .x = max(x1(), min(x2(), p.x)), + .y = max(y1(), min(y2(), p.y)) }; + } + + /** + * Operator for testing non-equality of two rectangled + */ + bool operator != (Rect const &r) const { return r.at != at || r.area != area; } + + /** + * Operator for testing equality of two rectangles + */ + bool operator == (Rect const &r) const { return r.at == at && r.area == area; } + /** * Print rectangle coordinates * diff --git a/repos/base/include/util/string.h b/repos/base/include/util/string.h index 0088a83e8f..8022266322 100644 --- a/repos/base/include/util/string.h +++ b/repos/base/include/util/string.h @@ -84,6 +84,15 @@ struct Genode::Byte_range_ptr : Noncopyable Byte_range_ptr(char *start, size_t num_bytes) : start(start), num_bytes(num_bytes) { } + + void with_skipped_bytes(size_t const n, auto const &fn) + { + if (num_bytes <= n) + return; + + Byte_range_ptr const remainder { start + n, num_bytes - n }; + fn(remainder); + } }; @@ -121,7 +130,7 @@ namespace Genode { /** * Return length of null-terminated string in bytes */ - __attribute((optimize("no-tree-loop-distribute-patterns"))) + __attribute((optimize("no-tree-loop-distribute-patterns"))) inline size_t strlen(const char *s) { size_t res = 0; @@ -181,6 +190,9 @@ namespace Genode { */ inline void *memcpy(void *dst, const void *src, size_t size) { + if (!size) + return dst; + char *d = (char *)dst, *s = (char *)src; size_t i; @@ -272,7 +284,7 @@ namespace Genode { * generation of a 'memset()' call in the 'while' loop * with gcc 10. */ - __attribute((optimize("no-tree-loop-distribute-patterns"))) + __attribute((optimize("no-tree-loop-distribute-patterns"))) inline void *memset(void *dst, uint8_t i, size_t size) { using word_t = unsigned long; diff --git a/repos/base/include/util/xml_node.h b/repos/base/include/util/xml_node.h index d94f709102..466654ceb0 100644 --- a/repos/base/include/util/xml_node.h +++ b/repos/base/include/util/xml_node.h @@ -576,7 +576,7 @@ class Genode::Xml_node start(skip_non_tag_characters(Token(addr, max_len))), end(_search_end_tag(start, num_sub_nodes)) { } - } _tags; + } _tags { _addr, _max_len }; /** * Return true if specified buffer contains a valid XML node @@ -628,14 +628,19 @@ class Genode::Xml_node * * \throw Invalid_syntax */ - Xml_node(char const *addr, size_t max_len = ~0UL) + Xml_node(Const_byte_range_ptr const &bytes) : - _addr(addr), _max_len(max_len), _tags(addr, max_len) + _addr(bytes.start), _max_len(bytes.num_bytes) { if (!_valid(_tags)) throw Invalid_syntax(); } + Xml_node(char const *addr, size_t max_len = ~0UL) + : + Xml_node(Const_byte_range_ptr { addr, max_len }) + { } + /** * Return size of node including start and end tags in bytes */ diff --git a/repos/base/include/vm_session/connection.h b/repos/base/include/vm_session/connection.h index 054de982b0..d3a3357bfd 100644 --- a/repos/base/include/vm_session/connection.h +++ b/repos/base/include/vm_session/connection.h @@ -19,6 +19,7 @@ #ifndef _INCLUDE__VM_SESSION__CONNECTION_H_ #define _INCLUDE__VM_SESSION__CONNECTION_H_ +#include #include #include #include @@ -49,11 +50,7 @@ struct Genode::Vm_connection : Connection, Rpc_client /* for example OMIT_FPU_ON_IRQ */ }; - - struct Call_with_state : Genode::Interface - { - virtual bool call_with_state(Vcpu_state &) = 0; - }; + using With_state = Callable; /** * Virtual CPU @@ -63,28 +60,13 @@ struct Genode::Vm_connection : Connection, Rpc_client */ struct Vcpu : Genode::Noncopyable { - void _with_state(Call_with_state &); + void _with_state(With_state::Ft const &); + + void with_state(auto const &fn) { _with_state(With_state::Fn { fn }); } Native_vcpu &_native_vcpu; Vcpu(Vm_connection &, Allocator &, Vcpu_handler_base &, Exit_config const &); - - template - void with_state(FN const &fn) - { - struct Untyped_fn : Call_with_state - { - FN const &_fn; - Untyped_fn(FN const &fn) : _fn(fn) {} - - bool call_with_state(Vcpu_state &state) override - { - return _fn(state); - } - } untyped_fn(fn); - - _with_state(untyped_fn); - } }; friend class Vcpu; @@ -99,7 +81,7 @@ struct Genode::Vm_connection : Connection, Rpc_client long priority = Cpu_session::DEFAULT_PRIORITY, unsigned long affinity = 0) : - Connection(env, label, Ram_quota { 16*1024 }, Affinity(), + Connection(env, label, Ram_quota { 5*1024*1024 }, Affinity(), Args("priority=", Hex(priority), ", " "affinity=", Hex(affinity))), Rpc_client(cap()) @@ -133,6 +115,11 @@ struct Genode::Vm_connection : Connection, Rpc_client void attach_pic(addr_t vm_addr) override { call(vm_addr); } + + Capability create_vcpu(Thread_capability tcap) override { + return with_upgrade([&] { + return call(tcap); }); + } }; #endif /* _INCLUDE__VM_SESSION__CONNECTION_H_ */ diff --git a/repos/base/include/vm_session/vm_session.h b/repos/base/include/vm_session/vm_session.h index 1872f9ce3c..ba5258014d 100644 --- a/repos/base/include/vm_session/vm_session.h +++ b/repos/base/include/vm_session/vm_session.h @@ -69,6 +69,7 @@ struct Genode::Vm_session : Session */ virtual void attach_pic(addr_t vm_addr) = 0; + /***************************************** ** Access to kernel-specific interface ** *****************************************/ @@ -78,6 +79,12 @@ struct Genode::Vm_session : Session */ struct Native_vcpu; + /** + * Create a virtual CPU. + */ + virtual Capability create_vcpu(Thread_capability) = 0; + + /********************* ** RPC declaration ** *********************/ diff --git a/repos/base/lib/symbols/ld b/repos/base/lib/symbols/ld index 5c705f5af1..2d07886846 100644 --- a/repos/base/lib/symbols/ld +++ b/repos/base/lib/symbols/ld @@ -92,7 +92,7 @@ _ZN6Genode13Shared_objectC1ERNS_3EnvERNS_9AllocatorEPKcNS0_4BindENS0_4KeepE T _ZN6Genode13Shared_objectC2ERNS_3EnvERNS_9AllocatorEPKcNS0_4BindENS0_4KeepE T _ZN6Genode13Shared_objectD1Ev T _ZN6Genode13Shared_objectD2Ev T -_ZN6Genode13Vm_connection4Vcpu11_with_stateERNS0_15Call_with_stateE T +_ZN6Genode13Vm_connection4Vcpu11_with_stateERKNS_8CallableIbJRNS_10Vcpu_stateEEE2FtE T _ZN6Genode13Vm_connection4VcpuC1ERS0_RNS_9AllocatorERNS_17Vcpu_handler_baseERKNS0_11Exit_configE T _ZN6Genode13Vm_connection4VcpuC2ERS0_RNS_9AllocatorERNS_17Vcpu_handler_baseERKNS0_11Exit_configE T _ZN6Genode13Xml_generator4NodeC1ERS0_PKcRKNS1_3_FnE T diff --git a/repos/base/mk/global.mk b/repos/base/mk/global.mk index 6d0dc55043..62b34a7612 100644 --- a/repos/base/mk/global.mk +++ b/repos/base/mk/global.mk @@ -98,6 +98,11 @@ ifneq ($(STDLIB),yes) LD_OPT_NOSTDLIB := -nostdlib -Wl,-nostdlib endif +# +# Prevent the definition of __STDC_HOSTED__ by default +# +CC_OPT_FREESTANDING ?= -ffreestanding + # # Add coverage options # @@ -166,7 +171,8 @@ CC_ADA_WARN ?= -gnatwa $(CC_ADA_WARN_STRICT) # # Aggregate compiler options that are common for C and C++ # -CC_OPT += $(CC_OPT_NOSTDINC) -g $(CC_MARCH) $(CC_OLEVEL) $(CC_OPT_DEP) $(CC_WARN) +CC_OPT += $(CC_OPT_NOSTDINC) $(CC_OPT_FREESTANDING) -g \ + $(CC_MARCH) $(CC_OLEVEL) $(CC_OPT_DEP) $(CC_WARN) # # Incorporate source-file-specific compiler options diff --git a/repos/base/recipes/api/base/hash b/repos/base/recipes/api/base/hash index 38c2481b49..44bbc47734 100644 --- a/repos/base/recipes/api/base/hash +++ b/repos/base/recipes/api/base/hash @@ -1 +1 @@ -2024-08-28 952cb023f90e6d847b6bfc8da87d8f7ba24f842c +2024-12-10 679ce4322aa21ae89a006562d0b7ee2525f49f79 diff --git a/repos/base/recipes/pkg/test-alarm/hash b/repos/base/recipes/pkg/test-alarm/hash index e014853762..f9ea0dc704 100644 --- a/repos/base/recipes/pkg/test-alarm/hash +++ b/repos/base/recipes/pkg/test-alarm/hash @@ -1 +1 @@ -2024-08-28 38800f3da875e5de6f2d561358fa8f56c85a7b3c +2024-12-10 3ffa5a2865cae514a74efae0db61d377b15d763c diff --git a/repos/base/recipes/pkg/test-callable/README b/repos/base/recipes/pkg/test-callable/README new file mode 100644 index 0000000000..a11c7ef1ec --- /dev/null +++ b/repos/base/recipes/pkg/test-callable/README @@ -0,0 +1 @@ +Scenario that tests the util/callable.h utility diff --git a/repos/base/recipes/pkg/test-callable/archives b/repos/base/recipes/pkg/test-callable/archives new file mode 100644 index 0000000000..d09094d232 --- /dev/null +++ b/repos/base/recipes/pkg/test-callable/archives @@ -0,0 +1 @@ +_/src/test-callable diff --git a/repos/base/recipes/pkg/test-callable/hash b/repos/base/recipes/pkg/test-callable/hash new file mode 100644 index 0000000000..ad76672ca4 --- /dev/null +++ b/repos/base/recipes/pkg/test-callable/hash @@ -0,0 +1 @@ +2025-01-14 74d8426380b0552c3c26487469c0aeeec32cbde0 diff --git a/repos/base/recipes/pkg/test-callable/runtime b/repos/base/recipes/pkg/test-callable/runtime new file mode 100644 index 0000000000..b3be06210f --- /dev/null +++ b/repos/base/recipes/pkg/test-callable/runtime @@ -0,0 +1,17 @@ + + + + + [init] result of action.compute: 34 + [init] accessing XML node, state=reset + [init] --- finished callable test --- + + + + + + + + + + diff --git a/repos/base/recipes/pkg/test-ds_ownership/hash b/repos/base/recipes/pkg/test-ds_ownership/hash index ccff0db4c7..6d8d9d7bcb 100644 --- a/repos/base/recipes/pkg/test-ds_ownership/hash +++ b/repos/base/recipes/pkg/test-ds_ownership/hash @@ -1 +1 @@ -2024-08-28 1263204bd1a920d6ea1a414c0a7de506ab225d54 +2024-12-10 bbe7bf0ec279122d824bee5c1195b01afc84dd4b diff --git a/repos/base/recipes/pkg/test-entrypoint/hash b/repos/base/recipes/pkg/test-entrypoint/hash index 5ef9617384..486badcce4 100644 --- a/repos/base/recipes/pkg/test-entrypoint/hash +++ b/repos/base/recipes/pkg/test-entrypoint/hash @@ -1 +1 @@ -2024-08-28 916b2b926332cfcd7960395cbae045c2f79e22e1 +2024-12-10 a7b0af32394148e425159d04d66eaf68d547e235 diff --git a/repos/base/recipes/pkg/test-log/hash b/repos/base/recipes/pkg/test-log/hash index 33bdefb237..359d98afd7 100644 --- a/repos/base/recipes/pkg/test-log/hash +++ b/repos/base/recipes/pkg/test-log/hash @@ -1 +1 @@ -2024-08-28 e9ad6072bfb3d9b3a33bc1bc0d8d569e572a23aa +2024-12-10 2b25d7303e7618744a76789b0bd3b67e6ac6118c diff --git a/repos/base/recipes/pkg/test-mmio/hash b/repos/base/recipes/pkg/test-mmio/hash index 63f14e6aca..6bb99a884f 100644 --- a/repos/base/recipes/pkg/test-mmio/hash +++ b/repos/base/recipes/pkg/test-mmio/hash @@ -1 +1 @@ -2024-08-28 eb64887a9855af98fd59ca684d76a117ad6bc218 +2024-12-10 53cd2f02ef23b3a499863c6d8ece98a34d5f6c1b diff --git a/repos/base/recipes/pkg/test-new_delete/hash b/repos/base/recipes/pkg/test-new_delete/hash index e90d442163..6f2a2c3811 100644 --- a/repos/base/recipes/pkg/test-new_delete/hash +++ b/repos/base/recipes/pkg/test-new_delete/hash @@ -1 +1 @@ -2024-08-28 2d87a4f1e768e5156bb2122e76aefe9b93250b98 +2024-12-10 d598d8570fdf0fac3c44800df6d102a685fefd4f diff --git a/repos/base/recipes/pkg/test-reconstructible/hash b/repos/base/recipes/pkg/test-reconstructible/hash index 46604b10f8..5021bbb37d 100644 --- a/repos/base/recipes/pkg/test-reconstructible/hash +++ b/repos/base/recipes/pkg/test-reconstructible/hash @@ -1 +1 @@ -2024-08-28 9999549086b013d745b7c29d0d73ce16a7b44460 +2024-12-10 a0c00bbc6afd51d935a027aac2f99c724b511475 diff --git a/repos/base/recipes/pkg/test-registry/hash b/repos/base/recipes/pkg/test-registry/hash index 9e20953106..1edc9687cd 100644 --- a/repos/base/recipes/pkg/test-registry/hash +++ b/repos/base/recipes/pkg/test-registry/hash @@ -1 +1 @@ -2024-08-28 eb836fa23731d48906eb17a55f4493a1f1d5f31e +2024-12-10 562d5813faeaea8af1f0d0113eaf8a34bac68278 diff --git a/repos/base/recipes/pkg/test-rm_fault/hash b/repos/base/recipes/pkg/test-rm_fault/hash index 1d80f7affc..5cb4b01b9d 100644 --- a/repos/base/recipes/pkg/test-rm_fault/hash +++ b/repos/base/recipes/pkg/test-rm_fault/hash @@ -1 +1 @@ -2024-08-28 b338f91749569157a0ee70bdac8b63b4604a10f1 +2024-12-10 768c693ffc03d646b6d17db9dba0e09b5824831a diff --git a/repos/base/recipes/pkg/test-rm_fault_no_nox/hash b/repos/base/recipes/pkg/test-rm_fault_no_nox/hash index 77775062de..9d98ecf19f 100644 --- a/repos/base/recipes/pkg/test-rm_fault_no_nox/hash +++ b/repos/base/recipes/pkg/test-rm_fault_no_nox/hash @@ -1 +1 @@ -2024-08-28 0c740d62b29e444a70f19786e73e919929b8a41b +2024-12-10 b0c035bf11e2c58d7d1d63bf419f77f10bb5029c diff --git a/repos/base/recipes/pkg/test-rm_nested/hash b/repos/base/recipes/pkg/test-rm_nested/hash index f936f1ffad..9cdb229d58 100644 --- a/repos/base/recipes/pkg/test-rm_nested/hash +++ b/repos/base/recipes/pkg/test-rm_nested/hash @@ -1 +1 @@ -2024-08-28 dcf9171eaf3917bc7dab03d2821105a25a8d9526 +2024-12-10 aa6bb600bf3fa65d998647297a92bfd156bac23a diff --git a/repos/base/recipes/pkg/test-rm_stress/hash b/repos/base/recipes/pkg/test-rm_stress/hash index 0d8cc58d39..681a8203dd 100644 --- a/repos/base/recipes/pkg/test-rm_stress/hash +++ b/repos/base/recipes/pkg/test-rm_stress/hash @@ -1 +1 @@ -2024-08-28 20da1561fd882dbd113366082471d95b8533e310 +2024-12-10 4f8eed217aacbb49e55c92f4a3478e6480ab7d44 diff --git a/repos/base/recipes/pkg/test-sanitizer/hash b/repos/base/recipes/pkg/test-sanitizer/hash index 2621e23b2e..c617a7b2ae 100644 --- a/repos/base/recipes/pkg/test-sanitizer/hash +++ b/repos/base/recipes/pkg/test-sanitizer/hash @@ -1 +1 @@ -2024-08-28 2179cbeaf81dd04431742572f2f685473cd84594 +2024-12-10 4446fdee68a430143a7f3fad9967cce025313cda diff --git a/repos/base/recipes/pkg/test-stack_smash/hash b/repos/base/recipes/pkg/test-stack_smash/hash index aff8a56547..f50ef1c25f 100644 --- a/repos/base/recipes/pkg/test-stack_smash/hash +++ b/repos/base/recipes/pkg/test-stack_smash/hash @@ -1 +1 @@ -2024-08-28 e9f6ccbe39344ae7f6a9e5787397d352383d50e9 +2024-12-10 86c625e9f1ee148ca591133b949201eb8e35bd62 diff --git a/repos/base/recipes/pkg/test-synced_interface/hash b/repos/base/recipes/pkg/test-synced_interface/hash index 8be6355d77..90c581249d 100644 --- a/repos/base/recipes/pkg/test-synced_interface/hash +++ b/repos/base/recipes/pkg/test-synced_interface/hash @@ -1 +1 @@ -2024-08-28 9a01b6b2d0d295435aa0a02ebc7348a285eeca8d +2024-12-10 4a3be510164139564f2c0fee666b2a44440c1b63 diff --git a/repos/base/recipes/pkg/test-timer/hash b/repos/base/recipes/pkg/test-timer/hash index 535345160b..a66493bc0b 100644 --- a/repos/base/recipes/pkg/test-timer/hash +++ b/repos/base/recipes/pkg/test-timer/hash @@ -1 +1 @@ -2024-08-28 ae27770a9af453d0c385aa2eedf3aeea9d017223 +2024-12-10 ca74ef5ce15156297109d276e4c84de0eb53ea1a diff --git a/repos/base/recipes/pkg/test-tls/hash b/repos/base/recipes/pkg/test-tls/hash index ff94b68744..e2b31f1e00 100644 --- a/repos/base/recipes/pkg/test-tls/hash +++ b/repos/base/recipes/pkg/test-tls/hash @@ -1 +1 @@ -2024-08-28 ebeb7886af2d31d276ab768af6bd8f3220de8953 +2024-12-10 78cfc1241bbeb91375ea7d868dc643da2cb15fdd diff --git a/repos/base/recipes/pkg/test-token/hash b/repos/base/recipes/pkg/test-token/hash index 71c6873ed2..2ce2c30d7b 100644 --- a/repos/base/recipes/pkg/test-token/hash +++ b/repos/base/recipes/pkg/test-token/hash @@ -1 +1 @@ -2024-08-28 0f803f76ccc130569e39451c51626feec05a712b +2024-12-10 87328a1454e601631109593eea99f67d67f6cb58 diff --git a/repos/base/recipes/pkg/test-xml_generator/hash b/repos/base/recipes/pkg/test-xml_generator/hash index e9aee142a4..e91485077f 100644 --- a/repos/base/recipes/pkg/test-xml_generator/hash +++ b/repos/base/recipes/pkg/test-xml_generator/hash @@ -1 +1 @@ -2024-08-28 1fbbbbe8badb32ea8ec9b07cee8f8a5d95360acb +2024-12-10 24326fce4a9a146c83a56b39ac47225704842e77 diff --git a/repos/base/recipes/pkg/test-xml_node/hash b/repos/base/recipes/pkg/test-xml_node/hash index 36f87174ce..455960da96 100644 --- a/repos/base/recipes/pkg/test-xml_node/hash +++ b/repos/base/recipes/pkg/test-xml_node/hash @@ -1 +1 @@ -2024-08-28 b48cf2518250d49a57109e7038d837ab02b94d56 +2024-12-10 ca7dc59df2e889b786ba71945267bc2312921aa2 diff --git a/repos/base/recipes/src/test-alarm/hash b/repos/base/recipes/src/test-alarm/hash index 6f3caf9123..873d584733 100644 --- a/repos/base/recipes/src/test-alarm/hash +++ b/repos/base/recipes/src/test-alarm/hash @@ -1 +1 @@ -2024-08-28 27a6c8bd9c14310c772eceaa6ce8545fad4161a0 +2024-12-10 4c5fdf8c9ec55ce700941db5e92e762b59eadf9d diff --git a/repos/base/recipes/src/test-callable/content.mk b/repos/base/recipes/src/test-callable/content.mk new file mode 100644 index 0000000000..9510e07c8f --- /dev/null +++ b/repos/base/recipes/src/test-callable/content.mk @@ -0,0 +1,2 @@ +SRC_DIR = src/test/callable +include $(GENODE_DIR)/repos/base/recipes/src/content.inc diff --git a/repos/base/recipes/src/test-callable/hash b/repos/base/recipes/src/test-callable/hash new file mode 100644 index 0000000000..4ebcd98156 --- /dev/null +++ b/repos/base/recipes/src/test-callable/hash @@ -0,0 +1 @@ +2025-01-14 86e453af4b2c1696028b76af2d459b3891550f11 diff --git a/repos/base/recipes/src/test-callable/used_apis b/repos/base/recipes/src/test-callable/used_apis new file mode 100644 index 0000000000..df967b96a5 --- /dev/null +++ b/repos/base/recipes/src/test-callable/used_apis @@ -0,0 +1 @@ +base diff --git a/repos/base/recipes/src/test-ds_ownership/hash b/repos/base/recipes/src/test-ds_ownership/hash index cc6790c865..33f5e1bb52 100644 --- a/repos/base/recipes/src/test-ds_ownership/hash +++ b/repos/base/recipes/src/test-ds_ownership/hash @@ -1 +1 @@ -2024-08-28 81579f87117d620bded1b18b94d32f8dfcf798c0 +2024-12-10 4b2f31583181dd5ea91853d185a3891b5de51991 diff --git a/repos/base/recipes/src/test-entrypoint/hash b/repos/base/recipes/src/test-entrypoint/hash index 09841a8644..512d851192 100644 --- a/repos/base/recipes/src/test-entrypoint/hash +++ b/repos/base/recipes/src/test-entrypoint/hash @@ -1 +1 @@ -2024-08-28 353ca16a476ea875269280a482133917404af2b4 +2024-12-10 4ce6ec42b350c805f049a20a150de0bdb9450870 diff --git a/repos/base/recipes/src/test-log/hash b/repos/base/recipes/src/test-log/hash index 58a5c77880..f22d23e9e2 100644 --- a/repos/base/recipes/src/test-log/hash +++ b/repos/base/recipes/src/test-log/hash @@ -1 +1 @@ -2024-08-28 5a105d705f54f092f8a5830a0ae6735ae9a4787a +2024-12-10 97a0bfdbe1db15c82b063e3db2047e4b0137951d diff --git a/repos/base/recipes/src/test-mmio/hash b/repos/base/recipes/src/test-mmio/hash index 233f312dc0..67f9201c98 100644 --- a/repos/base/recipes/src/test-mmio/hash +++ b/repos/base/recipes/src/test-mmio/hash @@ -1 +1 @@ -2024-08-28 1e93c3437d41e6177b8063f48aad15f5ca340956 +2024-12-10 19da5bfd961e5bd3388a6bf771e902edf8720fcc diff --git a/repos/base/recipes/src/test-new_delete/hash b/repos/base/recipes/src/test-new_delete/hash index d18561c597..53677cfa07 100644 --- a/repos/base/recipes/src/test-new_delete/hash +++ b/repos/base/recipes/src/test-new_delete/hash @@ -1 +1 @@ -2024-08-28 215be20a911ed192b38c93319396f6a5b3f7cb6d +2024-12-10 0f5f88878de68adcbadca0ff916f6550fe166691 diff --git a/repos/base/recipes/src/test-reconstructible/hash b/repos/base/recipes/src/test-reconstructible/hash index f8e73fdf76..17d95bf9a1 100644 --- a/repos/base/recipes/src/test-reconstructible/hash +++ b/repos/base/recipes/src/test-reconstructible/hash @@ -1 +1 @@ -2024-08-28 a27dcf2ba32e600ce9b02a18222d8286d9220b6e +2024-12-10 c462994f5183b4fa2e7b510953c61a47758efc8f diff --git a/repos/base/recipes/src/test-registry/hash b/repos/base/recipes/src/test-registry/hash index 8fa7788d32..9a81e59be7 100644 --- a/repos/base/recipes/src/test-registry/hash +++ b/repos/base/recipes/src/test-registry/hash @@ -1 +1 @@ -2024-08-28 34c983d620520d362a146f6c9f062885b2d98c38 +2024-12-10 73f1c2695f605e5ffb4b436ba46861408a1808f5 diff --git a/repos/base/recipes/src/test-rm_fault/hash b/repos/base/recipes/src/test-rm_fault/hash index 0a633b7d4c..a28c2418cb 100644 --- a/repos/base/recipes/src/test-rm_fault/hash +++ b/repos/base/recipes/src/test-rm_fault/hash @@ -1 +1 @@ -2024-08-28 78709e0ea496651d938423d0bb18a0254a04acaf +2024-12-10 edb8428080fb555fce9b579b27d5f1a7b64ba98d diff --git a/repos/base/recipes/src/test-rm_nested/hash b/repos/base/recipes/src/test-rm_nested/hash index cfb3987c66..0d33ecafb5 100644 --- a/repos/base/recipes/src/test-rm_nested/hash +++ b/repos/base/recipes/src/test-rm_nested/hash @@ -1 +1 @@ -2024-08-28 59c0abed548b66f8d54c74e82f1ab0ab7f0d0ee6 +2024-12-10 58e5fe045c8f3364f940b1f279b00feb3a490b31 diff --git a/repos/base/recipes/src/test-rm_stress/hash b/repos/base/recipes/src/test-rm_stress/hash index 485f2fcc74..9879fc1814 100644 --- a/repos/base/recipes/src/test-rm_stress/hash +++ b/repos/base/recipes/src/test-rm_stress/hash @@ -1 +1 @@ -2024-08-28 3ea09d83887d1fc0e07409e68d52c99f794846f9 +2024-12-10 ae413cc25fbcced7f064f2ec3483c85e2add1043 diff --git a/repos/base/recipes/src/test-sanitizer/hash b/repos/base/recipes/src/test-sanitizer/hash index 52c4b35c74..486d8f0af7 100644 --- a/repos/base/recipes/src/test-sanitizer/hash +++ b/repos/base/recipes/src/test-sanitizer/hash @@ -1 +1 @@ -2024-08-28 e4c5cc271035fd20416eca2b23005800bdbe22d5 +2024-12-10 4721bcab9444c1e20213fc97332435c6a8003c4d diff --git a/repos/base/recipes/src/test-segfault/hash b/repos/base/recipes/src/test-segfault/hash index 3b07ec270f..8d18b996a1 100644 --- a/repos/base/recipes/src/test-segfault/hash +++ b/repos/base/recipes/src/test-segfault/hash @@ -1 +1 @@ -2024-08-28 d30834f3bb7de0b8450835323179e126c057206d +2024-12-10 192c06392264f53e181c6f92a5bbcb86273e3918 diff --git a/repos/base/recipes/src/test-stack_smash/hash b/repos/base/recipes/src/test-stack_smash/hash index 7d41efcd8e..3dd0b6e546 100644 --- a/repos/base/recipes/src/test-stack_smash/hash +++ b/repos/base/recipes/src/test-stack_smash/hash @@ -1 +1 @@ -2024-08-28 6106585c8708899bc2b5580583ae3d80a873a4bb +2024-12-10 30d45f61656e670e8cb5e18b060a14f356b88ace diff --git a/repos/base/recipes/src/test-synced_interface/hash b/repos/base/recipes/src/test-synced_interface/hash index 7c3b2287eb..e17aa8b73e 100644 --- a/repos/base/recipes/src/test-synced_interface/hash +++ b/repos/base/recipes/src/test-synced_interface/hash @@ -1 +1 @@ -2024-08-28 548d48fdd30db99f612a172dbb6733b9705de758 +2024-12-10 99611181980e7a782fd155eaf36525218350abd2 diff --git a/repos/base/recipes/src/test-timer/hash b/repos/base/recipes/src/test-timer/hash index 6b33630d2b..42b21c9985 100644 --- a/repos/base/recipes/src/test-timer/hash +++ b/repos/base/recipes/src/test-timer/hash @@ -1 +1 @@ -2024-08-28 e9bcac3043d0ec5b0f99cf70c79c6a4602d7b381 +2024-12-10 d6fa422e41e40f7da917ea6fc4eb75896945c7ec diff --git a/repos/base/recipes/src/test-tls/hash b/repos/base/recipes/src/test-tls/hash index 141411fdf8..2f0a37577d 100644 --- a/repos/base/recipes/src/test-tls/hash +++ b/repos/base/recipes/src/test-tls/hash @@ -1 +1 @@ -2024-08-28 54a1cf1254fb7f5a3e21f19a4e93aaf48244e727 +2024-12-10 380e2f625f1289606d0b1366829b640e0805eb7c diff --git a/repos/base/recipes/src/test-token/hash b/repos/base/recipes/src/test-token/hash index 30f6b65c29..588653869d 100644 --- a/repos/base/recipes/src/test-token/hash +++ b/repos/base/recipes/src/test-token/hash @@ -1 +1 @@ -2024-08-28 a39e757b6833857b4ec32f2060305079d6cc068f +2024-12-10 906f19242a142f336c9abec8924594920cb68dcd diff --git a/repos/base/recipes/src/test-xml_generator/hash b/repos/base/recipes/src/test-xml_generator/hash index 1f107545ee..817eeb17c8 100644 --- a/repos/base/recipes/src/test-xml_generator/hash +++ b/repos/base/recipes/src/test-xml_generator/hash @@ -1 +1 @@ -2024-08-28 8fded3cec4f36bfe77abbed9060c577906c8f643 +2024-12-10 da695ee628e068a05af6e85177612a94409573a5 diff --git a/repos/base/recipes/src/test-xml_node/hash b/repos/base/recipes/src/test-xml_node/hash index 2b7cd83038..92e06208d5 100644 --- a/repos/base/recipes/src/test-xml_node/hash +++ b/repos/base/recipes/src/test-xml_node/hash @@ -1 +1 @@ -2024-08-28 636f2fe518818087444a67b7fea94c7daf5dd5af +2024-12-10 1510f2592e0579d9e404288e020b2096d652e465 diff --git a/repos/base/src/core/cpu_session_component.cc b/repos/base/src/core/cpu_session_component.cc index e00093ea92..edcb431d79 100644 --- a/repos/base/src/core/cpu_session_component.cc +++ b/repos/base/src/core/cpu_session_component.cc @@ -62,9 +62,9 @@ Cpu_session_component::create_thread(Capability pd_cap, try { Cpu_thread_component &thread = *new (&_thread_alloc) Cpu_thread_component( - cap(), *this, _thread_ep, _pager_ep, *pd, platform_pd, - pd_threads, _trace_control_area, _trace_sources, - weight, _weight_to_quota(weight.value), + cap(), *this, _thread_ep, _local_rm, _pager_ep, + *pd, _ram_alloc, platform_pd, pd_threads, _trace_control_area, + _trace_sources, weight, _weight_to_quota(weight.value), _thread_affinity(affinity), _label, name, _priority, utcb); @@ -261,6 +261,7 @@ Cpu_session_component::Cpu_session_component(Rpc_entrypoint &session_ep, : Session_object(session_ep, resources, label, diag), _session_ep(session_ep), _thread_ep(thread_ep), _pager_ep(pager_ep), + _local_rm(local_rm), _ram_alloc(ram_alloc, _ram_quota_guard(), _cap_quota_guard()), _md_alloc(_ram_alloc, local_rm), _thread_alloc(_md_alloc), _priority(0), diff --git a/repos/base/src/core/default_log.cc b/repos/base/src/core/default_log.cc index 1da89e4deb..8193429ae4 100644 --- a/repos/base/src/core/default_log.cc +++ b/repos/base/src/core/default_log.cc @@ -17,7 +17,6 @@ /* base-internal includes */ #include -#include /* core includes */ #include @@ -36,7 +35,8 @@ Genode::Log &Genode::Log::log() Log log { buffer }; }; - return unmanaged_singleton()->log; + static Buffer buffer { }; + return buffer.log; } diff --git a/repos/base/src/core/include/account.h b/repos/base/src/core/include/account.h index 81412178b8..7d3b8dec9a 100644 --- a/repos/base/src/core/include/account.h +++ b/repos/base/src/core/include/account.h @@ -16,6 +16,7 @@ #include #include +#include /* core includes */ #include @@ -132,33 +133,33 @@ class Core::Account _ref_account->_adopt(orphan); }); } + using Transfer_result = Pd_account::Transfer_result; + /** * Transfer quota to/from other account - * - * \throw Unrelated_account - * \throw Limit_exceeded */ - void transfer_quota(Account &other, UNIT amount) + [[nodiscard]] Transfer_result transfer_quota(Account &other, UNIT amount) { { Mutex::Guard guard(_mutex); /* transfers are permitted only from/to the reference account */ if (_ref_account != &other && other._ref_account != this) - throw Unrelated_account(); + return Transfer_result::INVALID; /* make sure to stay within the initial limit */ if (amount.value > _transferrable_quota().value) - throw Limit_exceeded(); + return Transfer_result::EXCEEDED; /* downgrade from this account */ if (!_quota_guard.try_downgrade(amount)) - throw Limit_exceeded(); + return Transfer_result::EXCEEDED; } /* credit to 'other' */ Mutex::Guard guard(other._mutex); other._quota_guard.upgrade(amount); + return Transfer_result::OK; } UNIT limit() const diff --git a/repos/base/src/core/include/core_account.h b/repos/base/src/core/include/core_account.h new file mode 100644 index 0000000000..e4a7167419 --- /dev/null +++ b/repos/base/src/core/include/core_account.h @@ -0,0 +1,60 @@ +/* + * \brief RAM and cap account of the core component + * \author Norman Feske + * \date 2024-12-17 + */ + +/* + * Copyright (C) 2016-2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CORE__INCLUDE__CORE_ACCOUNT_H_ +#define _CORE__INCLUDE__CORE_ACCOUNT_H_ + +namespace Core { struct Core_account; } + + +struct Core::Core_account : Rpc_object +{ + Rpc_entrypoint &_ep; + + Ram_quota_guard ram_quota_guard; + Cap_quota_guard cap_quota_guard; + + Core::Account ram_account { ram_quota_guard, "core" }; + Core::Account cap_account { cap_quota_guard, "core" }; + + Core_account(Rpc_entrypoint &ep, Ram_quota ram, Cap_quota caps) + : _ep(ep), ram_quota_guard(ram), cap_quota_guard(caps) { ep.manage(this); } + + Transfer_result _with_pd(Capability cap, auto const &fn) + { + if (this->cap() == cap) + return Transfer_result::OK; + + return _ep.apply(cap, [&] (Pd_session_component *pd_ptr) { + Transfer_result result = Transfer_result::INVALID; + if (pd_ptr) + fn(*pd_ptr, result); + return result; }); + } + + Transfer_result transfer_quota(Capability to, Cap_quota amount) override + { + return _with_pd(to, [&] (Pd_session_component &pd, Transfer_result &result) { + pd.with_cap_account([&] (Account &to) { + result = cap_account.transfer_quota(to, amount); }); }); + } + + Transfer_result transfer_quota(Capability to, Ram_quota amount) override + { + return _with_pd(to, [&] (Pd_session_component &pd, Transfer_result &result) { + pd.with_ram_account([&] (Account &to) { + result = ram_account.transfer_quota(to, amount); }); }); + } +}; + +#endif /* _CORE__INCLUDE__CORE_ACCOUNT_H_ */ diff --git a/repos/base/src/core/include/core_child.h b/repos/base/src/core/include/core_child.h new file mode 100644 index 0000000000..c42feb0dd0 --- /dev/null +++ b/repos/base/src/core/include/core_child.h @@ -0,0 +1,113 @@ +/* + * \brief Child policy for the init component + * \author Norman Feske + * \date 2024-12-17 + */ + +/* + * Copyright (C) 2016-2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CORE__INCLUDE__CORE_CHILD_H_ +#define _CORE__INCLUDE__CORE_CHILD_H_ + +/* Genode includes */ +#include +#include + +/* core includes */ +#include + +namespace Core { class Core_child; } + + +class Core::Core_child : public Child_policy +{ + private: + + Registry &_services; + Rpc_entrypoint &_ep; + Region_map &_core_rm; + Ram_allocator &_core_ram; + Core_account &_core_account; + + Capability _core_cpu_cap; + Cpu_session &_core_cpu; + + Cap_quota const _cap_quota; + Ram_quota const _ram_quota; + + Id_space _server_ids { }; + + Child _child { _core_rm, _ep, *this }; + + public: + + Core_child(Registry &services, Rpc_entrypoint &ep, + Region_map &core_rm, Ram_allocator &core_ram, + Core_account &core_account, + Cpu_session &core_cpu, Capability core_cpu_cap, + Cap_quota cap_quota, Ram_quota ram_quota) + : + _services(services), _ep(ep), _core_rm(core_rm), _core_ram(core_ram), + _core_account(core_account), + _core_cpu_cap(core_cpu_cap), _core_cpu(core_cpu), + _cap_quota(Child::effective_quota(cap_quota)), + _ram_quota(Child::effective_quota(ram_quota)) + { } + + + /**************************** + ** Child-policy interface ** + ****************************/ + + Name name() const override { return "init"; } + + Route resolve_session_request(Service::Name const &name, + Session_label const &label, + Session::Diag const diag) override + { + Service *service = nullptr; + _services.for_each([&] (Service &s) { + if (!service && s.name() == name) + service = &s; }); + + if (!service) + throw Service_denied(); + + return Route { .service = *service, + .label = label, + .diag = diag }; + } + + void init(Pd_session &, Capability cap) override + { + _ep.apply(cap, [&] (Pd_session_component *pd_ptr) { + if (pd_ptr) + pd_ptr->ref_accounts(_core_account.ram_account, + _core_account.cap_account); }); + + _core_account.transfer_quota(cap, _cap_quota); + _core_account.transfer_quota(cap, _ram_quota); + } + + void init(Cpu_session &session, Capability cap) override + { + session.ref_account(_core_cpu_cap); + _core_cpu.transfer_quota(cap, Cpu_session::quota_lim_upscale(100, 100)); + } + + Ram_allocator &session_md_ram() override { return _core_ram; } + + Pd_account &ref_account() override { return _core_account; } + Capability ref_account_cap() const override { return _core_account.cap(); } + + size_t session_alloc_batch_size() const override { return 128; } + + Id_space &server_id_space() override { return _server_ids; } +}; + +#endif /* _CORE__INCLUDE__CORE_CHILD_H_ */ diff --git a/repos/base/src/core/include/core_env.h b/repos/base/src/core/include/core_env.h deleted file mode 100644 index fef3b37bf8..0000000000 --- a/repos/base/src/core/include/core_env.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * \brief Core-specific environment - * \author Norman Feske - * \author Christian Helmuth - * \date 2006-07-28 - */ - -/* - * Copyright (C) 2006-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _CORE__INCLUDE__CORE_ENV_H_ -#define _CORE__INCLUDE__CORE_ENV_H_ - -/* Genode includes */ -#include - -/* base-internal includes */ -#include - -/* core includes */ -#include -#include -#include -#include -#include - -namespace Core { - - class Core_env; - extern Core_env &core_env(); -} - - -class Core::Core_env : public Noncopyable -{ - private: - - enum { ENTRYPOINT_STACK_SIZE = 20 * 1024 }; - - /* - * Initialize the stack area before creating the first thread, - * which happens to be the '_entrypoint'. - */ - bool _init_stack_area() { init_stack_area(); return true; } - bool _stack_area_initialized = _init_stack_area(); - - Rpc_entrypoint _entrypoint; - Core_region_map _region_map; - Pd_session_component _pd_session; - Synced_ram_allocator _synced_ram_allocator { _pd_session }; - - public: - - Core_env() - : - _entrypoint(nullptr, ENTRYPOINT_STACK_SIZE, "entrypoint", - Affinity::Location()), - _region_map(_entrypoint), - _pd_session(_entrypoint, - _entrypoint, - Session::Resources { - Ram_quota { platform().ram_alloc().avail() }, - Cap_quota { platform().max_caps() } }, - Session::Label("core"), - Session::Diag{false}, - platform().ram_alloc(), - Ram_dataspace_factory::any_phys_range(), - Ram_dataspace_factory::Virt_range { platform().vm_start(), - platform().vm_size() }, - Pd_session_component::Managing_system::PERMITTED, - _region_map, - *((Pager_entrypoint *)nullptr), - "" /* args to native PD */, - platform_specific().core_mem_alloc(), - *((Core::System_control *)nullptr)) - { - _pd_session.init_cap_and_ram_accounts(); - } - - Rpc_entrypoint &entrypoint() { return _entrypoint; } - Ram_allocator &ram_allocator() { return _synced_ram_allocator; } - Region_map &local_rm() { return _region_map; } - - Rpc_entrypoint &signal_ep(); - - Parent *parent() { return nullptr; } - Region_map *rm_session() { return &_region_map; } - Pd_session *pd_session() { return &_pd_session; } - Cpu_session *cpu_session() { ASSERT_NEVER_CALLED; } - Cpu_session_capability cpu_session_cap() { ASSERT_NEVER_CALLED; } - Pd_session_capability pd_session_cap() { return _pd_session.cap(); } -}; - -#endif /* _CORE__INCLUDE__CORE_ENV_H_ */ diff --git a/repos/base/src/core/include/cpu_session_component.h b/repos/base/src/core/include/cpu_session_component.h index 78559171e2..0b0cf54daf 100644 --- a/repos/base/src/core/include/cpu_session_component.h +++ b/repos/base/src/core/include/cpu_session_component.h @@ -43,6 +43,7 @@ class Core::Cpu_session_component : public Session_object, Rpc_entrypoint &_session_ep; Rpc_entrypoint &_thread_ep; Pager_entrypoint &_pager_ep; + Region_map &_local_rm; Constrained_ram_allocator _ram_alloc; Sliced_heap _md_alloc; /* guarded meta-data allocator */ Cpu_thread_allocator _thread_alloc; /* meta-data allocator */ diff --git a/repos/base/src/core/include/cpu_thread_component.h b/repos/base/src/core/include/cpu_thread_component.h index 626f222464..1850e32175 100644 --- a/repos/base/src/core/include/cpu_thread_component.h +++ b/repos/base/src/core/include/cpu_thread_component.h @@ -141,8 +141,10 @@ class Core::Cpu_thread_component : public Rpc_object, Cpu_thread_component(Cpu_session_capability cpu_session_cap, Cpu_session_component &cpu, Rpc_entrypoint &ep, + Region_map &core_rm, Pager_entrypoint &pager_ep, Pd_session_component &pd, + Ram_allocator &cpu_ram, Platform_pd &platform_pd, Pd_threads &pd_threads, Trace::Control_area &trace_control_area, @@ -160,7 +162,8 @@ class Core::Cpu_thread_component : public Rpc_object, _weight(weight), _session_label(label), _name(name), _pd_element(pd_threads, *this), - _platform_thread(platform_pd, quota, name.string(), priority, location, utcb), + _platform_thread(platform_pd, ep, cpu_ram, core_rm, quota, name.string(), + priority, location, utcb), _trace_control_slot(trace_control_area), _trace_sources(trace_sources), _managed_thread_cap(_ep, *this), diff --git a/repos/base/src/core/include/io_mem_session_component.h b/repos/base/src/core/include/io_mem_session_component.h index 93a6ea08bf..08f02095ce 100644 --- a/repos/base/src/core/include/io_mem_session_component.h +++ b/repos/base/src/core/include/io_mem_session_component.h @@ -67,6 +67,12 @@ class Core::Io_mem_session_component : public Rpc_object cacheable(c), req_base(req_base) { } }; + struct Map_local_result + { + addr_t core_local_addr { 0 }; + bool success { }; + }; + struct Io_dataspace_component : Dataspace_component { addr_t req_base; @@ -105,7 +111,8 @@ class Core::Io_mem_session_component : public Rpc_object * * Both parameters - base and size - must be page-aligned. */ - addr_t _map_local(addr_t base, size_t size); + Map_local_result _map_local(addr_t base, size_t size); + /** * Unmap Core-local mapping of region diff --git a/repos/base/src/core/include/io_port_root.h b/repos/base/src/core/include/io_port_root.h index 76eae53aa3..68bd43c259 100644 --- a/repos/base/src/core/include/io_port_root.h +++ b/repos/base/src/core/include/io_port_root.h @@ -25,27 +25,17 @@ namespace Core { } -class Core::Io_port_handler +struct Core::Io_port_handler { - private: + static constexpr size_t STACK_SIZE = 4096; - enum { STACK_SIZE = 4096 }; - Rpc_entrypoint _ep; - - public: - - Io_port_handler(Pd_session &pd_session) : - _ep(&pd_session, STACK_SIZE, "ioport", Affinity::Location()) - { } - - Rpc_entrypoint &entrypoint() { return _ep; } + Rpc_entrypoint handler_ep { nullptr, STACK_SIZE, "ioport", Affinity::Location() }; }; class Core::Io_port_root : private Io_port_handler, public Root_component { - private: Range_allocator &_io_port_alloc; /* I/O port allocator */ @@ -60,17 +50,14 @@ class Core::Io_port_root : private Io_port_handler, /** * Constructor * - * \param cap_session capability allocator * \param io_port_alloc platform IO_PORT allocator * \param md_alloc meta-data allocator to be used by root component */ - Io_port_root(Pd_session &pd_session, - Range_allocator &io_port_alloc, - Allocator &md_alloc) + Io_port_root(Range_allocator &io_port_alloc, Allocator &md_alloc) : - Io_port_handler(pd_session), - Root_component(&entrypoint(), &md_alloc), - _io_port_alloc(io_port_alloc) { } + Root_component(&handler_ep, &md_alloc), + _io_port_alloc(io_port_alloc) + { } }; #endif /* _CORE__INCLUDE__IO_PORT_ROOT_H_ */ diff --git a/repos/base/src/core/include/irq_args.h b/repos/base/src/core/include/irq_args.h index 4630097971..f8c70ee242 100644 --- a/repos/base/src/core/include/irq_args.h +++ b/repos/base/src/core/include/irq_args.h @@ -33,11 +33,14 @@ class Core::Irq_args long const _irq_number; + long const _bdf; + public: Irq_args(const char * args) : - _irq_number(Arg_string::find_arg(args, "irq_number").long_value(-1)) + _irq_number(Arg_string::find_arg(args, "irq_number").long_value(-1)), + _bdf(Arg_string::find_arg(args, "bdf").long_value(-1)) { long irq_trg = Arg_string::find_arg(args, "irq_trigger").long_value(-1); long irq_pol = Arg_string::find_arg(args, "irq_polarity").long_value(-1); @@ -99,6 +102,10 @@ class Core::Irq_args Irq_session::Trigger trigger() const { return _irq_trigger; } Irq_session::Polarity polarity() const { return _irq_polarity; } Irq_session::Type type() const { return _irq_type; } + + unsigned pci_bus() const { return 0xffu & (_bdf >> 8); } + unsigned pci_dev() const { return 0x1fu & (_bdf >> 3); } + unsigned pci_func() const { return 0x07u & _bdf; } }; #endif /* _CORE__INCLUDE__IRQ_ARGS_H_ */ diff --git a/repos/base/src/core/include/irq_root.h b/repos/base/src/core/include/irq_root.h index 6db7b8510c..bc28bae3cd 100644 --- a/repos/base/src/core/include/irq_root.h +++ b/repos/base/src/core/include/irq_root.h @@ -50,15 +50,13 @@ class Core::Irq_root : public Root_component /** * Constructor * - * \param pd_session capability allocator * \param irq_alloc IRQ range that can be assigned to clients * \param md_alloc meta-data allocator to be used by root component */ - Irq_root(Pd_session &pd_session, - Range_allocator &irq_alloc, Allocator &md_alloc) + Irq_root(Range_allocator &irq_alloc, Allocator &md_alloc) : Root_component(&_session_ep, &md_alloc), - _session_ep(&pd_session, STACK_SIZE, "irq", Affinity::Location()), + _session_ep(nullptr, STACK_SIZE, "irq", Affinity::Location()), _irq_alloc(irq_alloc) { } }; diff --git a/repos/base/src/core/include/pager.h b/repos/base/src/core/include/pager.h index 925c099d38..2322a0ce0a 100644 --- a/repos/base/src/core/include/pager.h +++ b/repos/base/src/core/include/pager.h @@ -47,6 +47,8 @@ namespace Core { using Pager_capability = Capability; enum { PAGER_EP_STACK_SIZE = sizeof(addr_t) * 2048 }; + + extern void init_page_fault_handling(Rpc_entrypoint &); } diff --git a/repos/base/src/core/include/pd_root.h b/repos/base/src/core/include/pd_root.h index 547c4035ff..be37f8563a 100644 --- a/repos/base/src/core/include/pd_root.h +++ b/repos/base/src/core/include/pd_root.h @@ -14,10 +14,11 @@ #ifndef _CORE__INCLUDE__PD_ROOT_H_ #define _CORE__INCLUDE__PD_ROOT_H_ -/* Genode */ +/* Genode includes */ #include +#include -/* Core */ +/* core includes */ #include namespace Core { class Pd_root; } diff --git a/repos/base/src/core/include/pd_session_component.h b/repos/base/src/core/include/pd_session_component.h index a897de79e0..ca1cbeebfa 100644 --- a/repos/base/src/core/include/pd_session_component.h +++ b/repos/base/src/core/include/pd_session_component.h @@ -120,6 +120,8 @@ class Core::Pd_session_component : public Session_object diag("released ", _name(type), " cap (", _cap_account, ")"); } + Transfer_result _with_pd_or_core_account(Capability, + auto const &, auto const &); public: using Phys_range = Ram_dataspace_factory::Phys_range; @@ -149,7 +151,7 @@ class Core::Pd_session_component : public Session_object _constrained_md_ram_alloc(*this, _ram_quota_guard(), _cap_quota_guard()), _constrained_core_ram_alloc(_ram_quota_guard(), _cap_quota_guard(), core_mem), _sliced_heap(_constrained_md_ram_alloc, local_rm), - _ram_ds_factory(ep, phys_alloc, phys_range, local_rm, + _ram_ds_factory(ep, phys_alloc, phys_range, _constrained_core_ram_alloc), _signal_broker(_sliced_heap, signal_ep, signal_ep), _rpc_cap_factory(_sliced_heap), @@ -168,6 +170,22 @@ class Core::Pd_session_component : public Session_object ~Pd_session_component(); + void ref_accounts(Account &ram_ref, Account &cap_ref) + { + _ram_account.construct(_ram_quota_guard(), _label, ram_ref); + _cap_account.construct(_cap_quota_guard(), _label, cap_ref); + } + + void with_ram_account(auto const &fn) + { + if (_ram_account.constructed()) fn(*_ram_account); + } + + void with_cap_account(auto const &fn) + { + if (_cap_account.constructed()) fn(*_cap_account); + } + /** * Initialize cap and RAM accounts without providing a reference account * @@ -308,10 +326,10 @@ class Core::Pd_session_component : public Session_object ** Capability and RAM trading and accounting ** ***********************************************/ - Ref_account_result ref_account(Capability) override; + Ref_account_result ref_account(Capability) override; - Transfer_cap_quota_result transfer_quota(Capability, Cap_quota) override; - Transfer_ram_quota_result transfer_quota(Capability, Ram_quota) override; + Transfer_result transfer_quota(Capability, Cap_quota) override; + Transfer_result transfer_quota(Capability, Ram_quota) override; Cap_quota cap_quota() const override { diff --git a/repos/base/src/core/include/platform_services.h b/repos/base/src/core/include/platform_services.h index 5193f7f892..fa4ea494b1 100644 --- a/repos/base/src/core/include/platform_services.h +++ b/repos/base/src/core/include/platform_services.h @@ -14,6 +14,9 @@ #ifndef _CORE__INCLUDE__PLATFORM_SERVICES_H_ #define _CORE__INCLUDE__PLATFORM_SERVICES_H_ +/* Genode includes */ +#include + /* core includes */ #include #include @@ -27,8 +30,7 @@ namespace Genode { namespace Core { /** - * Register platform-specific services at entrypoint, and service - * registry + * Register platform-specific services at entrypoint, and service registry * * \param ep entrypoint used for session components of platform-services * \param md metadata allocator for session components @@ -38,7 +40,10 @@ namespace Core { void platform_add_local_services(Rpc_entrypoint &ep, Sliced_heap &md, Registry ®, - Trace::Source_registry &trace); + Trace::Source_registry &trace, + Ram_allocator &core_ram, + Region_map &core_rm, + Range_allocator &io_port_ranges); } #endif /* _CORE__INCLUDE__PLATFORM_SERVICES_H_ */ diff --git a/repos/base/src/core/include/ram_dataspace_factory.h b/repos/base/src/core/include/ram_dataspace_factory.h index c00a2858fb..497f2c9178 100644 --- a/repos/base/src/core/include/ram_dataspace_factory.h +++ b/repos/base/src/core/include/ram_dataspace_factory.h @@ -87,7 +87,6 @@ class Core::Ram_dataspace_factory : public Ram_allocator, Ram_dataspace_factory(Rpc_entrypoint &ep, Range_allocator &phys_alloc, Phys_range phys_range, - Region_map &, Allocator &allocator) : _ep(ep), _phys_alloc(phys_alloc), _phys_range(phys_range), diff --git a/repos/base/src/core/include/rm_session_component.h b/repos/base/src/core/include/rm_session_component.h index 2621ab0c45..c8377927ed 100644 --- a/repos/base/src/core/include/rm_session_component.h +++ b/repos/base/src/core/include/rm_session_component.h @@ -18,6 +18,7 @@ #include #include #include +#include /* core includes */ #include diff --git a/repos/base/src/core/include/signal_transmitter.h b/repos/base/src/core/include/signal_transmitter.h index a3e4711180..00890fe621 100644 --- a/repos/base/src/core/include/signal_transmitter.h +++ b/repos/base/src/core/include/signal_transmitter.h @@ -39,6 +39,9 @@ namespace Core { * argument. */ void init_core_signal_transmitter(Rpc_entrypoint &ep); + + + Rpc_entrypoint &core_signal_ep(Rpc_entrypoint &core_ep); } #endif /* _CORE__INCLUDE__SIGNAL_TRANSMITTER_H_ */ diff --git a/repos/base/src/core/io_mem_session_component.cc b/repos/base/src/core/io_mem_session_component.cc index ab680b4f8c..aa33e2edbc 100644 --- a/repos/base/src/core/io_mem_session_component.cc +++ b/repos/base/src/core/io_mem_session_component.cc @@ -75,9 +75,13 @@ Io_mem_session_component::_prepare_io_mem(const char *args, } /* request local mapping */ - addr_t local_addr = _map_local(base, size); + auto const map_result = _map_local(base, size); - return Dataspace_attr(size, local_addr, base, _cacheable, req_base); + if (!map_result.success) + return Dataspace_attr(); + + return Dataspace_attr(size, map_result.core_local_addr, base, _cacheable, + req_base); } diff --git a/repos/base/src/core/main.cc b/repos/base/src/core/main.cc index 861a424847..f15e30c428 100644 --- a/repos/base/src/core/main.cc +++ b/repos/base/src/core/main.cc @@ -13,20 +13,13 @@ /* Genode includes */ #include -#include -#include -#include -#include -#include -#include -#include /* base-internal includes */ #include /* core includes */ #include -#include +#include #include #include #include @@ -39,41 +32,8 @@ #include #include #include - -using namespace Core; - - -/*************************************** - ** Core environment/platform support ** - ***************************************/ - -Core_env &Core::core_env() -{ - /* - * Make sure to initialize the platform before constructing the core - * environment. - */ - platform(); - - /* - * By placing the environment as static object here, we ensure that its - * constructor gets called when this function is used the first time. - */ - static Core_env _env; - - /* - * Register signal-source entrypoint at core-local signal-transmitter back - * end - */ - static bool signal_transmitter_initialized; - - if (!signal_transmitter_initialized) - signal_transmitter_initialized = - (init_core_signal_transmitter(_env.signal_ep()), true); - - return _env; -} - +#include +#include Core::Platform &Core::platform_specific() { @@ -82,132 +42,9 @@ Core::Platform &Core::platform_specific() } -Platform_generic &Core::platform() { return platform_specific(); } +Core::Platform_generic &Core::platform() { return platform_specific(); } -struct Genode::Platform { }; - - -Genode::Platform &Genode::init_platform() -{ - core_env(); - static Genode::Platform platform { }; - return platform; -} - - -/** - * Dummy implementation for core that has no parent to ask for resources - */ -void Genode::init_parent_resource_requests(Genode::Env &) {}; - - -/**************** - ** Core child ** - ****************/ - -class Core_child : public Child_policy -{ - private: - - Registry &_services; - - Capability _core_pd_cap; - Pd_session &_core_pd; - - Capability _core_cpu_cap; - Cpu_session &_core_cpu; - - Cap_quota const _cap_quota; - Ram_quota const _ram_quota; - - Id_space _server_ids { }; - - Child _child; - - public: - - /** - * Constructor - */ - Core_child(Registry &services, Region_map &local_rm, - Pd_session &core_pd, Capability core_pd_cap, - Cpu_session &core_cpu, Capability core_cpu_cap, - Cap_quota cap_quota, Ram_quota ram_quota, - Rpc_entrypoint &ep) - : - _services(services), - _core_pd_cap (core_pd_cap), _core_pd (core_pd), - _core_cpu_cap(core_cpu_cap), _core_cpu(core_cpu), - _cap_quota(Child::effective_quota(cap_quota)), - _ram_quota(Child::effective_quota(ram_quota)), - _child(local_rm, ep, *this) - { } - - - /**************************** - ** Child-policy interface ** - ****************************/ - - Name name() const override { return "init"; } - - Route resolve_session_request(Service::Name const &name, - Session_label const &label, - Session::Diag const diag) override - { - Service *service = nullptr; - _services.for_each([&] (Service &s) { - if (!service && s.name() == name) - service = &s; }); - - if (!service) - throw Service_denied(); - - return Route { .service = *service, - .label = label, - .diag = diag }; - } - - void init(Pd_session &session, Capability cap) override - { - session.ref_account(_core_pd_cap); - _core_pd.transfer_quota(cap, _cap_quota); - _core_pd.transfer_quota(cap, _ram_quota); - } - - void init(Cpu_session &session, Capability cap) override - { - session.ref_account(_core_cpu_cap); - _core_cpu.transfer_quota(cap, Cpu_session::quota_lim_upscale(100, 100)); - } - - Pd_session &ref_pd() override { return _core_pd; } - Pd_session_capability ref_pd_cap() const override { return _core_pd_cap; } - - size_t session_alloc_batch_size() const override { return 128; } - - Id_space &server_id_space() override { return _server_ids; } -}; - - -/**************** - ** Signal API ** - ****************/ - -/* - * In contrast to non-core components, core disables the signal thread by - * overriding 'Genode::init_signal_thread' with a dummy. Within core, the - * signal thread is not needed as core is never supposed to receive any - * signals. - */ - -void Genode::init_signal_thread(Env &) { } - - -/******************* - ** Trace support ** - *******************/ - Core::Trace::Source_registry &Core::Trace::sources() { static Source_registry inst; @@ -215,19 +52,57 @@ Core::Trace::Source_registry &Core::Trace::sources() } -/*************** - ** Core main ** - ***************/ +namespace Genode { extern char const *version_string; } -namespace Genode { - extern bool inhibit_tracing; - extern char const *version_string; + +struct Genode::Platform { }; + + +/* + * Executed on the initial stack + */ +Genode::Platform &Genode::init_platform() +{ + init_stack_area(); + + static Platform platform { }; + return platform; } +/* + * Executed on a stack located within the stack area + */ void Genode::bootstrap_component(Genode::Platform &) { - init_exception_handling(*core_env().pd_session(), core_env().local_rm()); + using namespace Core; + + Range_allocator &ram_ranges = Core::platform().ram_alloc(); + Rom_fs &rom_modules = Core::platform().rom_fs(); + Range_allocator &io_mem_ranges = Core::platform().io_mem_alloc(); + Range_allocator &io_port_ranges = Core::platform().io_port_alloc(); + Range_allocator &irq_ranges = Core::platform().irq_alloc(); + Allocator &core_alloc = platform_specific().core_mem_alloc(); + + Ram_quota const avail_ram { ram_ranges.avail() }; + Cap_quota const avail_caps { Core::platform().max_caps() }; + + static constexpr size_t STACK_SIZE = 20 * 1024; + + static Rpc_entrypoint ep { nullptr, STACK_SIZE, "entrypoint", Affinity::Location() }; + + static Core::Core_account core_account { ep, avail_ram, avail_caps }; + + static Ram_dataspace_factory core_ram { + ep, ram_ranges, Ram_dataspace_factory::any_phys_range(), core_alloc }; + + static Core_region_map core_rm { ep }; + + static Rpc_entrypoint &signal_ep = core_signal_ep(ep); + + init_exception_handling(core_ram, core_rm); + init_core_signal_transmitter(signal_ep); + init_page_fault_handling(ep); /* disable tracing within core because it is not fully implemented */ inhibit_tracing = true; @@ -236,24 +111,18 @@ void Genode::bootstrap_component(Genode::Platform &) static Core::Trace::Policy_registry trace_policies; - static Rpc_entrypoint &ep = core_env().entrypoint(); - static Ram_allocator &core_ram_alloc = core_env().ram_allocator(); - static Region_map &local_rm = core_env().local_rm(); - Pd_session &core_pd = *core_env().pd_session(); - Capability core_pd_cap = core_env().pd_session_cap(); - static Registry services; /* * Allocate session meta data on distinct dataspaces to enable independent * destruction (to enable quota trading) of session component objects. */ - static Sliced_heap sliced_heap(core_ram_alloc, local_rm); + static Sliced_heap sliced_heap { core_ram, core_rm }; /* * Factory for creating RPC capabilities within core */ - static Rpc_cap_factory rpc_cap_factory(sliced_heap); + static Rpc_cap_factory rpc_cap_factory { sliced_heap }; static Pager_entrypoint pager_ep(rpc_cap_factory); @@ -262,21 +131,17 @@ void Genode::bootstrap_component(Genode::Platform &) static Core::System_control &system_control = init_system_control(sliced_heap, ep); - static Rom_root rom_root (ep, ep, platform().rom_fs(), sliced_heap); - static Rm_root rm_root (ep, sliced_heap, core_ram_alloc, local_rm, pager_ep); - static Cpu_root cpu_root (core_ram_alloc, local_rm, ep, ep, pager_ep, + static Rom_root rom_root (ep, ep, rom_modules, sliced_heap); + static Rm_root rm_root (ep, sliced_heap, core_ram, core_rm, pager_ep); + static Cpu_root cpu_root (core_ram, core_rm, ep, ep, pager_ep, sliced_heap, Core::Trace::sources()); - static Pd_root pd_root (ep, core_env().signal_ep(), pager_ep, - platform().ram_alloc(), - local_rm, sliced_heap, + static Pd_root pd_root (ep, signal_ep, pager_ep, ram_ranges, core_rm, sliced_heap, platform_specific().core_mem_alloc(), system_control); static Log_root log_root (ep, sliced_heap); - static Io_mem_root io_mem_root (ep, ep, platform().io_mem_alloc(), - platform().ram_alloc(), sliced_heap); - static Irq_root irq_root (*core_env().pd_session(), - platform().irq_alloc(), sliced_heap); - static Trace_root trace_root (core_ram_alloc, local_rm, ep, sliced_heap, + static Io_mem_root io_mem_root (ep, ep, io_mem_ranges, ram_ranges, sliced_heap); + static Irq_root irq_root (irq_ranges, sliced_heap); + static Trace_root trace_root (core_ram, core_rm, ep, sliced_heap, Core::Trace::sources(), trace_policies); static Core_service rom_service (services, rom_root); @@ -289,26 +154,21 @@ void Genode::bootstrap_component(Genode::Platform &) static Core_service trace_service (services, trace_root); /* make platform-specific services known to service pool */ - platform_add_local_services(ep, sliced_heap, services, Core::Trace::sources()); + platform_add_local_services(ep, sliced_heap, services, Core::Trace::sources(), + core_ram, core_rm, io_port_ranges); - size_t const avail_ram_quota = core_pd.avail_ram().value; - size_t const avail_cap_quota = core_pd.avail_caps().value; - - size_t const preserved_ram_quota = 224*1024; - size_t const preserved_cap_quota = 1000; - - if (avail_ram_quota < preserved_ram_quota) { - error("core preservation exceeds platform RAM limit"); + if (!core_account.ram_account.try_withdraw({ 224*1024 })) { + error("core preservation exceeds available RAM"); return; } - if (avail_cap_quota < preserved_cap_quota) { - error("core preservation exceeds platform cap quota limit"); + if (!core_account.cap_account.try_withdraw({ 1000 })) { + error("core preservation exceeds available caps"); return; } - Ram_quota const init_ram_quota { avail_ram_quota - preserved_ram_quota }; - Cap_quota const init_cap_quota { avail_cap_quota - preserved_cap_quota }; + Ram_quota const init_ram_quota = core_account.ram_account.avail(); + Cap_quota const init_cap_quota = core_account.cap_account.avail(); /* CPU session representing core */ static Cpu_session_component @@ -316,19 +176,17 @@ void Genode::bootstrap_component(Genode::Platform &) Session::Resources{{Cpu_session::RAM_QUOTA}, {Cpu_session::CAP_QUOTA}}, "core", Session::Diag{false}, - core_ram_alloc, local_rm, ep, pager_ep, Core::Trace::sources(), "", + core_ram, core_rm, ep, pager_ep, Core::Trace::sources(), "", Affinity::unrestricted(), Cpu_session::QUOTA_LIMIT); - Cpu_session_capability core_cpu_cap = core_cpu.cap(); + log(init_ram_quota.value / (1024*1024), " MiB RAM and ", + init_cap_quota, " caps assigned to init"); - log("", init_ram_quota.value / (1024*1024), " MiB RAM and ", init_cap_quota, " caps " - "assigned to init"); + static Reconstructible + init(services, ep, core_rm, core_ram, core_account, + core_cpu, core_cpu.cap(), init_cap_quota, init_ram_quota); - static Reconstructible - init(services, local_rm, core_pd, core_pd_cap, core_cpu, core_cpu_cap, - init_cap_quota, init_ram_quota, ep); - - platform().wait_for_exit(); + Core::platform().wait_for_exit(); init.destruct(); } diff --git a/repos/base/src/core/pd_session_component.cc b/repos/base/src/core/pd_session_component.cc index ad9a88649a..a43ffc84be 100644 --- a/repos/base/src/core/pd_session_component.cc +++ b/repos/base/src/core/pd_session_component.cc @@ -14,6 +14,7 @@ /* core includes */ #include #include +#include using namespace Core; @@ -100,7 +101,7 @@ size_t Pd_session_component::dataspace_size(Ram_dataspace_capability ds_cap) con } -Pd_session::Ref_account_result Pd_session_component::ref_account(Capability pd_cap) +Pd_session::Ref_account_result Pd_session_component::ref_account(Capability pd_cap) { /* the reference account can be defined only once */ if (_cap_account.constructed()) @@ -116,8 +117,7 @@ Pd_session::Ref_account_result Pd_session_component::ref_account(Capability_ram_account.constructed()) return; - _cap_account.construct(_cap_quota_guard(), _label, *pd->_cap_account); - _ram_account.construct(_ram_quota_guard(), _label, *pd->_ram_account); + ref_accounts(*pd->_ram_account, *pd->_cap_account); result = Ref_account_result::OK; }); @@ -125,63 +125,60 @@ Pd_session::Ref_account_result Pd_session_component::ref_account(Capability pd_cap, Cap_quota amount) +Pd_account::Transfer_result +Pd_session_component::_with_pd_or_core_account(Capability cap, + auto const &pd_fn, auto const &core_fn) { + Transfer_result result = _ep.apply(cap, [&] (Pd_session_component *ptr) { + return (ptr && ptr->_cap_account.constructed()) ? pd_fn(*ptr) + : Transfer_result::INVALID; }); + if (result != Transfer_result::INVALID) + return result; + + return _ep.apply(cap, [&] (Core_account *ptr) { + return ptr ? core_fn(*ptr) : Transfer_result::INVALID; }); +}; + + +Pd_session::Transfer_result +Pd_session_component::transfer_quota(Capability cap, Cap_quota amount) +{ + if (this->cap() == cap) + return Transfer_result::OK; + if (!_cap_account.constructed()) - return Transfer_cap_quota_result::NO_REF_ACCOUNT; + return Transfer_result::INVALID; - if (this->cap() == pd_cap) - return Transfer_cap_quota_result::OK; + auto with_cap_account = [&] (auto const &fn) + { + return _with_pd_or_core_account(cap, + [&] (Pd_session_component &pd) { return fn(*pd._cap_account); }, + [&] (Core_account &core) { return fn(core.cap_account); }); + }; - Transfer_cap_quota_result result = Transfer_cap_quota_result::INVALID_SESSION; - - _ep.apply(pd_cap, [&] (Pd_session_component *pd) { - - if (!pd || !pd->_cap_account.constructed()) - return; - - try { - _cap_account->transfer_quota(*pd->_cap_account, amount); - diag("transferred ", amount, " caps " - "to '", pd->_cap_account->label(), "' (", _cap_account, ")"); - result = Transfer_cap_quota_result::OK; - } - catch (Account::Unrelated_account) { } - catch (Account::Limit_exceeded) { - result = Transfer_cap_quota_result::OUT_OF_CAPS; - } - }); - return result; + return with_cap_account([&] (Account &to) { + return _cap_account->transfer_quota(to, amount); }); } -Pd_session::Transfer_ram_quota_result -Pd_session_component::transfer_quota(Capability pd_cap, Ram_quota amount) +Pd_session::Transfer_result +Pd_session_component::transfer_quota(Capability cap, Ram_quota amount) { + if (this->cap() == cap) + return Transfer_result::OK; + if (!_ram_account.constructed()) - return Transfer_ram_quota_result::NO_REF_ACCOUNT; + return Transfer_result::INVALID; - if (this->cap() == pd_cap) - return Transfer_ram_quota_result::OK; + auto with_ram_account = [&] (auto const &fn) + { + return _with_pd_or_core_account(cap, + [&] (Pd_session_component &pd) { return fn(*pd._ram_account); }, + [&] (Core_account &core) { return fn(core.ram_account); }); + }; - Transfer_ram_quota_result result = Transfer_ram_quota_result::INVALID_SESSION; - - _ep.apply(pd_cap, [&] (Pd_session_component *pd) { - - if (!pd || !pd->_ram_account.constructed()) - return; - - try { - _ram_account->transfer_quota(*pd->_ram_account, amount); - result = Transfer_ram_quota_result::OK; - } - catch (Account::Unrelated_account) { } - catch (Account::Limit_exceeded) { - result = Transfer_ram_quota_result::OUT_OF_RAM; - } - }); - return result; + return with_ram_account([&] (Account &to) { + return _ram_account->transfer_quota(to, amount); }); } diff --git a/repos/base/src/core/platform_services.cc b/repos/base/src/core/platform_services.cc index f925e1bcb2..3b7482726e 100644 --- a/repos/base/src/core/platform_services.cc +++ b/repos/base/src/core/platform_services.cc @@ -16,5 +16,9 @@ void Core::platform_add_local_services(Rpc_entrypoint &, Sliced_heap &, - Registry &, - Trace::Source_registry &) { } + Registry &, + Trace::Source_registry &, + Ram_allocator &, + Region_map &, + Range_allocator &) +{ } diff --git a/repos/base/src/core/signal_transmitter_noinit.cc b/repos/base/src/core/signal_transmitter_noinit.cc index 62ba8f6342..25c1848909 100644 --- a/repos/base/src/core/signal_transmitter_noinit.cc +++ b/repos/base/src/core/signal_transmitter_noinit.cc @@ -15,7 +15,6 @@ */ /* core includes */ -#include #include using namespace Core; @@ -23,4 +22,5 @@ using namespace Core; void Core::init_core_signal_transmitter(Rpc_entrypoint &) { } -Rpc_entrypoint &Core_env::signal_ep() { return _entrypoint; } + +Rpc_entrypoint &Core::core_signal_ep(Rpc_entrypoint &core_ep) { return core_ep; } diff --git a/repos/base/src/core/signal_transmitter_proxy.cc b/repos/base/src/core/signal_transmitter_proxy.cc index 9e9a0f3f79..67fcbf9d7d 100644 --- a/repos/base/src/core/signal_transmitter_proxy.cc +++ b/repos/base/src/core/signal_transmitter_proxy.cc @@ -17,9 +17,9 @@ #include /* core includes */ -#include #include #include +#include /* base-internal includes */ #include @@ -46,9 +46,10 @@ void Signal_transmitter::submit(unsigned cnt) } -Rpc_entrypoint &Core_env::signal_ep() +Rpc_entrypoint &Core::core_signal_ep(Rpc_entrypoint &) { - static Rpc_entrypoint ep(nullptr, ENTRYPOINT_STACK_SIZE, + size_t const STACK_SIZE = 20 * 1024; + static Rpc_entrypoint ep(nullptr, STACK_SIZE, "signal_entrypoint", Affinity::Location()); return ep; } diff --git a/repos/base/src/core/spec/x86/platform_services.cc b/repos/base/src/core/spec/x86/platform_services.cc index 1edc5d85e2..8679bb43f5 100644 --- a/repos/base/src/core/spec/x86/platform_services.cc +++ b/repos/base/src/core/spec/x86/platform_services.cc @@ -13,9 +13,9 @@ /* Genode includes */ #include +#include /* core includes */ -#include #include #include #include @@ -27,11 +27,13 @@ void Core::platform_add_local_services(Rpc_entrypoint &, Sliced_heap &sliced_heap, Registry &local_services, - Trace::Source_registry &) + Trace::Source_registry &, + Ram_allocator &, + Region_map &, + Range_allocator &io_port_ranges) { - static Io_port_root io_port_root(*core_env().pd_session(), - platform().io_port_alloc(), sliced_heap); + static Io_port_root io_port_root(io_port_ranges, sliced_heap); - static Core_service - io_port_ls(local_services, io_port_root); + static Core_service io_port_ls(local_services, + io_port_root); } diff --git a/repos/base/src/include/base/internal/expanding_pd_session_client.h b/repos/base/src/include/base/internal/expanding_pd_session_client.h index fea7aa48fe..928fff60d0 100644 --- a/repos/base/src/include/base/internal/expanding_pd_session_client.h +++ b/repos/base/src/include/base/internal/expanding_pd_session_client.h @@ -83,26 +83,26 @@ struct Genode::Expanding_pd_session_client : Pd_session_client } } - Transfer_ram_quota_result transfer_quota(Pd_session_capability pd_session, Ram_quota amount) override + Transfer_result transfer_quota(Capability to, Ram_quota amount) override { /* * Should the transfer fail because we don't have enough quota, request * the needed amount from the parent. */ for (;;) { - auto const result = Pd_session_client::transfer_quota(pd_session, amount); - if (result != Transfer_ram_quota_result::OUT_OF_RAM) + auto const result = Pd_session_client::transfer_quota(to, amount); + if (result != Transfer_result::EXCEEDED) return result; _request_ram_from_parent(amount.value); } } - Transfer_cap_quota_result transfer_quota(Pd_session_capability pd_session, Cap_quota amount) override + Transfer_result transfer_quota(Capability to, Cap_quota amount) override { for (;;) { - auto const result = Pd_session_client::transfer_quota(pd_session, amount); - if (result != Transfer_cap_quota_result::OUT_OF_CAPS) + auto const result = Pd_session_client::transfer_quota(to, amount); + if (result != Transfer_result::EXCEEDED) return result; _request_caps_from_parent(amount.value); diff --git a/repos/base/src/include/base/internal/globals.h b/repos/base/src/include/base/internal/globals.h index 961eb81ed7..40ecde5d8d 100644 --- a/repos/base/src/include/base/internal/globals.h +++ b/repos/base/src/include/base/internal/globals.h @@ -58,6 +58,8 @@ namespace Genode { void prepare_init_main_thread(); void bootstrap_component(Platform &); void binary_ready_hook_for_platform(); + + extern bool inhibit_tracing; } void genode_exit(int); diff --git a/repos/base/src/include/base/internal/unmanaged_singleton.h b/repos/base/src/include/base/internal/unmanaged_singleton.h deleted file mode 100644 index 0909cd5d71..0000000000 --- a/repos/base/src/include/base/internal/unmanaged_singleton.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * \brief Singleton objects that aren't implicitly constructed or destructed - * \author Norman Feske - * \author Martin Stein - * \date 2013-12-04 - * - * Before enabling the MMU on ARM, the 'cmpxchg' implementation is not always - * guaranteed to work. For example, on the Raspberry Pi, the 'ldrex' as used by - * 'cmpxchg' causes the machine to reboot. After enabling the MMU, everything - * is fine. Hence, we need to avoid executing 'cmpxchg' prior this point. - * Unfortunately, 'cmpxchg' is implicitly called each time when creating a - * singleton object via a local-static object pattern. In this case, the - * compiler generates code that calls the '__cxa_guard_acquire' function of the - * C++ runtime, which, in turn, relies 'cmpxchg' for synchronization. - * - * The utility provided herein is an alternative way to create single object - * instances without implicitly calling 'cmpxchg'. Furthermore, the created - * objects are not destructed automatically at program exit which is useful - * because it prevents the main thread of a program from destructing the - * enviroment it needs to finish program close-down. Because object creation - * is not synchronized via a spin lock, it must not be used in scenarios where - * multiple threads may contend. - */ - -/* - * Copyright (C) 2013-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _INCLUDE__BASE__INTERNAL__UNMANAGED_SINGLETON_H_ -#define _INCLUDE__BASE__INTERNAL__UNMANAGED_SINGLETON_H_ - -/* Genode includes */ -#include - -/** - * Placement new operator - * - * \param p destination address - */ -inline void * operator new(__SIZE_TYPE__, void * p) { return p; } - -/** - * Helper class for the use of unmanaged_singleton with the singleton pattern - * - * If a class wants to make its constructor private to force the singleton - * pattern, it can declare this class as friend to be able to still use the - * unmanaged_singleton template. - */ -struct Unmanaged_singleton_constructor -{ - /** - * Call the constructor of 'T' with arguments 'args' at 'dst' - */ - template - static void call(char * const dst, auto &&... args) { new (dst) T(args...); } -}; - -/** - * Create a singleton object that isn't implicitly constructed or destructed - * - * \param T object type - * \param ALIGNMENT object alignment - * \param ARGS arguments to the object constructor - * - * \return object pointer - */ -template -static inline T * unmanaged_singleton(auto &&... args) -{ - /* - * Each instantiation of the function template with a different type 'T' - * yields a dedicated instance of the local static variables, thereby - * creating the living space for the singleton objects. - */ - enum { OBJECT_SIZE = sizeof(T) / sizeof(char) + 1 }; - static bool object_constructed = false; - static char object_space[OBJECT_SIZE] __attribute__((aligned(ALIGNMENT))); - - /* execute constructor on first call */ - if (!object_constructed) { - object_constructed = true; - Unmanaged_singleton_constructor::call(object_space, args...); - } - return reinterpret_cast(object_space); -} - -#endif /* _INCLUDE__BASE__INTERNAL__UNMANAGED_SINGLETON_H_ */ diff --git a/repos/base/src/lib/base/child.cc b/repos/base/src/lib/base/child.cc index 98834b8a60..c528017798 100644 --- a/repos/base/src/lib/base/child.cc +++ b/repos/base/src/lib/base/child.cc @@ -195,8 +195,8 @@ Parent::Session_result Child::session(Parent::Client::Id id, session.closed_callback = this; try { - Ram_transfer::Remote_account ref_ram_account { _policy.ref_pd(), _policy.ref_pd_cap() }; - Cap_transfer::Remote_account ref_cap_account { _policy.ref_pd(), _policy.ref_pd_cap() }; + Ram_transfer::Remote_account ref_ram_account { _policy.ref_account(), _policy.ref_account_cap() }; + Cap_transfer::Remote_account ref_cap_account { _policy.ref_account(), _policy.ref_account_cap() }; Ram_transfer::Remote_account ram_account { pd(), pd_session_cap() }; Cap_transfer::Remote_account cap_account { pd(), pd_session_cap() }; @@ -342,8 +342,8 @@ Parent::Upgrade_result Child::upgrade(Client::Id id, Parent::Upgrade_args const Arg_string::find_arg(args.string(), "cap_quota").ulong_value(0) }; try { - Ram_transfer::Remote_account ref_ram_account { _policy.ref_pd(), _policy.ref_pd_cap() }; - Cap_transfer::Remote_account ref_cap_account { _policy.ref_pd(), _policy.ref_pd_cap() }; + Ram_transfer::Remote_account ref_ram_account { _policy.ref_account(), _policy.ref_account_cap() }; + Cap_transfer::Remote_account ref_cap_account { _policy.ref_account(), _policy.ref_account_cap() }; Ram_transfer::Remote_account ram_account { pd(), pd_session_cap() }; Cap_transfer::Remote_account cap_account { pd(), pd_session_cap() }; @@ -397,11 +397,11 @@ Parent::Upgrade_result Child::upgrade(Client::Id id, Parent::Upgrade_args const void Child::_revert_quota_and_destroy(Session_state &session) { - Ram_transfer::Remote_account ref_ram_account(_policy.ref_pd(), _policy.ref_pd_cap()); + Ram_transfer::Remote_account ref_ram_account(_policy.ref_account(), _policy.ref_account_cap()); Ram_transfer::Account &service_ram_account = session.service(); Ram_transfer::Remote_account child_ram_account(pd(), pd_session_cap()); - Cap_transfer::Remote_account ref_cap_account(_policy.ref_pd(), _policy.ref_pd_cap()); + Cap_transfer::Remote_account ref_cap_account(_policy.ref_account(), _policy.ref_account_cap()); Cap_transfer::Account &service_cap_account = session.service(); Cap_transfer::Remote_account child_cap_account(pd(), pd_session_cap()); @@ -544,10 +544,10 @@ void Child::session_response(Server::Id id, Session_response response) * withdraw the session quota from the server ('this') to * the reference account, and destroy the session object. */ - Ram_transfer::Remote_account ref_ram_account(_policy.ref_pd(), _policy.ref_pd_cap()); + Ram_transfer::Remote_account ref_ram_account(_policy.ref_account(), _policy.ref_account_cap()); Ram_transfer::Account &service_ram_account = session.service(); - Cap_transfer::Remote_account ref_cap_account(_policy.ref_pd(), _policy.ref_pd_cap()); + Cap_transfer::Remote_account ref_cap_account(_policy.ref_account(), _policy.ref_account_cap()); Cap_transfer::Account &service_cap_account = session.service(); try { @@ -630,6 +630,7 @@ void Child::deliver_session_cap(Server::Id id, Session_capability cap) if (!session.client_exists()) { session.phase = Session_state::CLOSE_REQUESTED; session.service().initiate_request(session); + session.service().wakeup(); return; } diff --git a/repos/base/src/lib/base/default_log.cc b/repos/base/src/lib/base/default_log.cc index ab84657471..609f7b48aa 100644 --- a/repos/base/src/lib/base/default_log.cc +++ b/repos/base/src/lib/base/default_log.cc @@ -20,7 +20,6 @@ /* base-internal includes */ #include -#include using namespace Genode; @@ -100,7 +99,8 @@ void Genode::init_log(Parent &parent) if (log_ptr) return; - back_end_ptr = unmanaged_singleton(parent); + static Back_end back_end { parent }; + back_end_ptr = &back_end; struct Write_fn { void operator () (char const *s) { @@ -111,12 +111,10 @@ void Genode::init_log(Parent &parent) using Buffered_log_output = Buffered_output; - static Buffered_log_output *buffered_log_output = - unmanaged_singleton(Write_fn()); + static Buffered_log_output buffered_log_output { Write_fn() }; + static Log log { buffered_log_output }; + static Trace_output trace { }; - log_ptr = unmanaged_singleton(*buffered_log_output); - - /* enable trace back end */ - trace_ptr = unmanaged_singleton(); + log_ptr = &log; + trace_ptr = &trace; } - diff --git a/repos/base/src/lib/base/env_session_id_space.cc b/repos/base/src/lib/base/env_session_id_space.cc index 4749f42469..baa6c99445 100644 --- a/repos/base/src/lib/base/env_session_id_space.cc +++ b/repos/base/src/lib/base/env_session_id_space.cc @@ -17,15 +17,13 @@ /* base-internal includes */ #include -#include using namespace Genode; Id_space &Genode::env_session_id_space() { - Id_space &id_space = - *unmanaged_singleton >(); + static Id_space id_space { }; /* pre-allocate env session IDs */ static Parent::Client dummy; diff --git a/repos/base/src/lib/base/heartbeat.cc b/repos/base/src/lib/base/heartbeat.cc index 186cef6f0c..88882b97f7 100644 --- a/repos/base/src/lib/base/heartbeat.cc +++ b/repos/base/src/lib/base/heartbeat.cc @@ -13,11 +13,9 @@ /* Genode includes */ #include -#include /* base-internal includes */ #include -#include using namespace Genode; @@ -48,14 +46,7 @@ namespace { } -static Constructible *_heartbeat_handler_ptr = nullptr; - - void Genode::init_heartbeat_monitoring(Env &env) { - if (_heartbeat_handler_ptr) - return; - - _heartbeat_handler_ptr = unmanaged_singleton>(); - _heartbeat_handler_ptr->construct(env); + static Heartbeat_handler heartbeat_handler { env }; } diff --git a/repos/base/src/lib/base/raw_output.cc b/repos/base/src/lib/base/raw_output.cc index 3da8ac8aaf..46c70f1744 100644 --- a/repos/base/src/lib/base/raw_output.cc +++ b/repos/base/src/lib/base/raw_output.cc @@ -16,7 +16,6 @@ #include /* base-internal includes */ -#include #include @@ -24,10 +23,7 @@ Genode::Output &Genode::Raw::_output() { struct Write_fn { void operator () (char const *s) { raw_write_string(s); } }; - using Buffered_raw_output = Buffered_output<256, Write_fn>; + static Buffered_output<256, Write_fn> buffered_raw_output { Write_fn() }; - static Buffered_raw_output *buffered_raw_output = - unmanaged_singleton(Write_fn()); - - return *buffered_raw_output; + return buffered_raw_output; } diff --git a/repos/base/src/lib/base/signal.cc b/repos/base/src/lib/base/signal.cc index 2fbe929f29..5f01180971 100644 --- a/repos/base/src/lib/base/signal.cc +++ b/repos/base/src/lib/base/signal.cc @@ -22,7 +22,6 @@ /* base-internal includes */ #include -#include #include using namespace Genode; @@ -89,7 +88,8 @@ class Signal_handler_thread : Thread, Blockade */ static Constructible & signal_handler_thread() { - return *unmanaged_singleton >(); + static Constructible signal_handler_thread { }; + return signal_handler_thread; } diff --git a/repos/base/src/lib/base/vm.cc b/repos/base/src/lib/base/vm.cc index fa2c76f49d..3c66b9736d 100644 --- a/repos/base/src/lib/base/vm.cc +++ b/repos/base/src/lib/base/vm.cc @@ -24,11 +24,10 @@ static Vm_session::Native_vcpu dummy; struct Genode::Vcpu_state { }; -void Vm_connection::Vcpu::_with_state(Call_with_state &) {}; +void Vm_connection::Vcpu::_with_state(With_state::Ft const &) { }; Vm_connection::Vcpu::Vcpu(Vm_connection &, Allocator &, Vcpu_handler_base &, Exit_config const &) : _native_vcpu(dummy) -{ -} +{ } diff --git a/repos/base/src/lib/cxx/guard.cc b/repos/base/src/lib/cxx/guard.cc index 55324eaec5..feb5f4ca5a 100644 --- a/repos/base/src/lib/cxx/guard.cc +++ b/repos/base/src/lib/cxx/guard.cc @@ -18,7 +18,6 @@ /* base-internal includes */ #include -#include using Blockers = Genode::Registry >; @@ -29,7 +28,8 @@ static Blockers *blockers_ptr; void Genode::init_cxx_guard() { - blockers_ptr = unmanaged_singleton(); + static Blockers blockers { }; + blockers_ptr = &blockers; } diff --git a/repos/base/src/lib/cxx/malloc_free.cc b/repos/base/src/lib/cxx/malloc_free.cc index 7b744c5545..7a0a487246 100644 --- a/repos/base/src/lib/cxx/malloc_free.cc +++ b/repos/base/src/lib/cxx/malloc_free.cc @@ -21,7 +21,6 @@ /* base-internal includes */ #include -#include using namespace Genode; @@ -58,8 +57,8 @@ void Genode::init_cxx_heap(Ram_allocator &ram, Region_map &rm) */ static char initial_block[1024*sizeof(long)]; - cxx_heap_ptr = unmanaged_singleton(&ram, &rm, Heap::UNLIMITED, - initial_block, sizeof(initial_block)); + static Heap heap { &ram, &rm, Heap::UNLIMITED, initial_block, sizeof(initial_block) }; + cxx_heap_ptr = &heap; } diff --git a/repos/base/src/lib/ldso/include/config.h b/repos/base/src/lib/ldso/include/config.h index d4d9c3d8b5..7bb5f41dcc 100644 --- a/repos/base/src/lib/ldso/include/config.h +++ b/repos/base/src/lib/ldso/include/config.h @@ -24,35 +24,17 @@ class Linker::Config : Noncopyable { private: - /* - * Helper to transparently handle the case where no "config" ROM is - * available. - */ - struct Xml_config : Xml_node - { - Constructible _rom { }; + Attached_rom_dataspace const _config; - Xml_config(Env &env) : Xml_node("") - { - try { - _rom.construct(env, "config"); - static_cast(*this) = _rom->xml(); - } - catch (...) { } - } - }; - - Xml_config const _config; - - Bind const _bind = _config.attribute_value("ld_bind_now", false) + Bind const _bind = _config.xml().attribute_value("ld_bind_now", false) ? BIND_NOW : BIND_LAZY; - bool const _verbose = _config.attribute_value("ld_verbose", false); - bool const _check_ctors = _config.attribute_value("ld_check_ctors", true); + bool const _verbose = _config.xml().attribute_value("ld_verbose", false); + bool const _check_ctors = _config.xml().attribute_value("ld_check_ctors", true); public: - Config(Env &env) : _config(env) { } + Config(Env &env) : _config(env, "config") { } Bind bind() const { return _bind; } bool verbose() const { return _verbose; } @@ -67,7 +49,7 @@ class Linker::Config : Noncopyable */ void for_each_library(auto const &fn) const { - _config.with_optional_sub_node("ld", [&] (Xml_node ld) { + _config.xml().with_optional_sub_node("ld", [&] (Xml_node ld) { ld.for_each_sub_node("library", [&] (Xml_node lib) { diff --git a/repos/base/src/lib/ldso/main.cc b/repos/base/src/lib/ldso/main.cc index c9b21c3d52..242820ec70 100644 --- a/repos/base/src/lib/ldso/main.cc +++ b/repos/base/src/lib/ldso/main.cc @@ -22,7 +22,6 @@ #include /* base-internal includes */ -#include #include /* local includes */ @@ -58,7 +57,8 @@ Linker::Region_map::Constructible_region_map &Linker::Region_map::r() * the singleton object as the destructor would try to access * the capabilities also in the forked process. */ - return *unmanaged_singleton(); + static Constructible_region_map rm { }; + return rm; } @@ -637,7 +637,8 @@ extern "C" void init_rtld() static Genode::Constructible &heap() { - return *unmanaged_singleton>(); + static Constructible heap; + return heap; } @@ -684,7 +685,7 @@ void Genode::init_ldso_phdr(Env &env) Linker_area_region_map() { } }; - Linker_area_region_map &ld_rm = *unmanaged_singleton(); + static Linker_area_region_map ld_rm { }; /* * Use a statically allocated initial block to make the first dynamic @@ -781,7 +782,8 @@ void Component::construct(Genode::Env &env) /* load binary and all dependencies */ try { - binary_ptr = unmanaged_singleton(env, *heap(), config, binary_name()); + static Binary binary { env, *heap(), config, binary_name() }; + binary_ptr = &binary; } catch(Linker::Not_found &symbol) { error("LD: symbol not found: '", symbol, "'"); throw; diff --git a/repos/base/src/test/callable/main.cc b/repos/base/src/test/callable/main.cc new file mode 100644 index 0000000000..9fb0af46b8 --- /dev/null +++ b/repos/base/src/test/callable/main.cc @@ -0,0 +1,78 @@ +/* + * \brief Test for the Callable utility + * \author Norman Feske + * \date 2025-01-14 + */ + +/* + * Copyright (C) 2025 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#include +#include +#include + +using namespace Genode; + + +struct Action : Interface +{ + /* + * A functor argument taking 3 ints and returning one int. + */ + using With_3_numbers = Callable; + + virtual int _compute(With_3_numbers::Ft const &) const = 0; + + int compute(auto const &fn) const { return _compute( With_3_numbers::Fn { fn } ); } + + + /* + * A functor argument taking an Xml_node const &, without return value + */ + using With_xml_node = Callable; + + virtual void _with_xml(With_xml_node::Ft const &) = 0; + + void with_xml(auto const &fn) { _with_xml( With_xml_node::Fn { fn } ); } +}; + + +static void test(Action &action) +{ + int const result = action.compute([&] (int a, int b, int c) { + return a + b + c; }); + + log("result of action.compute: ", result); + + action.with_xml([&] (Xml_node const &node) { + log("accessing XML node, state=", + node.attribute_value("state", String<16>())); }); +} + + +void Component::construct(Env &) +{ + log("--- callable test ---"); + + struct Test_action : Action + { + int _compute(With_3_numbers::Ft const &fn) const override + { + return fn(10, 11, 13); + } + + void _with_xml(With_xml_node::Ft const &fn) override + { + Xml_node const node { "" }; + fn(node); + } + } action { }; + + test(action); + + log("--- finished callable test ---"); +} diff --git a/repos/base/src/test/callable/target.mk b/repos/base/src/test/callable/target.mk new file mode 100644 index 0000000000..77fffc14ea --- /dev/null +++ b/repos/base/src/test/callable/target.mk @@ -0,0 +1,3 @@ +TARGET = test-callable +SRC_CC = main.cc +LIBS = base diff --git a/repos/base/src/test/rm_fault/main.cc b/repos/base/src/test/rm_fault/main.cc index b558bc4797..6d87de8679 100644 --- a/repos/base/src/test/rm_fault/main.cc +++ b/repos/base/src/test/rm_fault/main.cc @@ -215,8 +215,10 @@ class Test_child_policy : public Child_policy Binary_name binary_name() const override { return "test-rm_fault"; } - Pd_session &ref_pd() override { return _env.pd(); } - Pd_session_capability ref_pd_cap() const override { return _env.pd_session_cap(); } + Ram_allocator &session_md_ram() override { return _env.pd(); } + + Pd_account &ref_account() override { return _env.pd(); } + Capability ref_account_cap() const override { return _env.pd_session_cap(); } void init(Pd_session &session, Pd_session_capability cap) override { diff --git a/repos/dde_bsd/README b/repos/dde_bsd/README index 80a1932b08..50748ddae9 100644 --- a/repos/dde_bsd/README +++ b/repos/dde_bsd/README @@ -74,6 +74,16 @@ Information about the available mixers and settings in general may be obtained by setting the 'verbose' to 'yes' in the config node. +When multiple microphones are present (e.g., internal microphone in a notebook +and a headset with a microphone), the preferred microphone can be configured +using the 'mic_priority' attribute in the '' node. Valid values are +"internal" and "external" (default). + +! + +The example above tells the driver to prioritize the internal microphone over a +headset. + Examples ======== diff --git a/repos/dde_bsd/ports/dde_bsd.hash b/repos/dde_bsd/ports/dde_bsd.hash index 460d603aaa..0fc8469337 100644 --- a/repos/dde_bsd/ports/dde_bsd.hash +++ b/repos/dde_bsd/ports/dde_bsd.hash @@ -1 +1 @@ -b6086e021be26a2f2a07463c0318b79fd8d0513e +931ffc4e67642ff7c5e639d8ca7b6f5bc345c803 diff --git a/repos/dde_bsd/ports/dde_bsd.port b/repos/dde_bsd/ports/dde_bsd.port index 4e45a44e98..423c46521e 100644 --- a/repos/dde_bsd/ports/dde_bsd.port +++ b/repos/dde_bsd/ports/dde_bsd.port @@ -3,13 +3,12 @@ VERSION := individual (see sources) DOWNLOADS := audio.archive # -# Audio drivers from OpenBSD 7.3 +# Audio drivers from OpenBSD # SRC_DIR_AUDIO := src/lib/audio -VERSION(audio) := 7.3 -BASE_URL := https://cdn.openbsd.org/pub/OpenBSD -URL(audio) := $(BASE_URL)/${VERSION(audio)}/sys.tar.gz -SHA(audio) := bb0dfa11584d68464b3f788e43655f6454bb3ecba8ad5500377630bcf23570ec +VERSION(audio) := 8571a5a +URL(audio) := https://distfiles.sysret.de/Genode/dde_bsd-8571a5a.tar.xz +SHA(audio) := 4a0de8a026d3a844022135c25bab5aabfd5f77146aaedaa6d7253b2cc110efca DIR(audio) := $(SRC_DIR_AUDIO) TAR_OPT(audio) := --strip-components=1 --files-from $(REP_DIR)/audio.list HASH_INPUT += $(REP_DIR)/audio.list diff --git a/repos/dde_bsd/recipes/pkg/bsd_audio/hash b/repos/dde_bsd/recipes/pkg/bsd_audio/hash index b8ccf5f15a..60b199da6d 100644 --- a/repos/dde_bsd/recipes/pkg/bsd_audio/hash +++ b/repos/dde_bsd/recipes/pkg/bsd_audio/hash @@ -1 +1 @@ -2024-08-28 d9b3b6700616965b61c9cf673d1d2924d795437b +2024-12-10 19af2857787095f29ff1156ca12921a84b8c2c88 diff --git a/repos/dde_bsd/recipes/pkg/bsd_audio/runtime b/repos/dde_bsd/recipes/pkg/bsd_audio/runtime index 99cfae20b7..2ee62bf288 100644 --- a/repos/dde_bsd/recipes/pkg/bsd_audio/runtime +++ b/repos/dde_bsd/recipes/pkg/bsd_audio/runtime @@ -1,6 +1,6 @@ - + diff --git a/repos/dde_bsd/recipes/src/bsd_audio/hash b/repos/dde_bsd/recipes/src/bsd_audio/hash index c6969cf50a..14cbe64c8c 100644 --- a/repos/dde_bsd/recipes/src/bsd_audio/hash +++ b/repos/dde_bsd/recipes/src/bsd_audio/hash @@ -1 +1 @@ -2024-08-28 efd2b77afecdc8673da69eaa69f4e8baf3d03950 +2024-12-10 0cb59fb39e1ef2c557804fe74904f262e7cc990d diff --git a/repos/dde_bsd/run/audio_out.run b/repos/dde_bsd/run/audio_out.run index 50bbb6539d..00e5ccc84d 100644 --- a/repos/dde_bsd/run/audio_out.run +++ b/repos/dde_bsd/run/audio_out.run @@ -14,14 +14,18 @@ if {[have_spec linux]} { proc use_record_play_sessions { } { return 1 } create_boot_directory +import_from_depot [depot_user]/src/[base_src] \ + [depot_user]/src/acpi \ + [depot_user]/src/bsd_audio \ + [depot_user]/src/init \ + [depot_user]/src/pci_decode \ + [depot_user]/src/platform \ + [depot_user]/src/report_rom + proc build_targets { } { - set targets { - core init timer - driver/acpi driver/platform app/pci_decode server/report_rom - driver/audio - } + set targets { driver/audio/pci } if {[use_record_play_sessions]} { lappend targets server/record_play_mixer app/waveform_player \ @@ -48,7 +52,7 @@ proc record_play_start_nodes { } { return "" } return { - + @@ -58,12 +62,12 @@ proc record_play_start_nodes { } { - - + +
- + @@ -94,7 +98,7 @@ proc audio_in_out_start_nodes { } { } install_config { - + @@ -108,7 +112,7 @@ install_config { - + @@ -122,15 +126,15 @@ install_config { - - + + - + @@ -139,7 +143,7 @@ install_config { - + @@ -154,7 +158,7 @@ install_config {
- + diff --git a/repos/dde_bsd/src/lib/audio/driver.cc b/repos/dde_bsd/src/lib/audio/driver.cc index b30ddd463f..19ade56860 100644 --- a/repos/dde_bsd/src/lib/audio/driver.cc +++ b/repos/dde_bsd/src/lib/audio/driver.cc @@ -41,6 +41,8 @@ static dev_t const mdev = 0xc0; /* /dev/audioctl */ static bool adev_usuable = false; +/* prioritize mic of headset if plugged in over internal mic */ +static bool mic_priority_external = true; static bool drv_loaded() { @@ -389,6 +391,11 @@ static void configure_mixer(Genode::Env &env, Mixer &mixer, Genode::Xml_node con { using namespace Genode; + typedef String<9> Mic_mode; + + Mic_mode mode = config.attribute_value("mic_priority", Mic_mode("external")); + mic_priority_external = (mode == "internal") ? false : true; + config.for_each_sub_node("mixer", [&] (Xml_node node) { typedef String<32> Field; @@ -615,7 +622,8 @@ extern "C" void notify_record() extern "C" void notify_hp_sense(int const sense) { - set_mixer_value(mixer, "record.adc-0:1_source", sense ? "mic2" : "mic"); + set_mixer_value(mixer, "record.adc-0:1_source", + sense && mic_priority_external ? "mic2" : "mic"); report_mixer_state(mixer, nullptr); } @@ -630,6 +638,8 @@ void Audio::update_config(Genode::Env &env, Genode::Xml_node config) if (mixer.info == nullptr) { return; } configure_mixer(env, mixer, config); + + notify_hp_sense(headphone_plugged() ? 1 : 0); } diff --git a/repos/dde_ipxe/recipes/pkg/ipxe_nic/hash b/repos/dde_ipxe/recipes/pkg/ipxe_nic/hash index acb9781c1c..be8d3b9352 100644 --- a/repos/dde_ipxe/recipes/pkg/ipxe_nic/hash +++ b/repos/dde_ipxe/recipes/pkg/ipxe_nic/hash @@ -1 +1 @@ -2024-08-28 7f3df4651694eb8b127d3dc0aabf16341b4cbf75 +2024-12-10 89e83d53d29fe7dd5d37b53d53715e2e8370c517 diff --git a/repos/dde_ipxe/recipes/src/ipxe_nic/hash b/repos/dde_ipxe/recipes/src/ipxe_nic/hash index a9768ba451..ac5714ac6c 100644 --- a/repos/dde_ipxe/recipes/src/ipxe_nic/hash +++ b/repos/dde_ipxe/recipes/src/ipxe_nic/hash @@ -1 +1 @@ -2024-08-28 d0fdf4e7f4928d752541494d82dc0eb14adabed1 +2024-12-10 88ed31a9ac73fdb34464241cd03d308382dc9b19 diff --git a/repos/dde_linux/include/wifi/ctrl.h b/repos/dde_linux/include/wifi/ctrl.h index 5cc748aa47..df95f66cb5 100644 --- a/repos/dde_linux/include/wifi/ctrl.h +++ b/repos/dde_linux/include/wifi/ctrl.h @@ -14,33 +14,90 @@ #ifndef _WIFI__CTRL_H_ #define _WIFI__CTRL_H_ -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ +#include -#define WPA_CTRL_FD 51 +namespace Wifi { -struct Msg_buffer + /* + * FD used to poll CTRL state from the supplicant. + */ + enum { CTRL_FD = 51, }; + + struct Msg_buffer; + + struct Notify_interface : Genode::Interface + { + virtual void submit_response() = 0; + virtual void submit_event() = 0; + virtual void block_for_processing() = 0; + }; + + void ctrl_init(Msg_buffer &); + +} /* namespace Wifi */ + + +struct Wifi::Msg_buffer { - unsigned char recv[4096*8]; - unsigned char send[4096]; - unsigned recv_id; + char send[4096]; unsigned send_id; - unsigned char event[1024]; + + char recv[4096*8]; + unsigned recv_id; + unsigned last_recv_id; + + char event[1024]; unsigned event_id; -} __attribute__((packed)); + unsigned last_event_id; + + Notify_interface &_notify; + + Msg_buffer(Notify_interface ¬ify) + : _notify { notify } { } + + /* + * Member functions below are called by the + * CTRL interface. + */ + + void notify_response() const { + _notify.submit_response(); } + + void notify_event() const { + _notify.submit_event(); } + + void block_for_processing() { + _notify.block_for_processing(); } + + /* + * Member functions below are called by the + * Manager. + */ + + void with_new_reply(auto const &fn) + { + char const *msg = reinterpret_cast(recv); + /* return early */ + if (last_recv_id == recv_id) + return; + + last_recv_id = recv_id; + fn(msg); + } + + void with_new_event(auto const &fn) + { + char const *msg = reinterpret_cast(event); + + if (last_event_id == event_id) + return; + + last_event_id = event_id; + fn(msg); + } +}; void wpa_ctrl_set_fd(void); -void *wifi_get_buffer(void); -void wifi_notify_cmd_result(void); -void wifi_block_for_processing(void); -void wifi_notify_event(void); - - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - #endif /* _WIFI__CTRL_H_ */ diff --git a/repos/dde_linux/include/wifi/rfkill.h b/repos/dde_linux/include/wifi/rfkill.h index 641b19d8be..ceb1824046 100644 --- a/repos/dde_linux/include/wifi/rfkill.h +++ b/repos/dde_linux/include/wifi/rfkill.h @@ -36,12 +36,20 @@ namespace Wifi { bool rfkill_blocked(); /** - * Set RFKILL state from the frontend + * Set RFKILL state from the manager * * May be only called from an EP context. */ void set_rfkill(bool); + /** + * Trigger RFKILL notification signal + * + * Used by the supplicants RFKILL driver to notify + * the management-layer. + */ + void rfkill_notify(); + } /* namespace Wifi */ #endif /* _WIFI__RFKILL_H_ */ diff --git a/repos/dde_linux/lib/mk/wpa_supplicant.mk b/repos/dde_linux/lib/mk/wpa_supplicant.mk index 3fe6593f26..8d7f0eb40e 100644 --- a/repos/dde_linux/lib/mk/wpa_supplicant.mk +++ b/repos/dde_linux/lib/mk/wpa_supplicant.mk @@ -10,7 +10,8 @@ CC_OPT += -Wno-unused-function CC_CXX_OPT += -fpermissive -SRC_C += main.c ctrl_iface_genode.c +SRC_C += main.c +SRC_CC += ctrl_iface_genode.cc INC_DIR += $(REP_DIR)/include @@ -31,6 +32,7 @@ SRC_C_wpa_supplicant = bssid_ignore.c \ scan.c \ sme.c \ wmm_ac.c \ + wnm_sta.c \ wpa_supplicant.c \ wpas_glue.c # @@ -45,7 +47,7 @@ CC_OPT += -DCONFIG_BACKEND_FILE -DCONFIG_NO_CONFIG_WRITE \ -DCONFIG_SME -DCONFIG_CTRL_IFACE \ -DCONFIG_BGSCAN -DCONFIG_BGSCAN_SIMPLE \ -DCONFIG_OPENSSL_CMAC -DCONFIG_SHA256 \ - -DCONFIG_SAE -DCONFIG_ECC + -DCONFIG_SAE -DCONFIG_ECC -DCONFIG_WNM CC_OPT += -DTLS_DEFAULT_CIPHERS=\"DEFAULT:!EXP:!LOW\" @@ -53,7 +55,7 @@ INC_DIR += $(WS_CONTRIB_DIR)/src/ # common SRC_C_common = ieee802_11_common.c wpa_common.c hw_features_common.c \ - ctrl_iface_common.c sae.c dragonfly.c + ctrl_iface_common.c sae.c dragonfly.c ptksa_cache.c SRC_C += $(addprefix src/common/, $(SRC_C_common)) INC_DIR += $(WS_CONTRIB_DIR)/src/common diff --git a/repos/dde_linux/lib/symbols/wifi b/repos/dde_linux/lib/symbols/wifi index 9f72cd9260..acde1609b6 100644 --- a/repos/dde_linux/lib/symbols/wifi +++ b/repos/dde_linux/lib/symbols/wifi @@ -22,5 +22,7 @@ wifi_ifname T _ZN4Wifi20firmware_get_requestEv T _ZN4Wifi26firmware_establish_handlerERNS_24Firmware_request_handlerE T _ZN4Wifi10set_rfkillEb T +_ZN4Wifi13rfkill_notifyEv T _ZN4Wifi14rfkill_blockedEv T _ZN4Wifi24rfkill_establish_handlerERNS_27Rfkill_notification_handlerE T +convert_errno_from_linux T diff --git a/repos/dde_linux/patches/i915_ggtt.patch b/repos/dde_linux/patches/i915_ggtt.patch new file mode 100644 index 0000000000..17691b5ec2 --- /dev/null +++ b/repos/dde_linux/patches/i915_ggtt.patch @@ -0,0 +1,28 @@ +intel_fb: avoid pagefault, since gt not setup by our port + +--- src/linux/drivers/gpu/drm/i915/i915_gem_evict.c ++++ src/linux/drivers/gpu/drm/i915/i915_gem_evict.c +@@ -187,8 +187,9 @@ + if (i915_is_ggtt(vm)) { + struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); + +- list_for_each_entry(gt, &ggtt->gt_list, ggtt_link) +- intel_gt_retire_requests(gt); ++ if (gt) ++ list_for_each_entry(gt, &ggtt->gt_list, ggtt_link) ++ intel_gt_retire_requests(gt); + } else { + intel_gt_retire_requests(vm->gt); + } +@@ -353,8 +354,9 @@ + struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); + struct intel_gt *gt; + +- list_for_each_entry(gt, &ggtt->gt_list, ggtt_link) +- intel_gt_retire_requests(gt); ++ if (gt) ++ list_for_each_entry(gt, &ggtt->gt_list, ggtt_link) ++ intel_gt_retire_requests(gt); + } else { + intel_gt_retire_requests(vm->gt); + } diff --git a/repos/dde_linux/patches/r8169_disable_irq_coalescing.patch b/repos/dde_linux/patches/r8169_disable_irq_coalescing.patch new file mode 100644 index 0000000000..87e69a57f2 --- /dev/null +++ b/repos/dde_linux/patches/r8169_disable_irq_coalescing.patch @@ -0,0 +1,15 @@ +Disable IRQ coalescing as it seems to not work properly in our +port because at some point triggering interrupts stops altogether. +In this case the netperf tests produce around 0.1(!) MBit/s of +throughput. +--- src/linux/drivers/net/ethernet/realtek/r8169_main.c ++++ src/linux/drivers/net/ethernet/realtek/r8169_main.c +@@ -5374,7 +5374,7 @@ + dev->hw_features |= NETIF_F_RXALL; + dev->hw_features |= NETIF_F_RXFCS; + +- netdev_sw_irq_coalesce_default_on(dev); ++ // netdev_sw_irq_coalesce_default_on(dev); + + /* configure chip for default features */ + rtl8169_set_features(dev, dev->features); diff --git a/repos/dde_linux/patches/wpa_supplicant.patch b/repos/dde_linux/patches/wpa_supplicant.patch index 1c1cc99cab..06c0651934 100644 --- a/repos/dde_linux/patches/wpa_supplicant.patch +++ b/repos/dde_linux/patches/wpa_supplicant.patch @@ -1,8 +1,38 @@ -diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c -index aec179a..6c07c73 100644 +The nl80211 driver patch contains the following changes: + +- Convert inline error values from Linux to libc (FreeBSD) as otherwise + wpa_supplicant might come to the wrong conclusions. + +- Show RFKILL operations at INFO level (so that the always appear in the + log) and generate a interface dis-/enable event that will be handled + by the management layer. + +- Remove netlink messages that rely on newer libnl versions, e.g. signed + value where introduced in 3.2.27. + +- Hardcode the I/O control socket rather than calling socket because it + is not used anyway (see wpa_driver_nl80211/ioctl.cc). --- a/src/drivers/driver_nl80211.c -+++ b/src/drivers/driver_nl80211.c -@@ -1985,13 +1985,13 @@ static void wpa_driver_nl80211_rfkill_blocked(void *ctx) ++++ a/src/drivers/driver_nl80211.c +@@ -487,6 +487,8 @@ + } + + ++extern int convert_errno_from_linux(int linux_errno); ++ + int send_and_recv(struct nl80211_global *global, + struct nl_sock *nl_handle, struct nl_msg *msg, + int (*valid_handler)(struct nl_msg *, void *), +@@ -579,7 +581,7 @@ + /* Always clear the message as it can potentially contain keys */ + nl80211_nlmsg_clear(msg); + nlmsg_free(msg); +- return err.err; ++ return convert_errno_from_linux(err.err); + } + + +@@ -2088,13 +2090,13 @@ { struct wpa_driver_nl80211_data *drv = ctx; @@ -18,7 +48,7 @@ index aec179a..6c07c73 100644 wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, NULL); } -@@ -1999,7 +1999,7 @@ static void wpa_driver_nl80211_rfkill_blocked(void *ctx) +@@ -2102,7 +2104,7 @@ static void wpa_driver_nl80211_rfkill_unblocked(void *ctx) { struct wpa_driver_nl80211_data *drv = ctx; @@ -27,7 +57,7 @@ index aec179a..6c07c73 100644 if (i802_set_iface_flags(drv->first_bss, 1)) { wpa_printf(MSG_DEBUG, "nl80211: Could not set interface UP " "after rfkill unblock"); -@@ -2013,7 +2013,7 @@ static void wpa_driver_nl80211_rfkill_unblocked(void *ctx) +@@ -2116,7 +2118,7 @@ * rtnetlink ifup handler will report interfaces other than the P2P * Device interface as enabled. */ @@ -36,12 +66,34 @@ index aec179a..6c07c73 100644 wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, NULL); } -@@ -8709,7 +8709,7 @@ static void * nl80211_global_init(void *ctx) +@@ -7826,7 +7828,7 @@ + [NL80211_STA_INFO_BEACON_SIGNAL_AVG] = { .type = NLA_U8}, + [NL80211_STA_INFO_RX_DURATION] = { .type = NLA_U64 }, + [NL80211_STA_INFO_ACK_SIGNAL] = { .type = NLA_U8 }, +- [NL80211_STA_INFO_ACK_SIGNAL_AVG] = { .type = NLA_S8 }, ++ [NL80211_STA_INFO_ACK_SIGNAL_AVG] = { .type = NLA_U8 }, + [NL80211_STA_INFO_RX_MPDUS] = { .type = NLA_U32 }, + [NL80211_STA_INFO_FCS_ERROR_COUNT] = { .type = NLA_U32 }, + [NL80211_STA_INFO_TX_DURATION] = { .type = NLA_U64 }, +@@ -7930,9 +7932,9 @@ + nla_get_u8(stats[NL80211_STA_INFO_ACK_SIGNAL]); + data->flags |= STA_DRV_DATA_LAST_ACK_RSSI; + } +- if (stats[NL80211_STA_INFO_ACK_SIGNAL_AVG]) +- data->avg_ack_signal = +- nla_get_s8(stats[NL80211_STA_INFO_ACK_SIGNAL_AVG]); ++ // if (stats[NL80211_STA_INFO_ACK_SIGNAL_AVG]) ++ // data->avg_ack_signal = ++ // nla_get_s8(stats[NL80211_STA_INFO_ACK_SIGNAL_AVG]); + if (stats[NL80211_STA_INFO_RX_MPDUS]) + data->rx_mpdus = nla_get_u32(stats[NL80211_STA_INFO_RX_MPDUS]); + if (stats[NL80211_STA_INFO_FCS_ERROR_COUNT]) +@@ -9939,7 +9941,7 @@ if (wpa_driver_nl80211_init_nl_global(global) < 0) goto err; - global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); -+ global->ioctl_sock = 42; ++ global->ioctl_sock = 12345; /* arbitrarily chosen number b/c it won't be used anyway */ if (global->ioctl_sock < 0) { wpa_printf(MSG_ERROR, "nl80211: socket(PF_INET,SOCK_DGRAM) failed: %s", strerror(errno)); diff --git a/repos/dde_linux/ports/linux-firmware.hash b/repos/dde_linux/ports/linux-firmware.hash index d3384f7ac3..6769e95ac8 100644 --- a/repos/dde_linux/ports/linux-firmware.hash +++ b/repos/dde_linux/ports/linux-firmware.hash @@ -1 +1 @@ -5fff60c84cc929423efe4d572ab9624da974ea25 +5727b3009cb951578cd5478b6c3d2bf14c7236ea diff --git a/repos/dde_linux/ports/linux-firmware.port b/repos/dde_linux/ports/linux-firmware.port index 3431395dc8..5cdaf44483 100644 --- a/repos/dde_linux/ports/linux-firmware.port +++ b/repos/dde_linux/ports/linux-firmware.port @@ -1,8 +1,8 @@ LICENSE := mixed (binary) -VERSION := 896ed3fb7ebd785adc2c232ce1e7008e38f795dc +VERSION := 6726071dc75e85fcf70558073a23faec3e976a08 DOWNLOADS := fw.archive FW_REV := $(VERSION) URL(fw) := https://github.com/cnuke/dde_linux_firmware/archive/$(FW_REV).tar.gz -SHA(fw) := 0120f27ebf7950671bc27dc0a2142da41784a9a5522eeed8ee54508c3f4e1994 +SHA(fw) := ed58a34df08fe962f97e827b3b89861963589b6d8c077d96da2209f1fb1981c6 DIR(fw) := firmware diff --git a/repos/dde_linux/ports/linux.hash b/repos/dde_linux/ports/linux.hash index 63ad33ef51..c86a76eb00 100644 --- a/repos/dde_linux/ports/linux.hash +++ b/repos/dde_linux/ports/linux.hash @@ -1 +1 @@ -403e8fecb5e0303605e2c7b913089710e66ad3d6 +5e77186d61fe216b38cf516c5a40babcfdbd50ad diff --git a/repos/dde_linux/ports/linux.port b/repos/dde_linux/ports/linux.port index 1f645de54b..c9f4661b39 100644 --- a/repos/dde_linux/ports/linux.port +++ b/repos/dde_linux/ports/linux.port @@ -10,6 +10,7 @@ DIR(linux) := src/linux # Patches # PATCH_FILES := i915_irq.patch \ + i915_ggtt.patch \ iwlwifi_break_busy_loop.patch \ iwlwifi_enable_irq_before_pnvm.patch \ iwlwifi_limit_rx_bufs.patch \ @@ -18,6 +19,7 @@ PATCH_FILES := i915_irq.patch \ usb_net_cdc_ncm.patch \ usb_net_pinephone.patch \ usb_net_smsc95xx.patch \ - workqueue_deadlock.patch + workqueue_deadlock.patch \ + r8169_disable_irq_coalescing.patch PATCHES += $(addprefix patches/,$(PATCH_FILES)) diff --git a/repos/dde_linux/ports/wpa_supplicant.hash b/repos/dde_linux/ports/wpa_supplicant.hash index 8eb5196c87..bd65b206b1 100644 --- a/repos/dde_linux/ports/wpa_supplicant.hash +++ b/repos/dde_linux/ports/wpa_supplicant.hash @@ -1 +1 @@ -6242912dd6f6c22550a7fe0b443bfd80c5cfedae +15974e67af9112d919f1625a5c2ed2d996cdbdfb diff --git a/repos/dde_linux/ports/wpa_supplicant.port b/repos/dde_linux/ports/wpa_supplicant.port index 6fb96266d0..eb4da6d1af 100644 --- a/repos/dde_linux/ports/wpa_supplicant.port +++ b/repos/dde_linux/ports/wpa_supplicant.port @@ -1,12 +1,12 @@ LICENSE := BSD-3-Clause -VERSION := 2.10 +VERSION := 2.11 DOWNLOADS := wpa_supplicant.archive # # wpa_supplicant sources # -URL(wpa_supplicant) := https://w1.fi/releases/wpa_supplicant-2.10.tar.gz -SHA(wpa_supplicant) := 20df7ae5154b3830355f8ab4269123a87affdea59fe74fe9292a91d0d7e17b2f +URL(wpa_supplicant) := https://w1.fi/releases/wpa_supplicant-2.11.tar.gz +SHA(wpa_supplicant) := 912ea06f74e30a8e36fbb68064d6cdff218d8d591db0fc5d75dee6c81ac7fc0a DIR(wpa_supplicant) := src/app/wpa_supplicant # diff --git a/repos/dde_linux/recipes/api/virt_linux/hash b/repos/dde_linux/recipes/api/virt_linux/hash index d7763a6de7..e066386daf 100644 --- a/repos/dde_linux/recipes/api/virt_linux/hash +++ b/repos/dde_linux/recipes/api/virt_linux/hash @@ -1 +1 @@ -2024-08-28 203107a559eaf5f4d23126894356dab42c76384a +2024-11-19 456f1dc7b465e43a487e98cae063f4b292ab14d0 diff --git a/repos/dde_linux/recipes/pkg/wireguard/hash b/repos/dde_linux/recipes/pkg/wireguard/hash index b4de56c928..c8682cc48e 100644 --- a/repos/dde_linux/recipes/pkg/wireguard/hash +++ b/repos/dde_linux/recipes/pkg/wireguard/hash @@ -1 +1 @@ -2024-08-28 461a4a470e6385e77585a1ed7b2d1c0f6a280275 +2024-12-10 5709222115ce2978146c734b9d64ed8ee41d8c66 diff --git a/repos/dde_linux/recipes/src/usb_hid/hash b/repos/dde_linux/recipes/src/usb_hid/hash index 13ff8ca28f..ca73e18d7a 100644 --- a/repos/dde_linux/recipes/src/usb_hid/hash +++ b/repos/dde_linux/recipes/src/usb_hid/hash @@ -1 +1 @@ -2024-08-28 1eca1b3baa82ba8cc89c6f0e34de3e0659ce2c13 +2024-12-10 a1bc3222e4396d1234079add6515167e679c0fa5 diff --git a/repos/dde_linux/recipes/src/usb_net/hash b/repos/dde_linux/recipes/src/usb_net/hash index c8354a652a..807f4ae3f4 100644 --- a/repos/dde_linux/recipes/src/usb_net/hash +++ b/repos/dde_linux/recipes/src/usb_net/hash @@ -1 +1 @@ -2024-08-28 f8ca538f97a744ec3f1c83c9dfce43c529ee377d +2024-12-10 a52995e90a5ed10b21494ee62c033feb5c30d491 diff --git a/repos/dde_linux/recipes/src/vfs_lxip/hash b/repos/dde_linux/recipes/src/vfs_lxip/hash index 8847faca88..e491fd2a23 100644 --- a/repos/dde_linux/recipes/src/vfs_lxip/hash +++ b/repos/dde_linux/recipes/src/vfs_lxip/hash @@ -1 +1 @@ -2024-08-28 e7253c5f91faf73ea45e0e1dac8f3b0ce3d05096 +2024-12-10 37f67ddb7b697b6dabfd5d9a9c2a38a3ea85576a diff --git a/repos/dde_linux/recipes/src/wireguard/hash b/repos/dde_linux/recipes/src/wireguard/hash index 72876e348e..80d7380329 100644 --- a/repos/dde_linux/recipes/src/wireguard/hash +++ b/repos/dde_linux/recipes/src/wireguard/hash @@ -1 +1 @@ -2024-08-28 17ae0534a3585c0bf11f818ec5163472b7a0d628 +2024-12-10 5e4d8594da6140470549e3a701991486a04fb42c diff --git a/repos/dde_linux/run/nic_router_uplinks.run b/repos/dde_linux/run/nic_router_uplinks.run index 77fe902d95..a17f051731 100644 --- a/repos/dde_linux/run/nic_router_uplinks.run +++ b/repos/dde_linux/run/nic_router_uplinks.run @@ -133,8 +133,8 @@ install_config { - - + + diff --git a/repos/dde_linux/run/wifi_config.inc b/repos/dde_linux/run/wifi_config.inc new file mode 100644 index 0000000000..b3a4dcf643 --- /dev/null +++ b/repos/dde_linux/run/wifi_config.inc @@ -0,0 +1,71 @@ +# +# This file includes snippets to generate the 'wifi_config' for the +# various wireless LAN driver for each test run-script. +# + +proc wifi_ssid { } { + return $::env(GENODE_WIFI_SSID) +} + +proc wifi_psk { } { + return $::env(GENODE_WIFI_PSK) +} + +proc wifi_wpa { } { + if {![info exists ::env(GENODE_WIFI_WPA)]} { + return WPA2 + } + return $::env(GENODE_WIFI_WPA) +} + +proc wifi_verbose { } { + if {![info exists ::env(GENODE_WIFI_VERBOSE)]} { + return false + } + return true +} + +# +# wifi-driver config generator (supporting a network list) +# +# You may script your tests with this function in the dynamic_rom config below. +# The syntax for the networks parameter is +# +# { ssid protection passphrase explicit_scan } +# +# Example dynamic_rom config: +# +# { +# } [wifi_config 5 no [list "net1 WPA2 net1_psk no" "net2 WPA2 net2_psk no"]] { +# +# +# } [wifi_config 5 no [list "net1 WPA2 net1_psk no" "net2 WPA2 net2_psk yes"]] { +# } +# + +set wifi_verbose false + +proc wifi_config { scan_interval update_quality_interval rfkill networks } { + global wifi_verbose + + set config "\n" + foreach n $networks { + if {[lindex $n 4] == "yes"} { + append config " \n" + } + append config " \n" + } + append config "\n" + + return $config +} + diff --git a/repos/dde_linux/src/driver/usb_net/lx_user.c b/repos/dde_linux/src/driver/usb_net/lx_user.c index d038379a95..e5d7a3698f 100644 --- a/repos/dde_linux/src/driver/usb_net/lx_user.c +++ b/repos/dde_linux/src/driver/usb_net/lx_user.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -30,230 +31,17 @@ struct task_struct *lx_user_new_usb_task(int (*func)(void*), void *args, } -static struct genode_uplink *dev_genode_uplink(struct net_device *dev) -{ - return (struct genode_uplink *)dev->ifalias; -} - - -struct genode_uplink_rx_context -{ - struct net_device *dev; -}; - - -struct genode_uplink_tx_packet_context -{ - struct sk_buff *skb; -}; - - -static unsigned long uplink_tx_packet_content(struct genode_uplink_tx_packet_context *ctx, - char *dst, unsigned long dst_len) -{ - struct sk_buff * const skb = ctx->skb; - - skb_push(skb, ETH_HLEN); - - if (dst_len < skb->len) { - printk("uplink_tx_packet_content: packet exceeds uplink packet size\n"); - memset(dst, 0, dst_len); - return 0; - } - - skb_copy_from_linear_data(skb, dst, skb->len); - - /* clear unused part of the destination buffer */ - memset(dst + skb->len, 0, dst_len - skb->len); - - return skb->len; -} - - -static rx_handler_result_t handle_rx(struct sk_buff **pskb) -{ - struct sk_buff *skb = *pskb; - struct net_device *dev = skb->dev; - struct genode_uplink_tx_packet_context ctx = { .skb = skb }; - - /* if uplink still exists */ - if (dev->ifalias) { - bool progress = genode_uplink_tx_packet(dev_genode_uplink(dev), - uplink_tx_packet_content, - &ctx); - if (!progress) - printk("handle_rx: uplink saturated, dropping packet\n"); - } - - kfree_skb(skb); - return RX_HANDLER_CONSUMED; -} - - -/** - * Create Genode uplink for given net device - * - * The uplink is registered at the dev->ifalias pointer. - */ -static void handle_create_uplink(struct net_device *dev) -{ - struct genode_uplink_args args; - - if (dev_genode_uplink(dev)) - return; - - if (!netif_carrier_ok(dev)) - return; - - printk("create uplink for net device %s\n", &dev->name[0]); - - memset(&args, 0, sizeof(args)); - - if (dev->addr_len != sizeof(args.mac_address)) { - printk("error: net device has unexpected addr_len %u\n", dev->addr_len); - return; - } - - { - unsigned i; - for (i = 0; i < dev->addr_len; i++) - args.mac_address[i] = dev->dev_addr[i]; - } - - args.label = &dev->name[0]; - - dev->ifalias = (struct dev_ifalias *)genode_uplink_create(&args); -} - - -static void handle_destroy_uplink(struct net_device *dev) -{ - struct genode_uplink *uplink = dev_genode_uplink(dev); - - if (!uplink) - return; - - if (netif_carrier_ok(dev)) - return; - - printk("destroy uplink for net device %s\n", &dev->name[0]); - genode_uplink_destroy(uplink); - - dev->ifalias = NULL; -} - - -static genode_uplink_rx_result_t uplink_rx_one_packet(struct genode_uplink_rx_context *ctx, - char const *ptr, unsigned long len) -{ - struct sk_buff *skb = alloc_skb(len, GFP_KERNEL); - - if (!skb) { - printk("alloc_skb failed\n"); - return GENODE_UPLINK_RX_RETRY; - } - - skb_copy_to_linear_data(skb, ptr, len); - skb_put(skb, len); - skb->dev = ctx->dev; - - if (dev_queue_xmit(skb) < 0) { - printk("lx_user: failed to xmit packet\n"); - return GENODE_UPLINK_RX_REJECTED; - } - - return GENODE_UPLINK_RX_ACCEPTED; -} - - -/* - * custom MAC address - */ -bool use_mac_address; -unsigned char mac_address[6]; -static bool mac_address_configured = false; - -static void handle_mac_address(struct net_device *dev) -{ - int err; - struct sockaddr addr; - struct genode_mac_address dev_addr; - - if (mac_address_configured || !netif_device_present(dev)) return; - - if (use_mac_address) { - memcpy(&addr.sa_data, mac_address, ETH_ALEN); - addr.sa_family = dev->type; - err = dev_set_mac_address(dev, &addr, NULL); - if (err < 0) - printk("Warning: Could not set configured MAC address: %pM (err=%d)\n", - mac_address, err); - } - - memcpy(dev_addr.addr, dev->dev_addr, sizeof(dev_addr)); - genode_mac_address_register(dev->name, dev_addr); - - mac_address_configured =true; -} - - -static int network_loop(void *arg) -{ - for (;;) { - - struct net_device *dev; - - for_each_netdev(&init_net, dev) { - - handle_mac_address(dev); - - /* enable link sensing, repeated calls are handled by testing IFF_UP */ - dev_open(dev, 0); - - /* install rx handler once */ - if (!netdev_is_rx_handler_busy(dev)) - netdev_rx_handler_register(dev, handle_rx, NULL); - - /* respond to cable plug/unplug */ - handle_create_uplink(dev); - handle_destroy_uplink(dev); - - /* transmit packets received from the uplink session */ - if (netif_carrier_ok(dev)) { - - struct genode_uplink_rx_context ctx = { .dev = dev }; - - while (genode_uplink_rx(dev_genode_uplink(dev), - uplink_rx_one_packet, - &ctx)); - } - }; - - /* block until lx_emul_task_unblock */ - lx_emul_task_schedule(true); - } - return 0; -} - - -static struct task_struct *net_task; - void lx_user_init(void) { - pid_t pid; - lx_emul_usb_client_init(); - - pid = kernel_thread(network_loop, NULL, "network_loop", - CLONE_FS | CLONE_FILES); - net_task = find_task_by_pid_ns(pid, NULL); + lx_emul_nic_init(); } void lx_user_handle_io(void) { lx_emul_usb_client_ticker(); - if (net_task) lx_emul_task_unblock(net_task); + lx_emul_nic_handle_io(); } @@ -269,11 +57,10 @@ void rtmsg_ifinfo(int type, struct net_device * dev, unsigned int change, gfp_t flags, u32 portid, const struct nlmsghdr *nlh) { - /* trigger handle_create_uplink / handle_destroy_uplink */ - if (net_task) lx_emul_task_unblock(net_task); + lx_emul_nic_handle_io(); if (force_uplink_destroy) { - struct genode_uplink *uplink = dev_genode_uplink(dev); + struct genode_uplink *uplink = (struct genode_uplink *)dev->ifalias; printk("force destroy uplink for net device %s\n", &dev->name[0]); genode_uplink_destroy(uplink); force_uplink_destroy = false; @@ -284,7 +71,9 @@ void rtmsg_ifinfo(int type, struct net_device * dev, void lx_emul_usb_client_device_unregister_callback(struct usb_device *) { force_uplink_destroy = true; - mac_address_configured = false; + + /* set mac as unconfigured by setting nothing */ + lx_emul_nic_set_mac_address(NULL, 0); } diff --git a/repos/dde_linux/src/driver/usb_net/main.cc b/repos/dde_linux/src/driver/usb_net/main.cc index 8ae8a8d458..497afb9980 100644 --- a/repos/dde_linux/src/driver/usb_net/main.cc +++ b/repos/dde_linux/src/driver/usb_net/main.cc @@ -23,15 +23,13 @@ #include #include #include +#include /* C-interface */ #include using namespace Genode; -extern bool use_mac_address; -extern unsigned char mac_address[6]; - struct Main { Env &env; @@ -90,12 +88,10 @@ struct Main usb_config = config_rom.xml().attribute_value("configuration", 0ul); /* retrieve possible MAC */ - use_mac_address = config_rom.xml().has_attribute("mac"); - if (use_mac_address) { + if (config_rom.xml().has_attribute("mac")) { auto const mac = config_rom.xml().attribute_value("mac", Nic::Mac_address{}); - mac.copy(mac_address); - use_mac_address = true; log("Trying to use configured mac: ", mac); + lx_emul_nic_set_mac_address(mac.addr, sizeof(mac.addr)); } } }; diff --git a/repos/dde_linux/src/driver/usb_net/target.inc b/repos/dde_linux/src/driver/usb_net/target.inc index 7fbee1840b..08d2559ef0 100644 --- a/repos/dde_linux/src/driver/usb_net/target.inc +++ b/repos/dde_linux/src/driver/usb_net/target.inc @@ -8,6 +8,7 @@ SRC_C += dummies.c \ lx_emul.c \ lx_user.c +SRC_C += lx_emul/nic.c SRC_C += lx_emul/virt/shadow/drivers/usb/core/buffer.c SRC_C += lx_emul/virt/shadow/drivers/usb/core/hcd.c SRC_C += lx_emul/virt/usb_client.c diff --git a/repos/dde_linux/src/driver/wifi/README b/repos/dde_linux/src/driver/wifi/README index d964b409b9..d4f812d98e 100644 --- a/repos/dde_linux/src/driver/wifi/README +++ b/repos/dde_linux/src/driver/wifi/README @@ -1,5 +1,5 @@ -The wifi component is a port of the Linux mac802.11 stack as well as -libnl and wpa_supplicant to Genode. Depending on the used platform it +The wifi component consists of a port of the Linux mac802.11 stack as well +as libnl and wpa_supplicant to Genode. Depending on the used platform it features a selection of drivers for wireless devices. For example on the PC platform it contains the ath9k, iwlwifi and rtlwifi drivers for PCI(e) devices. @@ -10,14 +10,18 @@ The 'wifi' binary is the generic management part that includes the Wifi configuration interface and the 'wpa_supplicant'. A suitable driver library is loaded at run-time (see section [Debugging]). -To start the component on the PC platform the following configuration snippet -can be used: + +Configuration +~~~~~~~~~~~~~ + +This configuration snippet shows how to start the component on the PC +platform. ! ! ! ! -! +! ! ! ! @@ -38,14 +42,14 @@ can be used: ! ! -On other platforms the wifi library will be different. The following -snippet illustrates the use of the driver on the PinePhone: +On other platforms the wifi library will be different. So, the +following snippet illustrates the use of the driver on the PinePhone. ! ! ! ! -! +! ! ! ! @@ -79,88 +83,150 @@ directory in the driver's local VFS. It is up to the configuration how those files are made available. In these examples they are contained in an '.tar' archive that is request as a ROM module. -The driver will request access to the ROM module 'wifi_config' to -connect to a network: +The driver will request access to the 'wifi_config' ROM module that +contains its actual configuration in the '' node. This +node features the following attributes. -! -! -! +* :scan_interval: sets the time interval in seconds in which scan + operations are requested and is used when not already connected + to a network. The default is 5 seconds. -To temporarily prevent any radio activity, the 'rfkill' attribute -can be set to 'true'. +* :update_quality_interval: sets the time interval in which the current + signal quality of the connected access point is updated (RSSI polling). + The default value is 30 seconds. -If the network is protected by, e.g., WPA/WPA2/WPA3, the protection type, -either 'WPA', 'WPA2' or 'WPA3' as well as the the passphrase have to be -specified. -The 'bssid' attribute can be used to select a specifc accesspoint within a -network. Of all attributes only the 'ssid' attribute is mandatory, all others -are optional and should only be used when needed. +* :rfkill: allows to temporarily prevent any radio activity. The + default is 'false'. -The configuration may contain more than one network. In This case the driver -will try to select the best one it gets a response from. To prevent it -from automatically joining the network the 'auto_connect' attribute must be -set to 'false'; the default value is 'true'. If the 'explicit_scan' attribute -is set, the driver will pro-actively scan for a hidden network with the given -SSID: +* :bgscan: is an expert option that configures the way the + supplicant performs background scanning to steer or rather optimize + roaming decisions within the same network (SSID). The syntax of the + option string corresponds to the original WPA-supplicant 'bgscan' option. + The default value is set to 'simple:30:-70:600'. This functionality can + be disabled by specifying an empty value, e.g. 'bgscan=""'. If bgscan is + disabled the 'accesspoints' report will not be updated while the + supplicant is connected to a network. -! +* :log_level: allows for steering the verbosity of the supplicant + and may assist while diagnosing problems with the driver. + Valid values correspond to levels used by the supplicant + and are as follows 'excessive', 'msgdump', 'debug', 'info', + 'warning' and 'error'. The default value is 'error' and configures + the least amount of verbosity. + +* :verbose: allows for logging of diagnostic messages generated + by the managing portion of the driver. The default is 'false'. + +Besides those attributes the '' node can host '' +nodes. Such a node describes the parameters of a network and its +existence implies the intent to join the network. It has the following +attributes. + +* :ssid: sets the name of the network. It also serves as look-up key + for a network and adding multiple nodes with the same SSID are + treated as the same node whose attributes are changing. + + Note: the SSID is copied verbatim and at the moment, there is no way + to express or escape non alphanumeric characters. + +* :bssid: can be used to select a specific access point within a + network. + +* :protection: specifies the used protection mechanism of the + network. Valid values are 'WPA', 'WPA2', 'WPA3' and 'NONE'. + The last one is used in case the network uses other means of + protection and access is open. + + Note: currently only personal WPA protection using a pre-shared-key + (PSK) is supported. + +* :passphrase: sets the PSK that is required should the + network be protected. + +Of all attributes solely the 'ssid' attribute is mandatory and all +others are optional. They should be used when needed only. + +Note: If configured networks overlap in locality, the driver might + switch dynamically between these networks. + +To scan for a hidden network a '' node must by added. +It contains the following mandatory attribute. + +* :ssid: set the name of the hidden network to scan for + + Note: the SSID is copied verbatim and at the moment, there is no way + to express or escape non alphanumeric characters. + +The number of hidden networks that can be scanned for is restricted to +a practical amount, around 48 networks, and all networks after hitting +the limit are silently omitted. + +The following exemplary snippet showcases a config for two networks where +the first one should be automatically considered for joining and uses 'WPA2' +while the second one is hidden but should show up in the scan results. + +! ! -! +! ! -By default, the driver scans for available networks only when not -connected. This can be changed with the 'connected_scan_interval' -attribute, which specifies the interval for connected scans in -seconds and directly influences any roaming decision, i.e., select -a better fit accesspoint for the configured network. +To join the hidden network a corresponding '' is needed. -In addition, by specifing 'update_quality_interval', the driver will -every so often update the current signal quality of the established -connection to the accesspoint. Note that this option is only useable when -the 'connected_scan_interval' is set to '0' as both options are mutually -exclusive. - -Also, the driver can be switched to verbose logging during runtime -by setting the 'verbose' or 'verbose_state' attribute to 'true'. - -The wifi driver creates two distinct reports to communicate its state and -information about the wireless infrastructure to other components. The -first one is a list of all available accesspoints. The following examplary -report shows its general structure: +The wifi driver uses two distinct reports, 'state' and 'accesspoints', +to communicate its state of connectivity and information about the wireless +access points in the vicinity to other components. +This exemplary 'accesspoints' report shows its general structure. ! -! -! -! +! +! +! ! -Each accesspoint node has attributes that contain the SSID and the BSSID -of the accesspoint as well as the link quality (signal strength). These -attributes are mandatory. If the network is protected, the node will also -have an attribute describing the type of protection in addition. +The '' node can contain a fluctuating number of '' +nodes that describe an access point with the following attributes. -The second report provides information about the state of the connection -to the currently connected accesspoint: +* :ssid: specifies the name of the network the access point advertises. + Empty SSIDs are not reported. + +* :bssid: specifies the physical address of the access point. + +* :freq: specifies the frequency used by the access point. + +* :quality: specifies the approximated link quality (calculated from the + RSSI value). + +* :protection: specifies which kind of protection is employed by the access + point. + + Note: when a mixed protection is used by the network, like WPA2-PSK and + WPA3-PSK mixed-mode, only the strongest protection (WPA3-PSK) is + advertised. + +The 'state' report provides information about the state of the connectivity +and looks as follows. ! ! ! -Valid state values are 'connected', 'disconnected', 'connecting'. Depending -on the state, there are additional attributes that can be checked. In case -of an authentication error, e.g. the passphrase is wrong, the 'auth_failure' -attribute will be set to 'true'. The 'rfkilled' attribute is set to 'true' -if a disconnect was triggered by disabling the radio activity via setting -the 'rfkill' attribute. It can also contain the optional 'quality' attribute -to denote the current signal quality (see 'update_quality_interval'). +The '' node encompasses one '' node that has the +following additional attributes beside the ones already discussed. -By subscribing to both reports and providing the required 'wifi_config' ROM -module, a component is able control the wireless driver. +* :state: specifies the actual state of connectivity. Valid values + are 'connected', 'connecting' and 'disconnected'. -Currently only WPA/WPA2/WPA3 protection using a passphrase is supported and -the SSID is copied verbatim. At the moment, there is no way to express or -escape non alphanumeric characters. +* :auth_failure: is an optional attribute and set to 'true' in case + the PSK was wrong + +* :rfkilled: is an optional attribute and set to 'true' whenever + radio activity was temporarily disabled. + +* :not_found: is an optional attribute and is only set when a single + network was configured but could not be found. + +By subscribing to both reports and providing the required 'wifi_config' +ROM module, a component is able control the wireless driver. The driver optionally reports the following information under the label "devices" if requested in the config as depicted. @@ -170,6 +236,67 @@ label "devices" if requested in the config as depicted. ! +Best practices +~~~~~~~~~~~~~~ + +The following section describes common use-cases, like being managed +or configured explicitly by a user provided configuration, and how to +interact with the driver in each of these cases. The way Sculpt handles +the driver can serve as an example. + +Externally managed (Sculpt mode) +-------------------------------- + +When the driver is managed by an external component via its configuration +based on its 'state' and 'accesspoints' reports the configuration should +contain at most one '' node. This node contains the network the +management component has chosen to join after evaluating the 'accesspoints' +report. This makes it easier for the management component to process the +'state' reports as all reports are immediate and logically belong to one +network and there is no unexpected switch between different networks. +The 'state' report contains at least the mandatory 'state' attribute that +denotes the state of connectivity, the 'ssid' and 'bssid' as well as the +'freq' attribute. The existence of any other attributes is not certain and +depends on the state of connectivity. The signal quality may not always +be available and the external component should account for that. + +For every hidden network a '' node must be added for the +access points to appear in the 'accesspoints' report. Such a node should +not be added for non-hidden networks as it influences the scanning attempt +and could lead to longer join times. As it also proactively asks for the +network it could allow for fingerprinting a device according to its list +of hidden networks. + +Roaming within one network is performed according to the 'bgscan' settings +automatically. This implicitly also refreshes the 'accesspoints' report +that then may be considered by the management component to switch to a +different network by replacing the '' node in the configuration. +It is up to the management component to make an educated decision. For +roaming to work properly the management component should not specify +the 'bssid' attribute in the '' node. + +Removing the '' node will lead to a disconnect from the network. + +Manually managed +---------------- + +When the driver is manually or rather explicitly managed by a user provided +configuration it generally exhibits the same behavior. However, as a common +pattern, user generated configurations tend to contain multiple networks and +it is expected that the driver joins a known network if it encounters one. +Normally these networks do not overlap in locality, i.e. there is one at home, +another one at work, and still a different one at a friend's dwelling place. +Providing multiple nodes covers this use case in a fair fashion as a network +is made known to the driver by adding the corresponding '' node to +the configuration. + +Since the driver does not know in advance which network it will end up joining +providing immediate feedback is not possible and switching to a different +network may occur naturally. This behavior renders the configuration of +multiple network nodes impractical for management components and should be +avoided. + + Debugging ~~~~~~~~~ @@ -177,7 +304,7 @@ As mentioned in the introduction the 'wifi' component is special in the regard that the actual driver is provided as a shared-object to better isolate it from the the driver binary that is a Libc::Component managing the 'wpa_supplicant'. Since this code and in return the binary is the same for each -platform it is linked against an artifical 'wifi' library that only exists as +platform it is linked against an artificial 'wifi' library that only exists as an ABI stub created via 'lib/symbols/wifi'. In case the driver is integrated via depot archives this is, besides setting the proper ROM routes, of no concern. However, when the driver is built without the depot, the boot image @@ -198,7 +325,7 @@ rather then stub ABI library. This is achieved by adapting the driver's ![…] 'LIBS' must be changed as follows in case the PC wifi driver library is -used: +used. !LIBS := base pc_wifi diff --git a/repos/dde_linux/src/driver/wifi/frontend.h b/repos/dde_linux/src/driver/wifi/frontend.h deleted file mode 100644 index f003987132..0000000000 --- a/repos/dde_linux/src/driver/wifi/frontend.h +++ /dev/null @@ -1,1829 +0,0 @@ - /* - * \author Josef Soentgen - * \date 2018-07-31 - * - * This wifi driver front end uses the CTRL interface of the wpa_supplicant via - * a Genode specific backend, which merely wraps a shared memory buffer, to - * manage the supplicant. - * - * Depending on the 'wifi_config' ROM content it will instruct the supplicant - * to enable, disable and connect to wireless networks. Commands and their - * corresponding execute result are handled by the '_cmd_handler' dispatcher. - * This handler drives the front end's state-machine. Any different type of - * action can only be initiated from the 'IDLE' state. Unsolicited events, e.g. - * a scan-results-available event, may influence the current state. Config - * updates are deferred in case the current state is not 'IDLE'. - * - * brain-dump - * ========== - * - * config update overview: - * [[block any new update]] > [mark stale] > [rm stale] > [add new] > [update new] > [[unblock update]] - * - * add new network: - * [[new ap]] > [ssid] > bssid? + [bssid] > [psk] > auto? + [enable] > new ap? + [[new ap]] - * - * update network: - * [[update ap] > bssid? + [bssid] > psk? + [psk] > auto? + [enable] > update ap? + [[update ap]] - * - * remove network: - * [[mark stale]] > [remove network] > stale? + [remove network] - */ - -/* - * Copyright (C) 2018-2022 Genode Labs GmbH - * - * This file is distributed under the terms of the GNU General Public License - * version 2. - */ - -#ifndef _WIFI_FRONTEND_H_ -#define _WIFI_FRONTEND_H_ - -/* Genode includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* rep includes */ -#include -#include - -/* local includes */ -#include - -/* declare manually as it is a internal hack^Winterface */ -extern void wifi_kick_socketcall(); - - -namespace Wifi { - struct Frontend; -} - - -/* keep ordered! */ -static struct Recv_msg_table { - char const *string; - size_t len; -} recv_table[] = { - { "OK", 2 }, - { "FAIL", 4 }, - { "CTRL-EVENT-SCAN-RESULTS", 23 }, - { "CTRL-EVENT-CONNECTED", 20 }, - { "CTRL-EVENT-DISCONNECTED", 23 }, - { "SME: Trying to authenticate", 27 }, - { "CTRL-EVENT-NETWORK-NOT-FOUND", 28 }, -}; - -enum Rmi { - OK = 0, - FAIL, - SCAN_RESULTS, - CONNECTED, - DISCONNECTED, - SME_AUTH, - NOT_FOUND, -}; - - -static inline bool check_recv_msg(char const *msg, - Recv_msg_table const &entry) { - return Genode::strcmp(entry.string, msg, entry.len) == 0; } - - -static bool cmd_successful(char const *msg) { - return check_recv_msg(msg, recv_table[OK]); } - - -static bool cmd_fail(char const *msg) { - return check_recv_msg(msg, recv_table[FAIL]); } - - -static bool results_available(char const *msg) { - return check_recv_msg(msg, recv_table[SCAN_RESULTS]); } - - -static bool connecting_to_network(char const *msg) { - return check_recv_msg(msg, recv_table[SME_AUTH]); } - - -static bool network_not_found(char const *msg) { - return check_recv_msg(msg, recv_table[NOT_FOUND]); } - - -static bool scan_results(char const *msg) { - return Genode::strcmp("bssid", msg, 5) == 0; } - - -static bool list_network_results(char const *msg) { - return Genode::strcmp("network", msg, 7) == 0; } - - -/* - * Central network data structure - */ -struct Accesspoint : Genode::Interface -{ - using Bssid = Genode::String<17+1>; - using Freq = Genode::String< 4+1>; - using Prot = Genode::String< 7+1>; - using Ssid = Genode::String<32+1>; - using Pass = Genode::String<63+1>; - - /* - * Accesspoint information fields used by the front end - */ - Bssid bssid { }; - Freq freq { }; - Prot prot { }; - Ssid ssid { }; - Pass pass { }; - unsigned signal { 0 }; - - /* - * CTRL interface fields - * - * The 'enabled' field is set to true if ENABLE_NETWORK - * was successfully executed. The network itself might - * get disabled by wpa_supplicant itself in case it cannot - * connect to the network, which will _not_ be reflected - * here. - */ - int id { -1 }; - bool enabled { false }; - - /* - * Internal configuration fields - */ - bool auto_connect { false }; - bool update { false }; - bool stale { false }; - bool explicit_scan { false }; - - /** - * Default constructor - */ - Accesspoint() { } - - /** - * Constructor that initializes information fields - */ - Accesspoint(char const *bssid, char const *freq, - char const *prot, char const *ssid, unsigned signal) - : bssid(bssid), freq(freq), prot(prot), ssid(ssid), signal(signal) - { } - - void invalidate() { ssid = Ssid(); bssid = Bssid(); } - - bool valid() const { return ssid.length() > 1; } - bool bssid_valid() const { return bssid.length() > 1; } - bool wpa() const { return prot != "NONE"; } - bool wpa3() const { return prot == "WPA3"; } - bool stored() const { return id != -1; } -}; - - -template -static void for_each_line(char const *msg, FUNC const &func) -{ - char line_buffer[1024]; - size_t cur = 0; - - while (msg[cur] != 0) { - size_t until = Util::next_char(msg, cur, '\n'); - Genode::memcpy(line_buffer, &msg[cur], until); - line_buffer[until] = 0; - cur += until + 1; - - func(line_buffer); - } -} - - -template -static void for_each_result_line(char const *msg, FUNC const &func) -{ - char line_buffer[1024]; - size_t cur = 0; - - /* skip headline */ - size_t until = Util::next_char(msg, cur, '\n'); - cur += until + 1; - - while (msg[cur] != 0) { - until = Util::next_char(msg, cur, '\n'); - Genode::memcpy(line_buffer, &msg[cur], until); - line_buffer[until] = 0; - cur += until + 1; - - char const *s[5] = { }; - - for (size_t c = 0, i = 0; i < 5; i++) { - size_t pos = Util::next_char(line_buffer, c, '\t'); - line_buffer[c+pos] = 0; - s[i] = (char const*)&line_buffer[c]; - c += pos + 1; - } - - bool const is_wpa1 = Util::string_contains((char const*)s[3], "WPA"); - bool const is_wpa2 = Util::string_contains((char const*)s[3], "WPA2"); - bool const is_wpa3 = Util::string_contains((char const*)s[3], "SAE"); - - unsigned signal = Util::approximate_quality(s[2]); - - char const *prot = is_wpa1 ? "WPA" : "NONE"; - prot = is_wpa2 ? "WPA2" : prot; - prot = is_wpa3 ? "WPA3" : prot; - - Accesspoint ap(s[0], s[1], prot, s[4], signal); - - func(ap); - } -} - - -/* - * Wifi driver front end - */ -struct Wifi::Frontend : Wifi::Rfkill_notification_handler -{ - Frontend(const Frontend&) = delete; - Frontend& operator=(const Frontend&) = delete; - - /* accesspoint */ - - Genode::Heap _ap_allocator; - - using Accesspoint_r = Genode::Registered; - - Genode::Registry _aps { }; - - Accesspoint *_lookup_ap_by_ssid(Accesspoint::Ssid const &ssid) - { - Accesspoint *p = nullptr; - _aps.for_each([&] (Accesspoint &ap) { - if (ap.valid() && ap.ssid == ssid) { p = ≈ } - }); - return p; - } - - Accesspoint *_lookup_ap_by_bssid(Accesspoint::Bssid const &bssid) - { - Accesspoint *p = nullptr; - _aps.for_each([&] (Accesspoint &ap) { - if (ap.valid() && ap.bssid == bssid) { p = ≈ } - }); - return p; - } - - Accesspoint *_alloc_ap() - { - return new (&_ap_allocator) Accesspoint_r(_aps); - } - - void _free_ap(Accesspoint &ap) - { - Genode::destroy(&_ap_allocator, &ap); - } - - template - void _for_each_ap(FUNC const &func) - { - _aps.for_each([&] (Accesspoint &ap) { - func(ap); - }); - } - - unsigned _count_to_be_enabled() - { - unsigned count = 0; - auto enable = [&](Accesspoint const &ap) { - count += ap.auto_connect; - }; - _for_each_ap(enable); - return count; - } - - unsigned _count_enabled() - { - unsigned count = 0; - auto enabled = [&](Accesspoint const &ap) { - count += ap.enabled; - }; - _for_each_ap(enabled); - return count; - } - - unsigned _count_stored() - { - unsigned count = 0; - auto enabled = [&](Accesspoint const &ap) { - count += ap.stored(); - }; - _for_each_ap(enabled); - return count; - } - - /* remaining stuff */ - - Msg_buffer &_msg; - - Genode::Blockade _notify_blockade { }; - - void _notify_lock_lock() { _notify_blockade.block(); } - void _notify_lock_unlock() { _notify_blockade.wakeup(); } - - bool _rfkilled { false }; - - Genode::Signal_handler _rfkill_handler; - - void _handle_rfkill() - { - _rfkilled = Wifi::rfkill_blocked(); - - /* re-enable scan timer */ - if (!_rfkilled) { - _timer.sigh(_timer_sigh); - _try_arming_any_timer(); - } else { - _timer.sigh(Genode::Signal_context_capability()); - } - - if (_rfkilled && _state != State::IDLE) { - Genode::warning("rfkilled in state ", state_strings(_state)); - } - } - - /* config */ - - Genode::Attached_rom_dataspace _config_rom; - Genode::Signal_handler _config_sigh; - - bool _verbose { false }; - bool _verbose_state { false }; - - bool _deferred_config_update { false }; - bool _single_autoconnect { false }; - - Genode::uint64_t _connected_scan_interval { 30 }; - Genode::uint64_t _scan_interval { 5 }; - Genode::uint64_t _update_quality_interval { 0 }; - - void _config_update(bool signal) - { - _config_rom.update(); - - if (!_config_rom.valid()) { return; } - - Genode::Xml_node config = _config_rom.xml(); - - _verbose = config.attribute_value("verbose", _verbose); - _verbose_state = config.attribute_value("verbose_state", _verbose_state); - - Genode::uint64_t const connected_scan_interval = - Util::check_time(config.attribute_value("connected_scan_interval", - _connected_scan_interval), - 0, 15*60); - - Genode::uint64_t const scan_interval = - Util::check_time(config.attribute_value("scan_interval", - _scan_interval), - 5, 15*60); - - Genode::uint64_t const update_quality_interval = - Util::check_time(config.attribute_value("update_quality_interval", - _update_quality_interval), - 0, 15*60); - - bool const new_connected_scan_interval = - connected_scan_interval != _connected_scan_interval; - - bool const new_scan_interval = - connected_scan_interval != _scan_interval; - - bool const new_update_quality_interval = - update_quality_interval != _update_quality_interval; - - _connected_scan_interval = connected_scan_interval; - _scan_interval = scan_interval; - _update_quality_interval = update_quality_interval; - - /* - * Arm again if intervals changed, implicitly discards - * an already scheduled timer. - * - * First try to arm scanning and if that fails try arming - * signal-strength polling. - */ - if ( new_connected_scan_interval - || new_scan_interval - || new_update_quality_interval) - _try_arming_any_timer(); - - /* - * Always handle rfkill, regardless in which state we are currently in. - * When we come back from rfkill, will most certainly will be IDLE anyway. - */ - if (config.has_attribute("rfkill")) { - bool const blocked = config.attribute_value("rfkill", false); - Wifi::set_rfkill(blocked); - - /* - * In case we get blocked set rfkilled immediately to prevent - * any further scanning operation. The actual value will be set - * by the singal handler but is not expected to be any different - * as the rfkill call is not supposed to fail. - */ - if (blocked && !_rfkilled) { - _rfkilled = true; - - Genode::Reporter::Xml_generator xml(*_state_reporter, [&] () { - xml.node("accesspoint", [&] () { - xml.attribute("state", "disconnected"); - xml.attribute("rfkilled", _rfkilled); - }); - }); - - _connected_ap.invalidate(); - } - } - - /* - * Block any further config updates until we have finished applying - * the current one. - */ - if (_state != State::IDLE) { - Genode::warning("deferring config update (", state_strings(_state), ")"); - _deferred_config_update = true; - return; - } - - bool single_autoconnect = false; - - /* update AP list */ - auto parse = [&] ( Genode::Xml_node node) { - - Accesspoint ap; - ap.ssid = node.attribute_value("ssid", Accesspoint::Ssid()); - ap.bssid = node.attribute_value("bssid", Accesspoint::Bssid()); - - size_t const ssid_len = ap.ssid.length() - 1; - if (ssid_len == 0 || ssid_len > 32) { - Genode::warning("ignoring accesspoint with invalid ssid"); - return; - } - - Accesspoint *p = _lookup_ap_by_ssid(ap.ssid); - if (p) { - if (_verbose) { Genode::log("Update: '", p->ssid, "'"); } - /* mark for updating */ - p->update = true; - } else { - p = _alloc_ap(); - if (!p) { - Genode::warning("could not add accesspoint, no slots left"); - return; - } - } - - ap.pass = node.attribute_value("passphrase", Accesspoint::Pass("")); - ap.prot = node.attribute_value("protection", Accesspoint::Prot("NONE")); - ap.auto_connect = node.attribute_value("auto_connect", true); - ap.explicit_scan = node.attribute_value("explicit_scan", false); - - if (ap.wpa()) { - size_t const psk_len = ap.pass.length() - 1; - if (psk_len < 8 || psk_len > 63) { - Genode::warning("ignoring accesspoint '", ap.ssid, - "' with invalid pass"); - return; - } - } - - - /* check if updating is really necessary */ - if (p->update) { - p->update = ((ap.bssid.length() > 1 && ap.bssid != p->bssid) - || ap.pass != p->pass - || ap.prot != p->prot - || ap.auto_connect != p->auto_connect); - } - - /* TODO add better way to check validity */ - if (ap.bssid.length() == 17 + 1) { p->bssid = ap.bssid; } - - p->ssid = ap.ssid; - p->prot = ap.prot; - p->pass = ap.pass; - p->auto_connect = ap.auto_connect; - p->explicit_scan = ap.explicit_scan; - - single_autoconnect |= (p->update || p->auto_connect) && !_connected_ap.valid(); - }; - config.for_each_sub_node("network", parse); - - /* - * To accomodate a management component that only deals - * with on network, e.g. the sculpt_manager, generate a - * fake connecting event. Either a connected or disconnected - * event will bring us to square one. - */ - if (signal && _count_to_be_enabled() == 1 && single_autoconnect && !_rfkilled) { - - auto lookup = [&] (Accesspoint const &ap) { - if (!ap.auto_connect) { return; } - - if (_verbose) { Genode::log("Single autoconnect event for '", ap.ssid, "'"); } - - try { - Genode::Reporter::Xml_generator xml(*_state_reporter, [&] () { - xml.node("accesspoint", [&] () { - xml.attribute("ssid", ap.ssid); - xml.attribute("state", "connecting"); - }); - }); - - _single_autoconnect = true; - - } catch (...) { } - }; - _for_each_ap(lookup); - } - - /* - * Marking removes stale APs first and triggers adding of - * new ones afterwards. - */ - _mark_stale_aps(config); - } - - void _handle_config_update() { _config_update(true); } - - /* state */ - - Accesspoint *_processed_ap { nullptr }; - Accesspoint _connected_ap { }; - - enum State { - IDLE = 0x00, - SCAN = 0x01, - NETWORK = 0x02, - CONNECT = 0x03, - STATUS = 0x04, - INFO = 0x05, - SIGNAL = 0x06, - - INITIATE_SCAN = 0x00|SCAN, - PENDING_RESULTS = 0x10|SCAN, - - ADD_NETWORK = 0x00|NETWORK, - FILL_NETWORK_SSID = 0x10|NETWORK, - FILL_NETWORK_BSSID = 0x20|NETWORK, - FILL_NETWORK_KEY_MGMT = 0x30|NETWORK, - FILL_NETWORK_PSK = 0x40|NETWORK, - REMOVE_NETWORK = 0x50|NETWORK, - ENABLE_NETWORK = 0x60|NETWORK, - DISABLE_NETWORK = 0x70|NETWORK, - LIST_NETWORKS = 0x90|NETWORK, - SET_NETWORK_PMF = 0xA0|NETWORK, - - CONNECTING = 0x00|CONNECT, - CONNECTED = 0x10|CONNECT, - DISCONNECTED = 0x20|CONNECT, - }; - - State _state { State::IDLE }; - - char const *state_strings(State state) - { - switch (state) { - case IDLE: return "idle"; - case INITIATE_SCAN: return "initiate scan"; - case PENDING_RESULTS: return "pending results"; - case ADD_NETWORK: return "add network"; - case FILL_NETWORK_SSID: return "fill network ssid"; - case FILL_NETWORK_BSSID: return "fill network bssid"; - case FILL_NETWORK_KEY_MGMT: return "fill network key_mgmt"; - case FILL_NETWORK_PSK: return "fill network pass"; - case REMOVE_NETWORK: return "remove network"; - case ENABLE_NETWORK: return "enable network"; - case DISABLE_NETWORK: return "disable network"; - case CONNECTING: return "connecting"; - case CONNECTED: return "connected"; - case DISCONNECTED: return "disconnected"; - case STATUS: return "status"; - case LIST_NETWORKS: return "list networks"; - case INFO: return "info"; - case SET_NETWORK_PMF: return "set network pmf"; - case SIGNAL: return "signal poll"; - default: return "unknown"; - }; - } - - void _state_transition(State ¤t, State next) - { - if (_verbose_state) { - using namespace Genode; - log("Transition: ", state_strings(current), " -> ", - state_strings(next)); - } - - current = next; - } - - using Cmd_str = Genode::String; - - void _submit_cmd(Cmd_str const &str) - { - Genode::memset(_msg.send, 0, sizeof(_msg.send)); - Genode::memcpy(_msg.send, str.string(), str.length()); - ++_msg.send_id; - - wpa_ctrl_set_fd(); - - /* - * We might have to pull the socketcall task out of poll_all() - * because otherwise we might be late and wpa_supplicant has - * already removed all scan results due to BSS age settings. - */ - wifi_kick_socketcall(); - } - - /* scan */ - - enum class Timer_type : uint8_t { CONNECTED_SCAN, SCAN, SIGNAL_POLL }; - - Genode::uint64_t _seconds_from_type(Timer_type const type) - { - switch (type) { - case Timer_type::CONNECTED_SCAN: return _connected_scan_interval; - case Timer_type::SCAN: return _scan_interval; - case Timer_type::SIGNAL_POLL: return _update_quality_interval; - } - /* never reached */ - return 0; - } - - static char const *_name_from_type(Timer_type const type) - { - switch (type) { - case Timer_type::CONNECTED_SCAN: return "connected-scan"; - case Timer_type::SCAN: return "scan"; - case Timer_type::SIGNAL_POLL: return "signal-poll"; - } - /* never reached */ - return nullptr; - } - - Timer::Connection _timer; - Genode::Signal_handler _timer_sigh; - - bool _arm_timer(Timer_type const type) - { - Genode::uint64_t const sec = _seconds_from_type(type); - if (!sec) { return false; } - - if (_verbose) - Genode::log("Arm timer for ", _name_from_type(type)); - - _timer.trigger_once(sec * (1000 * 1000)); - return true; - } - - void _request_scan() - { - /* skip as we will be scheduled some time soon(tm) anyway */ - if (_state != State::IDLE) { - if (_verbose) { - Genode::log("Not idle, ignore scan request, state: ", - Genode::Hex((unsigned)_state)); - } - return; - } - - /* left one attempt out */ - if (_scan_busy) { - if (_verbose) { Genode::log("Scan already pending, ignore scan request"); } - _scan_busy = false; - return; - } - - enum { SSID_ARG_LEN = 6 + 64, /* " ssid " + "a5a5a5a5..." */ }; - /* send buffer - 'SCAN ' + stuff */ - char ssid_buffer[sizeof(Msg_buffer::send)-16] = { }; - size_t buffer_pos = 0; - - auto valid_ssid = [&] (Accesspoint const &ap) { - - if (buffer_pos + SSID_ARG_LEN >= sizeof(ssid_buffer)) { - return; - } - - if (!ap.explicit_scan) { return; } - - char ssid_hex[64+1] = { }; - char const *ssid = ap.ssid.string(); - - for (size_t i = 0; i < ap.ssid.length() - 1; i++) { - Util::byte2hex((ssid_hex + i * 2), ssid[i]); - } - - Genode::String tmp(" ssid ", (char const*)ssid_hex); - size_t const tmp_len = tmp.length() - 1; - - Genode::memcpy((ssid_buffer + buffer_pos), tmp.string(), tmp_len); - buffer_pos += tmp_len; - }; - _for_each_ap(valid_ssid); - - _state_transition(_state, State::INITIATE_SCAN); - _submit_cmd(Cmd_str("SCAN", (char const*)ssid_buffer)); - } - - void _poll_signal_strength() - { - if (_state != State::IDLE) { - if (_verbose) - Genode::log("Not idle, ignore signal-poll request, state: ", - Genode::Hex((unsigned)_state)); - return; - } - - _state_transition(_state, State::SIGNAL); - _submit_cmd(Cmd_str("SIGNAL_POLL")); - } - - void _handle_timer() - { - /* - * If we are blocked or currently trying to join a network - * suspend scanning. - */ - if (_rfkilled || _connecting.length() > 1) { - if (_verbose) - Genode::log("Timer: suspend due to RFKILL or connection" - " attempt"); - return; - } - - /* - * First check if (connected-)scanning is enabled, re-arm - * the timer again and try to submit the request. In case we - * are not able to submit it the timer will trigger another - * attempt later on. - */ - if (_arm_scan_timer()) { - _request_scan(); - return; - } else - if (_verbose) - Genode::log("Timer: scanning disabled"); - - /* - * We arm the poll timer only when we are not scanning. - * So connected-scan MUST be disabled for the signal-strength - * polling to be active. - */ - if (_arm_poll_timer()) { - _poll_signal_strength(); - return; - } else - if (_verbose) - Genode::log("Timer: signal-strength polling disabled"); - } - - bool _arm_scan_timer() - { - Timer_type const type = _connected_ap.bssid_valid() - ? Timer_type::CONNECTED_SCAN - : Timer_type::SCAN; - return _arm_timer(type); - } - - bool _arm_poll_timer() - { - if (!_connected_ap.bssid_valid()) - return false; - - return _arm_timer(Timer_type::SIGNAL_POLL); - } - - void _try_arming_any_timer() - { - if (!_arm_scan_timer()) - (void)_arm_poll_timer(); - } - - Genode::Constructible _ap_reporter { }; - - void _generate_scan_results_report(char const *msg) - { - unsigned count_lines = 0; - for_each_line(msg, [&] (char const*) { count_lines++; }); - - if (!count_lines) { - if (_verbose) { Genode::log("Scan results empty"); } - return; - } - - bool connecting_attempt = false; - try { - - _ap_reporter->generate([&] (Genode::Xml_generator &xml) { - - for_each_result_line(msg, [&] (Accesspoint const &ap) { - - /* ignore potentially empty ssids */ - if (ap.ssid == "") { return; } - - xml.node("accesspoint", [&]() { - xml.attribute("ssid", ap.ssid); - xml.attribute("bssid", ap.bssid); - xml.attribute("freq", ap.freq); - xml.attribute("quality", ap.signal); - if (ap.wpa()) { xml.attribute("protection", ap.prot); } - }); - - auto check_existence = [&] (Accesspoint &lap) { - connecting_attempt |= (lap.ssid == ap.ssid) && ap.auto_connect; - }; - _for_each_ap(check_existence); - }); - }); - - } catch (...) { /* silently omit report */ } - - try { - if (!_connected_ap.bssid_valid() && connecting_attempt) { - - Genode::Reporter::Xml_generator xml(*_state_reporter, [&] () { - xml.node("accesspoint", [&] () { - xml.attribute("state", "connecting"); - }); - }); - } - } catch (...) { /* silently omit state */ } - } - - /* network commands */ - - void _mark_stale_aps(Genode::Xml_node const &config) - { - auto mark_stale = [&] (Accesspoint &ap) { - ap.stale = true; - - config.for_each_sub_node("network", [&] ( Genode::Xml_node node) { - Accesspoint::Ssid ssid = node.attribute_value("ssid", Accesspoint::Ssid("")); - - if (ap.ssid == ssid) { ap.stale = false; } - }); - }; - _for_each_ap(mark_stale); - - _remove_stale_aps(); - } - - void _remove_stale_aps() - { - if (_state != State::IDLE) { - Genode::warning("cannot remove stale APs in non-idle state " - "(", state_strings(_state), ")"); - return; - } - - if (_processed_ap) { return; } - - _aps.for_each([&] (Accesspoint &ap) { - if (!_processed_ap && ap.valid() && ap.stale) { - _processed_ap = ≈ - } - }); - - if (!_processed_ap) { - /* TODO move State transition somewhere more sane */ - _state_transition(_state, State::IDLE); - _add_new_aps(); - return; - } - - if (_verbose) { - Genode::log("Remove network: '", _processed_ap->ssid, "'"); - } - - _state_transition(_state, State::REMOVE_NETWORK); - _submit_cmd(Cmd_str("REMOVE_NETWORK ", _processed_ap->id)); - } - - void _update_aps() - { - if (_state != State::IDLE) { - Genode::warning("cannot enable network in non-idle state"); - return; - } - - if (_processed_ap) { return; } - - _aps.for_each([&] (Accesspoint &ap) { - if (!_processed_ap && ap.stored() && ap.update) { - _processed_ap = ≈ - } - }); - - if (!_processed_ap) { return; } - - if (_verbose) { - Genode::log("Update network: '", _processed_ap->ssid, "'"); - } - - /* re-use state to change PSK */ - _state_transition(_state, State::FILL_NETWORK_PSK); - _network_set_psk(); - } - - - void _add_new_aps() - { - if (_state != State::IDLE) { - Genode::warning("cannot enable network in non-idle state"); - return; - } - - if (_processed_ap) { return; } - - _aps.for_each([&] (Accesspoint &ap) { - if (!_processed_ap && ap.valid() && !ap.stored()) { - _processed_ap = ≈ - } - }); - - if (!_processed_ap) { - /* XXX move State transition somewhere more sane */ - _state_transition(_state, State::IDLE); - _update_aps(); - return; - } - - if (_verbose) { - Genode::log("Add network: '", _processed_ap->ssid, "'"); - } - - _state_transition(_state, State::ADD_NETWORK); - _submit_cmd(Cmd_str("ADD_NETWORK")); - } - - void _network_enable(Accesspoint &ap) - { - if (_state != State::IDLE) { - Genode::warning("cannot enable network in non-idle state"); - return; - } - - if (ap.enabled) { return; } - - if (_verbose) { - Genode::log("Enable network: ", ap.id, " '", ap.ssid, "'"); - } - - ap.enabled = true; - - _state_transition(_state, State::ENABLE_NETWORK); - _submit_cmd(Cmd_str("ENABLE_NETWORK ", ap.id)); - } - - void _network_disable(Accesspoint &ap) - { - if (_state != State::IDLE) { - Genode::warning("cannot enable network in non-idle state"); - return; - } - - if (!ap.enabled) { return; } - - if (_verbose) { - Genode::log("Disable network: ", ap.id, " '", ap.ssid, "'"); - } - - ap.enabled = false; - - _state_transition(_state, State::DISABLE_NETWORK); - _submit_cmd(Cmd_str("DISABLE_NETWORK ", ap.id)); - } - - void _network_set_ssid(char const *msg) - { - long id = -1; - Genode::ascii_to(msg, id); - - _processed_ap->id = static_cast(id); - _submit_cmd(Cmd_str("SET_NETWORK ", _processed_ap->id, - " ssid \"", _processed_ap->ssid, "\"")); - } - - void _network_set_bssid() - { - bool const valid = _processed_ap->bssid.length() == 17 + 1; - char const *bssid = valid ? _processed_ap->bssid.string() : ""; - - _submit_cmd(Cmd_str("SET_NETWORK ", _processed_ap->id, - " bssid ", bssid)); - } - - void _network_set_key_mgmt_sae() - { - _submit_cmd(Cmd_str("SET_NETWORK ", _processed_ap->id, - " key_mgmt SAE")); - } - - void _network_set_pmf() - { - _submit_cmd(Cmd_str("SET_NETWORK ", _processed_ap->id, - " ieee80211w 2")); - } - - void _network_set_psk() - { - if (_processed_ap->wpa()) { - _submit_cmd(Cmd_str("SET_NETWORK ", _processed_ap->id, - " psk \"", _processed_ap->pass, "\"")); - } else { - _submit_cmd(Cmd_str("SET_NETWORK ", _processed_ap->id, - " key_mgmt NONE")); - } - } - - /* result handling */ - - bool _scan_busy { false }; - - void _handle_scan_results(State state, char const *msg) - { - switch (state) { - case State::INITIATE_SCAN: - if (!cmd_successful(msg)) { - _scan_busy = Genode::strcmp(msg, "FAIL-BUSY"); - if (!_scan_busy) { - Genode::warning("could not initiate scan: ", msg); - } - } - _state_transition(_state, State::IDLE); - break; - case State::PENDING_RESULTS: - if (scan_results(msg)) { - _state_transition(_state, State::IDLE); - _generate_scan_results_report(msg); - } - break; - default: - Genode::warning("unknown SCAN state: ", msg); - break; - } - } - - void _handle_network_results(State state, char const *msg) - { - bool successfully = false; - - switch (state) { - case State::ADD_NETWORK: - if (cmd_fail(msg)) { - Genode::error("could not add network: ", msg); - _state_transition(_state, State::IDLE); - } else { - _state_transition(_state, State::FILL_NETWORK_SSID); - _network_set_ssid(msg); - - successfully = true; - } - break; - case State::REMOVE_NETWORK: - { - _state_transition(_state, State::IDLE); - - Accesspoint &ap = *_processed_ap; - /* reset processed AP as this is an end state */ - _processed_ap = nullptr; - - if (cmd_fail(msg)) { - Genode::error("could not remove network: ", msg); - } else { - _free_ap(ap); - - /* trigger the next round */ - _remove_stale_aps(); - - successfully = true; - } - break; - } - case State::FILL_NETWORK_SSID: - _state_transition(_state, State::IDLE); - - if (!cmd_successful(msg)) { - Genode::error("could not set ssid for network: ", msg); - _state_transition(_state, State::IDLE); - } else { - _state_transition(_state, State::FILL_NETWORK_BSSID); - _network_set_bssid(); - - successfully = true; - } - break; - case State::FILL_NETWORK_BSSID: - _state_transition(_state, State::IDLE); - - if (!cmd_successful(msg)) { - Genode::error("could not set bssid for network: ", msg); - _state_transition(_state, State::IDLE); - } else { - - /* - * For the moment branch here to handle WPA3-personal-only - * explicitly. - */ - if (_processed_ap->wpa3()) { - _state_transition(_state, State::FILL_NETWORK_KEY_MGMT); - _network_set_key_mgmt_sae(); - } else { - _state_transition(_state, State::FILL_NETWORK_PSK); - _network_set_psk(); - } - - successfully = true; - } - break; - case State::FILL_NETWORK_KEY_MGMT: - _state_transition(_state, State::IDLE); - - if (!cmd_successful(msg)) { - Genode::error("could not set key_mgmt for network: ", msg); - _state_transition(_state, State::IDLE); - } else { - _state_transition(_state, State::SET_NETWORK_PMF); - _network_set_pmf(); - - successfully = true; - } - break; - case State::SET_NETWORK_PMF: - _state_transition(_state, State::IDLE); - - if (!cmd_successful(msg)) { - Genode::error("could not set PMF for network: ", msg); - _state_transition(_state, State::IDLE); - } else { - _state_transition(_state, State::FILL_NETWORK_PSK); - _network_set_psk(); - - successfully = true; - } - break; - case State::FILL_NETWORK_PSK: - { - _state_transition(_state, State::IDLE); - - Accesspoint &ap = *_processed_ap; - - if (!cmd_successful(msg)) { - Genode::error("could not set passphrase for network: ", msg); - } else { - - /* - * Disable network to trick wpa_supplicant into reloading - * the settings. - */ - if (ap.update) { - ap.enabled = true; - _network_disable(ap); - } else - - if (ap.auto_connect) { - _network_enable(ap); - } else { - /* trigger the next round */ - _add_new_aps(); - } - - successfully = true; - } - break; - } - case State::ENABLE_NETWORK: - { - _state_transition(_state, State::IDLE); - - /* reset processed AP as this is an end state */ - _processed_ap = nullptr; - - if (!cmd_successful(msg)) { - Genode::error("could not enable network: ", msg); - } else { - /* trigger the next round */ - _add_new_aps(); - - successfully = true; - } - break; - } - case State::DISABLE_NETWORK: - { - _state_transition(_state, State::IDLE); - - Accesspoint &ap = *_processed_ap; - /* reset processed AP as this is an end state */ - _processed_ap = nullptr; - - if (!cmd_successful(msg)) { - Genode::error("could not disable network: ", msg); - } else { - - /* - * Updated settings are applied, enable the network - * anew an try again. - */ - if (ap.update) { - ap.update = false; - - if (ap.auto_connect) { - _network_enable(ap); - } - } - - successfully = true; - } - break; - } - case State::LIST_NETWORKS: - _state_transition(_state, State::IDLE); - - if (list_network_results(msg)) { - Genode::error("List networks:\n", msg); - } - break; - default: - Genode::warning("unknown network state: ", msg); - break; - } - - /* - * If some step failed we have to generate a fake - * disconnect event. - */ - if (_single_autoconnect && !successfully) { - try { - Genode::Reporter::Xml_generator xml(*_state_reporter, [&] () { - xml.node("accesspoint", [&] () { - xml.attribute("state", "disconnected"); - xml.attribute("rfkilled", _rfkilled); - xml.attribute("config_error", true); - }); - }); - - _single_autoconnect = false; - } catch (...) { } - } - } - - void _handle_status_result(State &state, char const *msg) - { - _state_transition(state, State::IDLE); - - /* - * Querying the status might have failed but we already sent - * out a rudimentary report, just stop here. - */ - if (0 == msg[0]) { return; } - - Accesspoint ap { }; - - auto fill_ap = [&] (char const *line) { - if (Genode::strcmp(line, "ssid=", 5) == 0) { - ap.ssid = Accesspoint::Ssid(line+5); - } else - - if (Genode::strcmp(line, "bssid=", 6) == 0) { - ap.bssid = Accesspoint::Bssid(line+6); - } else - - if (Genode::strcmp(line, "freq=", 5) == 0) { - ap.freq = Accesspoint::Freq(line+5); - } - }; - for_each_line(msg, fill_ap); - - if (!ap.ssid.valid()) { - Genode::error("Cannot query SSID :-("); - return; - } - - Accesspoint *p = _lookup_ap_by_ssid(ap.ssid); - if (p) { - p->bssid = ap.bssid; - p->freq = ap.freq; - } - - _connected_ap.ssid = ap.ssid; - - Genode::Reporter::Xml_generator xml(*_state_reporter, [&] () { - xml.node("accesspoint", [&] () { - xml.attribute("ssid", ap.ssid); - xml.attribute("bssid", ap.bssid); - xml.attribute("freq", ap.freq); - xml.attribute("state", "connected"); - - /* - * Only add the attribute when we have something - * to report so that a consumer of the state report - * may take appropriate actions. - */ - if (_connected_ap.signal) - xml.attribute("quality", _connected_ap.signal); - }); - }); - } - - void _handle_info_result(State &state, char const *msg) - { - _state_transition(state, State::IDLE); - - if (!_connected_event && !_disconnected_event) { return; } - - /* - * It might happen that the supplicant already flushed - * its internal BSS information and cannot help us out. - * Since we already sent out a rudimentary report, just - * stop here. - */ - if (0 == msg[0]) { return; } - - Accesspoint ap { }; - - auto fill_ap = [&] (char const *line) { - if (Genode::strcmp(line, "ssid=", 5) == 0) { - ap.ssid = Accesspoint::Ssid(line+5); - } else - - if (Genode::strcmp(line, "bssid=", 6) == 0) { - ap.bssid = Accesspoint::Bssid(line+6); - } else - - if (Genode::strcmp(line, "freq=", 5) == 0) { - ap.freq = Accesspoint::Freq(line+5); - } - }; - for_each_line(msg, fill_ap); - - /* - * When the config is changed while we are still connecting and - * for some reasons the accesspoint does not get disabled - * a connected event could arrive and we will get a nullptr... - */ - Accesspoint *p = _lookup_ap_by_ssid(ap.ssid); - - /* - * ... but we still generate a report and let the management - * component deal with it. - */ - Genode::Reporter::Xml_generator xml(*_state_reporter, [&] () { - xml.node("accesspoint", [&] () { - xml.attribute("ssid", ap.ssid); - xml.attribute("bssid", ap.bssid); - xml.attribute("freq", ap.freq); - xml.attribute("state", _connected_event ? "connected" - : "disconnected"); - if (!_connected_event) { - xml.attribute("rfkilled", _rfkilled); - xml.attribute("auth_failure", _disconnected_fail); - } - }); - }); - - if (_disconnected_fail) { - /* - * Being able to remove a failed network from the internal - * state of the supplicant relies on a sucessful BSS request. - * In case that failes the supplicant will try to join the - * network again and again... - */ - if (!p || _processed_ap) { - Genode::error("cannot disabled failed network"); - } else { - _processed_ap = p; - _network_disable(*_processed_ap); - } - } else - - if (_connected_event) { - /* - * In case the BSS cmd did not return a valid SSID, which - * was observed only with hidden networks so far, check the - * current status. - */ - if (!p) { - _state_transition(state, State::STATUS); - _submit_cmd(Cmd_str("STATUS")); - - } else { - p->bssid = ap.bssid; - p->freq = ap.freq; - } - - _connected_ap = ap; - } - } - - void _handle_signal_poll_result(State &state, char const *msg) - { - _state_transition(state, State::IDLE); - - using Rssi = Genode::String<5>; - Rssi rssi { }; - auto get_rssi = [&] (char const *line) { - if (Genode::strcmp(line, "RSSI=", 5) != 0) - return; - - rssi = Rssi(line + 5); - }; - for_each_line(msg, get_rssi); - - /* - * Use the same simplified approximation for denoting - * the quality to be in line with the scan results. - */ - _connected_ap.signal = - Util::approximate_quality(rssi.valid() ? rssi.string() - : "-100"); - - /* - * Query the status to incorporate the newly acquired - * quality into a new state report. - */ - _state_transition(state, State::STATUS); - _submit_cmd(Cmd_str("STATUS")); - } - - /* connection state */ - - Genode::Constructible _state_reporter { }; - - Accesspoint::Bssid _connecting { }; - - Accesspoint::Bssid const _extract_bssid(char const *msg, State state) - { - char bssid[32] = { }; - /* by the power of wc -c, I have the start pos... */ - enum { BSSID_CONNECT = 37, BSSID_DISCONNECT = 30, BSSID_CONNECTING = 33, }; - - bool const connected = state == State::CONNECTED; - bool const connecting = state == State::CONNECTING; - - size_t const len = 17; - size_t const start = connected ? BSSID_CONNECT - : connecting ? BSSID_CONNECTING - : BSSID_DISCONNECT; - Genode::memcpy(bssid, msg + start, len); - return Accesspoint::Bssid((char const*)bssid); - } - - bool _auth_failure(char const *msg) - { - enum { REASON_OFFSET = 55, }; - unsigned reason = 0; - Genode::ascii_to((msg + REASON_OFFSET), reason); - switch (reason) { - case 2: /* prev auth no longer valid */ - case 15: /* 4-way handshake timeout/failed */ - return true; - default: - return false; - } - } - - /* events */ - - bool _connected_event { false }; - bool _disconnected_event { false }; - bool _disconnected_fail { false }; - bool _was_connected { false }; - - enum { MAX_REAUTH_ATTEMPTS = 1 }; - unsigned _reauth_attempts { 0 }; - - enum { MAX_ATTEMPTS = 3, }; - unsigned _scan_attempts { 0 }; - - Accesspoint::Bssid _pending_bssid { }; - - void _handle_connection_events(char const *msg) - { - _connected_event = false; - _disconnected_event = false; - _disconnected_fail = false; - - bool const connected = check_recv_msg(msg, recv_table[Rmi::CONNECTED]); - bool const disconnected = check_recv_msg(msg, recv_table[Rmi::DISCONNECTED]); - bool const auth_failed = disconnected && _auth_failure(msg); - - State state = connected ? State::CONNECTED : State::DISCONNECTED; - Accesspoint::Bssid const &bssid = _extract_bssid(msg, state); - - /* simplistic heuristic to ignore re-authentication requests */ - if (_connected_ap.bssid.valid() && auth_failed) { - if (_reauth_attempts < MAX_ATTEMPTS) { - Genode::log("ignore deauth from: ", _connected_ap.bssid); - _reauth_attempts++; - return; - } - } - _reauth_attempts = 0; - - /* - * Always reset the "global" connection state first - */ - _connected_ap.invalidate(); - if (connected) { _connected_ap.bssid = bssid; } - if (connected || disconnected) { _connecting = Accesspoint::Bssid(); } - - /* - * Save local connection state here for later re-use when - * the BSS information are handled. - */ - _connected_event = connected; - _disconnected_event = disconnected; - _disconnected_fail = auth_failed; - - if (!_rfkilled) { - - /* - * As we only received the BSSID, try to gather more information - * so we may generate a more thorough follow-up state report. - */ - if (_state != State::IDLE) { - _pending_bssid = bssid; - } else { - _state_transition(_state, State::INFO); - _submit_cmd(Cmd_str("BSS ", bssid)); - } - - _try_arming_any_timer(); - } - - /* - * Generate the first rudimentary report whose missing information - * are (potentially) filled in later (see above). - */ - Genode::Reporter::Xml_generator xml(*_state_reporter, [&] () { - xml.node("accesspoint", [&] () { - xml.attribute("bssid", bssid); - xml.attribute("state", connected ? "connected" - : "disconnected"); - if (disconnected) { - xml.attribute("rfkilled", _rfkilled); - if (auth_failed) { - xml.attribute("auth_failure", auth_failed); - } - } - }); - }); - - /* reset */ - _single_autoconnect = false; - } - - Genode::Signal_handler _events_handler; - - unsigned _last_event_id { 0 }; - - void _handle_events() - { - char const *msg = reinterpret_cast(_msg.event); - unsigned const event_id = _msg.event_id; - - /* return early */ - if (_last_event_id == event_id) { - _notify_lock_unlock(); - return; - } - - if (results_available(msg)) { - - /* - * We might have to pull the socketcall task out of poll_all() - * because otherwise we might be late and wpa_supplicant has - * already removed all scan results due to BSS age settings. - */ - wifi_kick_socketcall(); - - if (_state == State::IDLE) { - _state_transition(_state, State::PENDING_RESULTS); - _submit_cmd(Cmd_str("SCAN_RESULTS")); - } - } else - - if (connecting_to_network(msg)) { - if (!_single_autoconnect) { - Accesspoint::Bssid const &bssid = _extract_bssid(msg, State::CONNECTING); - _connecting = bssid; - - Genode::Reporter::Xml_generator xml(*_state_reporter, [&] () { - xml.node("accesspoint", [&] () { - xml.attribute("bssid", bssid); - xml.attribute("state", "connecting"); - }); - }); - } - } else - - if (network_not_found(msg)) { - - /* always try to update the accesspoint list */ - if (_state == State::IDLE) { - _state_transition(_state, State::PENDING_RESULTS); - _submit_cmd(Cmd_str("SCAN_RESULTS")); - } - - if (_single_autoconnect && ++_scan_attempts >= MAX_ATTEMPTS) { - _scan_attempts = 0; - _single_autoconnect = false; - - Genode::Reporter::Xml_generator xml(*_state_reporter, [&] () { - xml.node("accesspoint", [&] () { - xml.attribute("state", "disconnected"); - xml.attribute("rfkilled", _rfkilled); - xml.attribute("not_found", true); - }); - }); - } - - } else - - { - _handle_connection_events(msg); - } - - _notify_lock_unlock(); - } - - Genode::Signal_handler _cmd_handler; - - unsigned _last_recv_id { 0 }; - - void _handle_cmds() - { - char const *msg = reinterpret_cast(_msg.recv); - unsigned const recv_id = _msg.recv_id; - - - /* return early */ - if (_last_recv_id == recv_id) { - _notify_lock_unlock(); - return; - } - - _last_recv_id = recv_id; - - switch (_state & 0xf) { - case State::SCAN: - _handle_scan_results(_state, msg); - break; - case State::NETWORK: - _handle_network_results(_state, msg); - break; - case State::STATUS: - _handle_status_result(_state, msg); - break; - case State::INFO: - _handle_info_result(_state, msg); - break; - case State::SIGNAL: - _handle_signal_poll_result(_state, msg); - break; - case State::IDLE: - default: - break; - } - _notify_lock_unlock(); - - if (_verbose_state) { - Genode::log("State:", - " connected: ", _connected_ap.bssid_valid(), - " connecting: ", _connecting.length() > 1, - " enabled: ", _count_enabled(), - " stored: ", _count_stored(), - ""); - } - - if (_state == State::IDLE && _deferred_config_update) { - _deferred_config_update = false; - _handle_config_update(); - } - - if (_state == State::IDLE && _pending_bssid.length() > 1) { - _state_transition(_state, State::INFO); - _submit_cmd(Cmd_str("BSS ", _pending_bssid)); - - _pending_bssid = Accesspoint::Bssid(); - } - } - - /** - * Constructor - */ - Frontend(Genode::Env &env, Msg_buffer &msg_buffer) - : - _ap_allocator(env.ram(), env.rm()), - _msg(msg_buffer), - _rfkill_handler(env.ep(), *this, &Wifi::Frontend::_handle_rfkill), - _config_rom(env, "wifi_config"), - _config_sigh(env.ep(), *this, &Wifi::Frontend::_handle_config_update), - _timer(env), - _timer_sigh(env.ep(), *this, &Wifi::Frontend::_handle_timer), - _events_handler(env.ep(), *this, &Wifi::Frontend::_handle_events), - _cmd_handler(env.ep(), *this, &Wifi::Frontend::_handle_cmds) - { - _config_rom.sigh(_config_sigh); - _timer.sigh(_timer_sigh); - - /* set/initialize as unblocked */ - _notify_blockade.wakeup(); - - try { - _ap_reporter.construct(env, "accesspoints", "accesspoints"); - _ap_reporter->generate([&] (Genode::Xml_generator &) { }); - } catch (...) { - Genode::warning("no Report session available, scan results will " - "not be reported"); - } - - try { - _state_reporter.construct(env, "state"); - _state_reporter->enabled(true); - - Genode::Reporter::Xml_generator xml(*_state_reporter, [&] () { - xml.node("accesspoint", [&] () { - xml.attribute("state", "disconnected"); - xml.attribute("rfkilled", _rfkilled); - }); - }); - } catch (...) { - Genode::warning("no Report session available, connectivity will " - "not be reported"); - } - - /* read in list of APs */ - _config_update(false); - - /* get initial RFKILL state */ - _handle_rfkill(); - - /* kick-off initial scanning */ - _handle_timer(); - } - - /** - * Trigger RFKILL notification - * - * Used by the wifi driver to notify front end. - */ - void rfkill_notify() override - { - _rfkill_handler.local_submit(); - } - - /** - * Get result signal capability - * - * Used by the wpa_supplicant to notify front end after processing - * a command. - */ - Genode::Signal_context_capability result_sigh() - { - return _cmd_handler; - } - - /** - * Get event signal capability - * - * Used by the wpa_supplicant to notify front whenever a event - * was triggered. - */ - Genode::Signal_context_capability event_sigh() - { - return _events_handler; - } - - /** - * Block until events were handled by the front end - * - * Used by the wpa_supplicant to wait for the front end. - */ - void block_for_processing() { _notify_lock_lock(); } -}; - -#endif /* _WIFI_FRONTEND_H_ */ diff --git a/repos/dde_linux/src/driver/wifi/main.cc b/repos/dde_linux/src/driver/wifi/main.cc index ef5842875e..18c1386bbd 100644 --- a/repos/dde_linux/src/driver/wifi/main.cc +++ b/repos/dde_linux/src/driver/wifi/main.cc @@ -28,68 +28,12 @@ /* local includes */ #include "util.h" #include "wpa.h" -#include "frontend.h" +#include "manager.h" #include "access_firmware.h" using namespace Genode; -static Msg_buffer _wifi_msg_buffer; -static Wifi::Frontend *_wifi_frontend = nullptr; - - -/** - * Notify front end about command processing - * - * Called by the CTRL interface after wpa_supplicant has processed - * the command. - */ -void wifi_block_for_processing(void) -{ - if (!_wifi_frontend) { - warning("frontend not available, dropping notification"); - return; - } - - /* - * Next time we block as long as the front end has not finished - * handling our previous request - */ - _wifi_frontend->block_for_processing(); - - /* XXX hack to trick poll() into returning faster */ - wpa_ctrl_set_fd(); -} - - -void wifi_notify_cmd_result(void) -{ - if (!_wifi_frontend) { - warning("frontend not available, dropping notification"); - return; - } - - Signal_transmitter(_wifi_frontend->result_sigh()).submit(); -} - - -/** - * Notify front end about triggered event - * - * Called by the CTRL interface whenever wpa_supplicant has triggered - * a event. - */ -void wifi_notify_event(void) -{ - if (!_wifi_frontend) { - Genode::warning("frontend not available, dropping notification"); - return; - } - - Signal_transmitter(_wifi_frontend->event_sigh()).submit(); -} - - /* exported by wifi.lib.so */ extern void wifi_init(Genode::Env&, Genode::Blockade&); extern void wifi_set_rfkill_sigh(Genode::Signal_context_capability); @@ -101,8 +45,8 @@ struct Main { Env &env; - Constructible _wpa; - Constructible _frontend; + Constructible _wpa; + Constructible _manager; struct Request_handler : Wifi::Firmware_request_handler { @@ -173,28 +117,17 @@ struct Main /* prepare Lx_kit::Env */ wifi_init(env, _wpa_startup_blockade); - _frontend.construct(env, _wifi_msg_buffer); - _wifi_frontend = &*_frontend; + _manager.construct(env); - Wifi::rfkill_establish_handler(*_wifi_frontend); + Wifi::rfkill_establish_handler(*_manager); Wifi::firmware_establish_handler(_request_handler); + Wifi::ctrl_init(_manager->msg_buffer()); _wpa.construct(env, _wpa_startup_blockade); } }; -/** - * Return shared-memory message buffer - * - * It is used by the wpa_supplicant CTRL interface. - */ -void *wifi_get_buffer(void) -{ - return &_wifi_msg_buffer; -} - - void Libc::Component::construct(Libc::Env &env) { static Main server(env); diff --git a/repos/dde_linux/src/driver/wifi/manager.h b/repos/dde_linux/src/driver/wifi/manager.h new file mode 100644 index 0000000000..8ee850eb5e --- /dev/null +++ b/repos/dde_linux/src/driver/wifi/manager.h @@ -0,0 +1,2199 @@ + /* + * \author Josef Soentgen + * \date 2018-07-31 + * + * Wifi manager uses the CTRL interface of the wpa_supplicant via a Genode + * specific ctrl_iface implementation that comprises two distinct memory + * buffers for communication - one for the command results and one for events. + */ + +/* + * Copyright (C) 2018-2024 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef _WIFI_MANAGER_H_ +#define _WIFI_MANAGER_H_ + +/* Genode includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* rep includes */ +#include +#include +using Ctrl_msg_buffer = Wifi::Msg_buffer; + +/* local includes */ +#include + +using namespace Genode; + +/* internal interface of lib/wifi/socket_call.cc */ +extern void wifi_kick_socketcall(); + + +namespace Wifi { + struct Manager; +} + + +enum Recv_msg_index : unsigned char { + OK = 0, + FAIL, + SCAN_RESULTS, + CONNECTED, + DISCONNECTED, + SME_AUTH, + NOT_FOUND, + MAX_INDEX, /* keep as last entry */ +}; + + +static struct { + char const *string; + size_t len; +} recv_table[Recv_msg_index::MAX_INDEX] = { + { "OK", 2 }, + { "FAIL", 4 }, + { "CTRL-EVENT-SCAN-RESULTS", 23 }, + { "CTRL-EVENT-CONNECTED", 20 }, + { "CTRL-EVENT-DISCONNECTED", 23 }, + { "SME: Trying to authenticate", 27 }, + { "CTRL-EVENT-NETWORK-NOT-FOUND", 28 }, +}; + + +static inline bool check_recv_msg(char const *msg, + auto const &entry) { + return Genode::strcmp(entry.string, msg, entry.len) == 0; } + + +static bool cmd_successful(char const *msg) { + return check_recv_msg(msg, recv_table[Recv_msg_index::OK]); } + + +static bool cmd_fail(char const *msg) { + return check_recv_msg(msg, recv_table[Recv_msg_index::FAIL]); } + + +static bool results_available(char const *msg) { + return check_recv_msg(msg, recv_table[Recv_msg_index::SCAN_RESULTS]); } + + +static bool connecting_to_network(char const *msg) { + return check_recv_msg(msg, recv_table[Recv_msg_index::SME_AUTH]); } + + +static bool network_not_found(char const *msg) { + return check_recv_msg(msg, recv_table[Recv_msg_index::NOT_FOUND]); } + + +static bool disconnected_from_network(char const *msg) { + return check_recv_msg(msg, recv_table[Recv_msg_index::DISCONNECTED]); } + + +static bool connected_to_network(char const *msg) { + return check_recv_msg(msg, recv_table[Recv_msg_index::CONNECTED]); } + + +static bool scan_results(char const *msg) { + return Genode::strcmp("bssid", msg, 5) == 0; } + + +using Cmd = String; +static void ctrl_cmd(Ctrl_msg_buffer &msg, Cmd const &cmd) +{ + memcpy(msg.send, cmd.string(), cmd.length()); + ++msg.send_id; + + wpa_ctrl_set_fd(); + + /* + * We might have to pull the socketcall task out of poll_all() + * because otherwise we might be late and wpa_supplicant has + * already removed all scan results due to BSS age settings. + */ + wifi_kick_socketcall(); +} + + +/* + * The Accesspoint object contains all information to join + * a wireless network. + */ +struct Accesspoint : Interface +{ + using Bssid = String<17+1>; + using Freq = String< 4+1>; + using Prot = String< 7+1>; + using Ssid = String<32+1>; + using Pass = String<63+1>; + + static bool valid(Ssid const &ssid) { + return ssid.length() > 1 && ssid.length() <= 32 + 1; } + + static bool valid(Pass const &pass) { + return pass.length() > 8 && pass.length() <= 63 + 1; } + + static bool valid(Bssid const &bssid) { + return bssid.length() == 17 + 1; } + + /* + * Accesspoint information fields used by manager + */ + Bssid bssid { }; + Freq freq { }; + Prot prot { }; + Ssid ssid { }; + Pass pass { }; + unsigned quality { 0 }; + + static Accesspoint from_xml(Xml_node const &node) + { + Accesspoint ap { }; + + ap.ssid = node.attribute_value("ssid", Accesspoint::Ssid()); + ap.bssid = node.attribute_value("bssid", Accesspoint::Bssid()); + + ap.pass = node.attribute_value("passphrase", Accesspoint::Pass("")); + ap.prot = node.attribute_value("protection", Accesspoint::Prot("NONE")); + + return ap; + } + + /* + * CTRL interface fields + */ + int id { -1 }; + + /** + * Default constructor + */ + Accesspoint() { } + + /** + * Constructor that initializes SSID fields + * + * It is used by the join-state handling to construct + * the connect/connecting AP. + */ + Accesspoint(Bssid const &bssid, Ssid const &ssid) + : bssid { bssid }, ssid { ssid } { } + + /** + * Constructor that initializes information fields + * + * It is used when parsing the scan results into an + * AP. + */ + Accesspoint(char const *bssid, char const *freq, + char const *prot, char const *ssid, unsigned quality) + : bssid(bssid), freq(freq), prot(prot), ssid(ssid), quality(quality) + { } + + void print(Output &out) const + { + Genode::print(out, "SSID: '", ssid, "'", " " + "BSSID: '", bssid, "'", " " + "protection: ", prot, " " + "id: ", id, " " + "quality: ", quality); + } + + bool wpa() const { return prot != "NONE"; } + bool wpa3() const { return prot == "WPA3"; } + bool stored() const { return id != -1; } + + bool updated_from(Accesspoint const &other) + { + bool const update = ((Accesspoint::valid(other.bssid) && other.bssid != bssid) + || pass != other.pass + || prot != other.prot); + if (!update) + return false; + + if (Accesspoint::valid(other.bssid)) + bssid = other.bssid; + + pass = other.pass; + prot = other.prot; + return true; + } +}; + + +struct Network : List_model::Element +{ + + Accesspoint _accesspoint { }; + + Network(Accesspoint const &ap) : _accesspoint { ap } { } + + virtual ~Network() { } + + void with_accesspoint(auto const &fn) { + fn(_accesspoint); } + + void with_accesspoint(auto const &fn) const { + fn(_accesspoint); } + + /************************** + ** List_model interface ** + **************************/ + + static bool type_matches(Xml_node const &node) { + return node.has_type("network"); } + + bool matches(Xml_node const &node) { + return _accesspoint.ssid == node.attribute_value("ssid", Accesspoint::Ssid()); } +}; + + +struct Explicit_scan : List_model::Element +{ + + Accesspoint::Ssid _ssid { }; + + Explicit_scan(Accesspoint::Ssid const &ssid) : _ssid { ssid } { } + + virtual ~Explicit_scan() { } + + void with_ssid(auto const &fn) { + if (Accesspoint::valid(_ssid)) + fn(_ssid); + } + + void with_ssid(auto const &fn) const { + if (Accesspoint::valid(_ssid)) + fn(_ssid); + } + + /************************** + ** List_model interface ** + **************************/ + + static bool type_matches(Xml_node const &node) { + return node.has_type("explicit_scan"); } + + bool matches(Xml_node const &node) { + return _ssid == node.attribute_value("ssid", Accesspoint::Ssid()); } +}; + + +static void for_each_line(char const *msg, auto const &fn) +{ + char line_buffer[1024]; + size_t cur = 0; + + while (msg[cur] != 0) { + size_t until = Util::next_char(msg, cur, '\n'); + if (until >= sizeof(line_buffer)) { + Genode::error(__func__, ": line too large, abort processing"); + return; + } + memcpy(line_buffer, &msg[cur], until); + line_buffer[until] = 0; + cur += until + 1; + + fn(line_buffer); + } +} + + +static void for_each_result_line(char const *msg, auto const &fn) +{ + char line_buffer[1024]; + size_t cur = 0; + + /* skip headline */ + size_t until = Util::next_char(msg, cur, '\n'); + cur += until + 1; + + while (msg[cur] != 0) { + until = Util::next_char(msg, cur, '\n'); + if (until >= sizeof(line_buffer)) { + Genode::error(__func__, ": line too large, abort processing"); + return; + } + memcpy(line_buffer, &msg[cur], until); + line_buffer[until] = 0; + cur += until + 1; + + char const *s[5] = { }; + + for (size_t c = 0, i = 0; i < 5; i++) { + size_t pos = Util::next_char(line_buffer, c, '\t'); + line_buffer[c+pos] = 0; + s[i] = (char const*)&line_buffer[c]; + c += pos + 1; + } + + bool const is_wpa1 = Util::string_contains((char const*)s[3], "WPA"); + bool const is_wpa2 = Util::string_contains((char const*)s[3], "WPA2"); + bool const is_wpa3 = Util::string_contains((char const*)s[3], "SAE"); + + unsigned const quality = Util::approximate_quality(s[2]); + + char const *prot = is_wpa1 ? "WPA" : "NONE"; + prot = is_wpa2 ? "WPA2" : prot; + prot = is_wpa3 ? "WPA3" : prot; + + fn(Accesspoint(s[0], s[1], prot, s[4], quality)); + } +} + + +struct Action : Fifo::Element +{ + enum class Type : unsigned { COMMAND, QUERY }; + enum class Command : unsigned { + INVALID, ADD, DISABLE, ENABLE, EXPLICIT_SCAN, + LOG_LEVEL, REMOVE, SCAN, SCAN_RESULTS, SET, UPDATE, }; + enum class Query : unsigned { + INVALID, BSS, RSSI, STATUS, }; + + Type const type; + Command const command; + Query const query; + + bool successful; + + Action(Command cmd) + : + type { Type::COMMAND }, + command { cmd }, + query { Query::INVALID }, + successful { true } + { } + + Action(Query query) + : + type { Type::QUERY }, + command { Command::INVALID }, + query { query }, + successful { true } + { } + + virtual void execute() { } + + virtual void check(char const *) { } + + virtual void response(char const *, Accesspoint &) { } + + virtual bool complete() const = 0; + + virtual void print(Genode::Output &) const = 0; +}; + + +/* + * Action for adding a new network + * + * In case the 'auto_connect' option is set for the network it + * will also be enabled to active auto-joining. + */ +struct Add_network_cmd : Action +{ + enum class State : unsigned { + INIT, ADD_NETWORK, FILL_NETWORK_SSID, FILL_NETWORK_BSSID, + FILL_NETWORK_KEY_MGMT, SET_NETWORK_PMF, FILL_NETWORK_PSK, + ENABLE_NETWORK, COMPLETE + }; + + Ctrl_msg_buffer &_msg; + Accesspoint _accesspoint; + State _state; + + Add_network_cmd(Ctrl_msg_buffer &msg, Accesspoint const &ap) + : + Action { Command::ADD }, + _msg { msg }, + _accesspoint { ap }, + _state { State::INIT } + { } + + void print(Output &out) const override + { + Genode::print(out, "Add_network_cmd[", (unsigned)_state, + "] '", _accesspoint.ssid, "'"); + } + + void execute() override + { + switch (_state) { + case State::INIT: + ctrl_cmd(_msg, Cmd("ADD_NETWORK")); + _state = State::ADD_NETWORK; + break; + case State::ADD_NETWORK: + ctrl_cmd(_msg, Cmd("SET_NETWORK ", _accesspoint.id, + " ssid \"", _accesspoint.ssid, "\"")); + _state = State::FILL_NETWORK_SSID; + break; + case State::FILL_NETWORK_SSID: + { + bool const valid = Accesspoint::valid(_accesspoint.bssid); + char const *bssid = valid ? _accesspoint.bssid.string() : ""; + + ctrl_cmd(_msg, Cmd("SET_NETWORK ", _accesspoint.id, + " bssid ", bssid)); + _state = State::FILL_NETWORK_BSSID; + break; + } + case State::FILL_NETWORK_BSSID: + if (_accesspoint.wpa3()) { + ctrl_cmd(_msg, Cmd("SET_NETWORK ", _accesspoint.id, + " key_mgmt SAE")); + _state = State::FILL_NETWORK_KEY_MGMT; + } else { + if (_accesspoint.wpa()) + ctrl_cmd(_msg, Cmd("SET_NETWORK ", _accesspoint.id, + " psk \"", _accesspoint.pass, "\"")); + else + ctrl_cmd(_msg, Cmd("SET_NETWORK ", _accesspoint.id, + " key_mgmt NONE")); + _state = State::FILL_NETWORK_PSK; + } + break; + case State::FILL_NETWORK_KEY_MGMT: + ctrl_cmd(_msg, Cmd("SET_NETWORK ", _accesspoint.id, + " ieee80211w 2")); + _state = State::SET_NETWORK_PMF; + break; + case State::SET_NETWORK_PMF: + ctrl_cmd(_msg, Cmd("SET_NETWORK ", _accesspoint.id, + " psk \"", _accesspoint.pass, "\"")); + _state = State::FILL_NETWORK_PSK; + break; + case State::FILL_NETWORK_PSK: + ctrl_cmd(_msg, Cmd("ENABLE_NETWORK ", _accesspoint.id)); + _state = State::ENABLE_NETWORK; + break; + case State::ENABLE_NETWORK: + _state = State::COMPLETE; + break; + case State::COMPLETE: + break; + } + } + + void check(char const *msg) override + { + using namespace Genode; + + bool complete = false; + + /* + * Handle response by expected failure handling + * and use fallthrough switch cases to reduce code. + */ + switch (_state) { + case State::INIT: break; + + case State::ADD_NETWORK: + if (cmd_fail(msg)) { + error("ADD_NETWORK(", (unsigned)_state, ") failed: ", msg); + Action::successful = false; + complete = true; + } + break; + + case State::FILL_NETWORK_SSID: [[fallthrough]]; + case State::FILL_NETWORK_BSSID: [[fallthrough]]; + case State::FILL_NETWORK_KEY_MGMT: [[fallthrough]]; + case State::SET_NETWORK_PMF: [[fallthrough]]; + case State::FILL_NETWORK_PSK: [[fallthrough]]; + case State::ENABLE_NETWORK: + if (!cmd_successful(msg)) { + error("ADD_NETWORK(", (unsigned)_state, ") failed: ", msg); + Action::successful = false; + complete = true; + } + break; + case State::COMPLETE: break; + } + + if (complete) { + _state = State::COMPLETE; + return; + } + + switch (_state) { + case State::INIT: break; + case State::ADD_NETWORK: + { + long id = -1; + ascii_to(msg, id); + _accesspoint.id = static_cast(id); + break; + } + case State::FILL_NETWORK_SSID: break; + case State::FILL_NETWORK_BSSID: break; + case State::FILL_NETWORK_KEY_MGMT: break; + case State::SET_NETWORK_PMF: break; + case State::FILL_NETWORK_PSK: break; + case State::ENABLE_NETWORK: break; + case State::COMPLETE: break; + } + } + + Accesspoint const &accesspoint() const + { + return _accesspoint; + } + + bool complete() const override { + return _state == State::COMPLETE; } +}; + + +/* + * Action for removing a network + */ +struct Remove_network_cmd : Action +{ + enum class State : unsigned { + INIT, REMOVE_NETWORK, COMPLETE + }; + + Ctrl_msg_buffer &_msg; + int _id; + State _state; + + Remove_network_cmd(Ctrl_msg_buffer &msg, int id) + : + Action { Command::REMOVE }, + _msg { msg }, + _id { id }, + _state { State::INIT } + { } + + void print(Output &out) const override + { + Genode::print(out, "Remove_network_cmd[", (unsigned)_state, "] id: ", _id); + } + + void execute() override + { + switch (_state) { + case State::INIT: + ctrl_cmd(_msg, Cmd("REMOVE_NETWORK ", _id)); + _state = State::REMOVE_NETWORK; + break; + case State::REMOVE_NETWORK: + _state = State::COMPLETE; + break; + case State::COMPLETE: + break; + } + } + + void check(char const *msg) override + { + using namespace Genode; + + bool complete = false; + + switch (_state) { + case State::INIT: break; + case State::REMOVE_NETWORK: + if (cmd_fail(msg)) { + error("could not remove network: ", msg); + Action::successful = false; + complete = true; + } + break; + case State::COMPLETE: break; + } + + if (complete) + _state = State::COMPLETE; + } + + bool complete() const override { + return _state == State::COMPLETE; } +}; + + +/* + * Action for updating a network + * + * For now only the PSK is updated. + */ +struct Update_network_cmd : Action +{ + enum class Op : unsigned { + UPDATE_ALL, DISABLE_ONLY }; + enum class State : unsigned { + INIT, UPDATE_NETWORK_PSK, + DISABLE_NETWORK, ENABLE_NETWORK, COMPLETE + }; + Ctrl_msg_buffer &_msg; + Accesspoint _accesspoint; + State _state; + Op _op; + + Update_network_cmd(Ctrl_msg_buffer &msg, + Accesspoint const &ap, + Op op = Op::UPDATE_ALL) + : + Action { Command::UPDATE }, + _msg { msg }, + _accesspoint { ap }, + _state { State::INIT }, + _op { op } + { } + + void print(Output &out) const override + { + Genode::print(out, "Update_network_cmd[", (unsigned)_state, + "] id: ", _accesspoint.id); + } + + void execute() override + { + // XXX change to disable -> psk ?-> enable + switch (_state) { + case State::INIT: + ctrl_cmd(_msg, Cmd("SET_NETWORK ", _accesspoint.id, + " psk \"", _accesspoint.pass, "\"")); + _state = State::UPDATE_NETWORK_PSK; + break; + case State::UPDATE_NETWORK_PSK: + ctrl_cmd(_msg, Cmd("DISABLE_NETWORK ", _accesspoint.id)); + _state = State::DISABLE_NETWORK; + break; + case State::DISABLE_NETWORK: + if (_op != Op::DISABLE_ONLY) { + ctrl_cmd(_msg, Cmd("ENABLE_NETWORK ", _accesspoint.id)); + _state = State::ENABLE_NETWORK; + } else + _state = State::COMPLETE; + break; + case State::ENABLE_NETWORK: + _state = State::COMPLETE; + case State::COMPLETE: + break; + } + } + + void check(char const *msg) override + { + using namespace Genode; + + bool complete = false; + + switch (_state) { + case State::INIT: break; + case State::UPDATE_NETWORK_PSK: [[fallthrough]]; + case State::ENABLE_NETWORK: [[fallthrough]]; + case State::DISABLE_NETWORK: + if (!cmd_successful(msg)) { + error("UPDATE_NETWORK(", (unsigned)_state, ") failed: ", msg); + Action::successful = false; + complete = true; + } + break; + case State::COMPLETE: break; + } + + if (complete) + _state = State::COMPLETE; + } + + bool complete() const override { + return _state == State::COMPLETE; } +}; + + +/* + * Action for initiating a scan request + */ +struct Scan_cmd : Action +{ + enum class State : unsigned { + INIT, SCAN, COMPLETE + }; + Ctrl_msg_buffer &_msg; + State _state; + + /* enough to store 64 hidden networks */ + char ssid_buffer[4060] { }; + size_t buffer_pos { 0 }; + + Scan_cmd(Ctrl_msg_buffer &msg) + : + Action { Command::SCAN }, + _msg { msg }, + _state { State::INIT } + { } + + void print(Output &out) const override + { + Genode::print(out, "Scan_cmd[", (unsigned)_state, "]"); + } + + void append_ssid(Accesspoint::Ssid const &ssid) + { + enum { SSID_ARG_LEN = 6 + 64, /* " ssid " + "a5a5a5a5..." */ }; + /* silently ignore SSID */ + if (buffer_pos + SSID_ARG_LEN >= sizeof(ssid_buffer)) + return; + + char ssid_hex[64+1] { }; + char const *ssid_ptr = ssid.string(); + + for (size_t i = 0; i < ssid.length() - 1; i++) { + Util::byte2hex((ssid_hex + i * 2), ssid_ptr[i]); + } + + Genode::String tmp(" ssid ", (char const*)ssid_hex); + size_t const tmp_len = tmp.length() - 1; + + Genode::memcpy((ssid_buffer + buffer_pos), tmp.string(), tmp_len); + buffer_pos += tmp_len; + } + + void execute() override + { + switch (_state) { + case State::INIT: + ctrl_cmd(_msg, Cmd("SCAN ", (char const*)ssid_buffer)); + _state = State::SCAN; + break; + case State::SCAN: + _state = State::COMPLETE; + break; + case State::COMPLETE: + break; + } + } + + void check(char const *msg) override + { + using namespace Genode; + + bool complete = false; + + switch (_state) { + case State::INIT: break; + case State::SCAN: + if (!cmd_successful(msg)) { + /* ignore busy fails silently */ + bool const scan_busy = strcmp(msg, "FAIL-BUSY"); + if (!scan_busy) { + error("could not initiate scan: ", msg); + Action::successful = false; + complete = true; + } + } + break; + case State::COMPLETE: break; + } + + if (complete) + _state = State::COMPLETE; + } + + bool complete() const override { + return _state == State::COMPLETE; } +}; + + +/* + * Action for initiating a scan results request + */ +struct Scan_results_cmd : Action +{ + enum class State : unsigned { + INIT, SCAN_RESULTS, COMPLETE + }; + Ctrl_msg_buffer &_msg; + State _state; + + Expanding_reporter &_reporter; + + void _generate_report(char const *msg) + { + unsigned count_lines = 0; + for_each_line(msg, [&] (char const*) { count_lines++; }); + + if (!count_lines) + return; + + try { + _reporter.generate([&] (Xml_generator &xml) { + + for_each_result_line(msg, [&] (Accesspoint const &ap) { + + /* ignore potentially empty ssids */ + if (ap.ssid == "") + return; + + xml.node("accesspoint", [&]() { + xml.attribute("ssid", ap.ssid); + xml.attribute("bssid", ap.bssid); + xml.attribute("freq", ap.freq); + xml.attribute("quality", ap.quality); + if (ap.wpa()) { xml.attribute("protection", ap.prot); } + }); + }); + }); + + } catch (...) { /* silently omit report */ } + } + + Scan_results_cmd(Ctrl_msg_buffer &msg, + Genode::Expanding_reporter &reporter) + : + Action { Command::SCAN_RESULTS }, + _msg { msg }, + _state { State::INIT }, + _reporter { reporter } + { } + + void print(Output &out) const override + { + Genode::print(out, "Scan_results_cmd[", (unsigned)_state, "]"); + } + + void execute() override + { + switch (_state) { + case State::INIT: + ctrl_cmd(_msg, Cmd("SCAN_RESULTS")); + _state = State::SCAN_RESULTS; + break; + case State::SCAN_RESULTS: + _state = State::COMPLETE; + break; + case State::COMPLETE: + break; + } + } + + void check(char const *msg) override + { + using namespace Genode; + + bool complete = false; + + switch (_state) { + case State::INIT: break; + case State::SCAN_RESULTS: + if (scan_results(msg)) + _generate_report(msg); + break; + case State::COMPLETE: break; + } + + if (complete) + _state = State::COMPLETE; + } + + bool complete() const override { + return _state == State::COMPLETE; } +}; + + +/* + * Action for setting a configuration variable + */ +struct Set_cmd : Action +{ + using Key = String<64>; + using Value = String<128>; + + enum class State : unsigned { + INIT, SET, COMPLETE + }; + Ctrl_msg_buffer &_msg; + State _state; + + Key _key; + Value _value; + + Set_cmd(Ctrl_msg_buffer &msg, Key key, Value value) + : + Action { Command::SET }, + _msg { msg }, + _state { State::INIT }, + _key { key }, + _value { value } + { } + + void print(Output &out) const override + { + Genode::print(out, "Set_cmd[", (unsigned)_state, "] key: '", + _key, "' value: '", _value, "'"); + } + + void execute() override + { + switch (_state) { + case State::INIT: + ctrl_cmd(_msg, Cmd("SET ", _key, " \"", _value, "\"")); + _state = State::SET; + break; + case State::SET: + _state = State::COMPLETE; + break; + case State::COMPLETE: + break; + } + } + + void check(char const *msg) override + { + using namespace Genode; + + bool complete = false; + + switch (_state) { + case State::INIT: break; + case State::SET: + if (!cmd_successful(msg)) { + error("could not set '", _key, "' to '", + _value, "': '", msg, "'"); + Action::successful = false; + complete = true; + } + break; + case State::COMPLETE: break; + } + + if (complete) + _state = State::COMPLETE; + } + + bool complete() const override { + return _state == State::COMPLETE; } +}; + + +/* + * Action for setting a configuration variable + */ +struct Log_level_cmd : Action +{ + using Level = Genode::String<16>; + + enum class State : unsigned { + INIT, LOG_LEVEL, COMPLETE + }; + Ctrl_msg_buffer &_msg; + State _state; + + Level _level; + + Log_level_cmd(Ctrl_msg_buffer &msg, Level const &level) + : + Action { Command::LOG_LEVEL }, + _msg { msg }, + _state { State::INIT }, + _level { level } + { } + + void print(Output &out) const override + { + Genode::print(out, "Log_level_cmd[", (unsigned)_state, "] '", _level, "'"); + } + + void execute() override + { + switch (_state) { + case State::INIT: + ctrl_cmd(_msg, Cmd("LOG_LEVEL ", _level)); + _state = State::LOG_LEVEL; + break; + case State::LOG_LEVEL: + _state = State::COMPLETE; + break; + case State::COMPLETE: + break; + } + } + + void check(char const *msg) override + { + using namespace Genode; + + bool complete = false; + + switch (_state) { + case State::INIT: break; + case State::LOG_LEVEL: + if (!cmd_successful(msg)) { + error("could not set LOG_LEVEL to ", _level); + Action::successful = false; + complete = true; + } + break; + case State::COMPLETE: break; + } + + if (complete) + _state = State::COMPLETE; + } + + bool complete() const override { + return _state == State::COMPLETE; } +}; + + +/* + * Action for querying BSS information + */ +struct Bss_query : Action +{ + enum class State : unsigned { + INIT, BSS, COMPLETE + }; + Ctrl_msg_buffer &_msg; + Accesspoint::Bssid _bssid; + State _state; + + Bss_query(Ctrl_msg_buffer &msg, Accesspoint::Bssid bssid) + : + Action { Query::BSS }, + _msg { msg }, + _bssid { bssid }, + _state { State::INIT } + { } + + void print(Output &out) const override + { + Genode::print(out, "Bss_query[", (unsigned)_state, "] ", _bssid); + } + + void execute() override + { + switch (_state) { + case State::INIT: + ctrl_cmd(_msg, Cmd("BSS ", _bssid)); + _state = State::BSS; + break; + case State::BSS: break; + case State::COMPLETE: break; + } + } + + void response(char const *msg, Accesspoint &ap) override + { + if (_state != State::BSS) + return; + + _state = State::COMPLETE; + + /* + * It might happen that the supplicant already flushed + * its internal BSS information and cannot help us out. + * Since we already sent out a rudimentary report, just + * stop here. + */ + if (0 == msg[0]) + return; + + auto fill_ap = [&] (char const *line) { + if (Genode::strcmp(line, "ssid=", 5) == 0) { + ap.ssid = Accesspoint::Ssid(line+5); + } else + + if (Genode::strcmp(line, "bssid=", 6) == 0) { + ap.bssid = Accesspoint::Bssid(line+6); + } else + + if (Genode::strcmp(line, "freq=", 5) == 0) { + ap.freq = Accesspoint::Freq(line+5); + } + }; + for_each_line(msg, fill_ap); + } + + bool complete() const override { + return _state == State::COMPLETE; } +}; + + +/* + * Action for querying RSSI information + */ +struct Rssi_query : Action +{ + enum class State : unsigned { + INIT, RSSI, COMPLETE + }; + Ctrl_msg_buffer &_msg; + State _state; + + Rssi_query(Ctrl_msg_buffer &msg) + : + Action { Query::RSSI }, + _msg { msg }, + _state { State::INIT } + { } + + void print(Output &out) const override + { + Genode::print(out, "Rssi_query[", (unsigned)_state, "]"); + } + + void execute() override + { + switch (_state) { + case State::INIT: + ctrl_cmd(_msg, Cmd("SIGNAL_POLL")); + _state = State::RSSI; + break; + case State::RSSI: break; + case State::COMPLETE: break; + } + } + + void response(char const *msg, Accesspoint &ap) override + { + if (_state != State::RSSI) + return; + + _state = State::COMPLETE; + + using Rssi = Genode::String<5>; + Rssi rssi { }; + auto get_rssi = [&] (char const *line) { + if (strcmp(line, "RSSI=", 5) != 0) + return; + + rssi = Rssi(line + 5); + }; + for_each_line(msg, get_rssi); + + /* + * Use the same simplified approximation for denoting + * the quality to be in line with the scan results. + */ + ap.quality = Util::approximate_quality(rssi.valid() ? rssi.string() + : "-100"); + } + + bool complete() const override { + return _state == State::COMPLETE; } +}; + + +/* + * Action for querying the current connection status + */ +struct Status_query : Action +{ + enum class State : unsigned { + INIT, STATUS, COMPLETE + }; + Ctrl_msg_buffer &_msg; + State _state; + + Status_query(Ctrl_msg_buffer &msg) + : + Action { Query::STATUS }, + _msg { msg }, + _state { State::INIT } + { } + + void print(Output &out) const override + { + Genode::print(out, "Status_query[", (unsigned)_state, "]"); + } + + void execute() override + { + switch (_state) { + case State::INIT: + ctrl_cmd(_msg, Cmd("STATUS")); + _state = State::STATUS; + break; + case State::STATUS: break; + case State::COMPLETE: break; + } + } + + void response(char const *msg, Accesspoint &ap) override + { + if (_state != State::STATUS) + return; + + _state = State::COMPLETE; + + /* + * It might happen that the supplicant already flushed + * its internal BSS information and cannot help us out. + * Since we already sent out a rudimentary report, just + * stop here. + */ + if (0 == msg[0]) + return; + + auto fill_ap = [&] (char const *line) { + if (strcmp(line, "ssid=", 5) == 0) { + ap.ssid = Accesspoint::Ssid(line+5); + } else + + if (strcmp(line, "bssid=", 6) == 0) { + ap.bssid = Accesspoint::Bssid(line+6); + } else + + if (strcmp(line, "freq=", 5) == 0) { + ap.freq = Accesspoint::Freq(line+5); + } + }; + for_each_line(msg, fill_ap); + } + + bool complete() const override { + return _state == State::COMPLETE; } +}; + + +/* + * Wifi driver manager + */ +struct Wifi::Manager : Wifi::Rfkill_notification_handler +{ + Manager(const Manager&) = delete; + Manager& operator=(const Manager&) = delete; + + /* Network handling */ + + Heap _network_allocator; + List_model _network_list { }; + + /* Explicit_scan handling */ + + Heap _explicit_scan_allocator; + List_model _explicit_scan_list { }; + + /* + * Action queue handling + */ + + Heap _actions_alloc; + Fifo _actions { }; + + Action *_pending_action { nullptr }; + + void _queue_action(Action &action, bool verbose) + { + _actions.enqueue(action); + if (verbose) + Genode::log("Queue ", action); + } + + enum class Pending_action_result : unsigned { + INCOMPLETE, COMPLETE }; + + void _with_pending_action(auto const &fn) + { + if (!_pending_action) + _actions.dequeue([&] (Action &action) { + _pending_action = &action; }); + + Pending_action_result const result = + _pending_action ? fn(*_pending_action) + : Pending_action_result::INCOMPLETE; + if (result == Pending_action_result::COMPLETE) { + destroy(_actions_alloc, _pending_action); + _pending_action = nullptr; + } + } + + void _dispatch_action_if_needed() + { + if (_pending_action) + return; + + /* + * Grab the next action and call execute() + * to poke the CTRL interface. + */ + + _actions.dequeue([&] (Action &action) { + _pending_action = &action; + _pending_action->execute(); + }); + } + + Signal_handler _cmd_handler; + Signal_handler _events_handler; + + Blockade _notify_blockade { }; + + struct Notify : Notify_interface + { + Signal_handler &_response; + Signal_handler &_event; + Blockade &_blockade; + + Notify(Signal_handler &response, + Signal_handler &event, + Blockade &blockade) + : + _response { response }, + _event { event }, + _blockade { blockade } + { } + + /********************** + ** Notify_interface ** + **********************/ + + void submit_response() override { + _response.local_submit(); } + + void submit_event() override { + _event.local_submit(); } + + void block_for_processing() override { + _blockade.block(); } + } _notify { _cmd_handler, _events_handler, _notify_blockade }; + + Msg_buffer _msg { _notify }; + + void _handle_rfkill() + { + _join.rfkilled = Wifi::rfkill_blocked(); + + /* re-enable scan timer */ + if (!_join.rfkilled) + _try_arming_any_timer(); + } + + Signal_handler _rfkill_handler; + + /* + * Configuration handling + */ + + Attached_rom_dataspace _config_rom; + Signal_handler _config_sigh; + + struct Config + { + enum { + DEFAULT_CONNECTED_SCAN_INTERVAL = 30, + DEFAULT_SCAN_INTERVAL = 5, + DEFAULT_UPDATE_QUAILITY_INTERVAL = 30, + + DEFAULT_VERBOSE = false, + DEFAULT_RFKILL = false, + }; + + unsigned scan_interval { DEFAULT_SCAN_INTERVAL }; + unsigned update_quality_interval { DEFAULT_UPDATE_QUAILITY_INTERVAL }; + + bool intervals_changed(Config const &cfg) const + { + return scan_interval != cfg.scan_interval + || update_quality_interval != cfg.update_quality_interval; + } + + bool verbose { DEFAULT_VERBOSE }; + bool rfkill { DEFAULT_RFKILL }; + + bool rfkill_changed(Config const &cfg) const { + return rfkill != cfg.rfkill; } + + /* see wpa_debug.h - EXCESSIVE, MSGDUMP, DEBUG, INFO, WARNING, ERROR */ + using Log_level = Log_level_cmd::Level; + Log_level log_level { "" }; + + bool log_level_changed(Config const &cfg) const { + return log_level != cfg.log_level; } + + bool log_level_set() const { + return log_level.length() > 1; } + + using Bgscan = Genode::String<16>; + Bgscan bgscan { "" }; + + bool bgscan_changed(Config const &cfg) const { + return bgscan != cfg.bgscan; } + + bool bgscan_set() const { + return bgscan.length() >= 1; } + + static Config from_xml(Xml_node const &node) + { + bool const verbose = node.attribute_value("verbose", + (bool)DEFAULT_VERBOSE); + bool const rfkill = node.attribute_value("rfkill", + (bool)DEFAULT_RFKILL); + Log_level log_level = + node.attribute_value("log_level", Log_level("error")); + /* always enforce at leaast error level of verbosity */ + if (log_level.length() <= 1) + log_level = Log_level("error"); + + Bgscan const bgscan = + node.attribute_value("bgscan", Bgscan("simple:30:-70:600")); + + unsigned const scan_interval = + Util::check_time(node.attribute_value("scan_interval", + (unsigned)DEFAULT_SCAN_INTERVAL), + 5, 15*60); + + unsigned const update_quality_interval = + Util::check_time(node.attribute_value("update_quality_interval", + (unsigned)DEFAULT_UPDATE_QUAILITY_INTERVAL), + 10, 15*60); + + Config new_config { + .scan_interval = scan_interval, + .update_quality_interval = update_quality_interval, + .verbose = verbose, + .rfkill = rfkill, + .log_level = log_level, + .bgscan = bgscan + }; + return new_config; + } + }; + + Config _config { }; + + void _config_update(bool initial_config) + { + _config_rom.update(); + + if (!_config_rom.valid()) + return; + + Xml_node const config_node = _config_rom.xml(); + + Config const old_config = _config; + + _config = Config::from_xml(config_node); + + if (_config.intervals_changed(old_config) || initial_config) + _try_arming_any_timer(); + + if (_config.rfkill_changed(old_config) || initial_config) { + Wifi::set_rfkill(_config.rfkill); + + /* + * In case we get blocked set rfkilled immediately to prevent + * any further scanning operation. The actual value will be set + * by the singal handler but is not expected to be any different + * as the rfkill call is not supposed to fail. + */ + if (_config.rfkill && !_join.rfkilled) + _join.rfkilled = true; + } + + if (_config.log_level_changed(old_config) || initial_config) + if (_config.log_level_set()) + _queue_action(*new (_actions_alloc) + Log_level_cmd(_msg, _config.log_level), _config.verbose); + + if (_config.bgscan_changed(old_config) || initial_config) + if (_config.bgscan_set()) + _queue_action(*new (_actions_alloc) + Set_cmd(_msg, Set_cmd::Key("bgscan"), + Set_cmd::Value(_config.bgscan)), + _config.verbose); + + _network_list.update_from_xml(config_node, + + [&] (Genode::Xml_node const &node) -> Network & { + + Accesspoint const ap = Accesspoint::from_xml(node); + + /* + * Only make the supplicant acquainted with the network + * when it is usable, it always needs a valid SSID and + * in case it is protected also a valid PSK, but create + * the Network object nonetheless to satisfy the List_model + * requirements. + */ + + bool const ssid_valid = Accesspoint::valid(ap.ssid); + if (!ssid_valid) + warning("accesspoint has invalid ssid: '", ap.ssid, "'"); + + bool const pass_valid = ap.wpa() ? Accesspoint::valid(ap.pass) + : true; + if (!pass_valid) + warning("accesspoint '", ap.ssid, "' has invalid psk"); + + if (ssid_valid && pass_valid) + _queue_action(*new (_actions_alloc) + Add_network_cmd(_msg, ap), _config.verbose); + + return *new (_network_allocator) Network(ap); + }, + [&] (Network &network) { + + network.with_accesspoint([&] (Accesspoint &ap) { + + if (!Accesspoint::valid(ap.ssid) || !ap.stored()) + return; + + _queue_action(*new (_actions_alloc) + Remove_network_cmd(_msg, ap.id), _config.verbose); + }); + + Genode::destroy(_network_allocator, &network); + }, + [&] (Network &network, Genode::Xml_node const &node) { + Accesspoint const updated_ap = Accesspoint::from_xml(node); + + network.with_accesspoint([&] (Accesspoint &ap) { + + if (!ap.updated_from(updated_ap)) + return; + + if (!ap.stored()) + return; + + _queue_action(*new (_actions_alloc) + Update_network_cmd(_msg, ap), _config.verbose); + }); + }); + + _explicit_scan_list.update_from_xml(config_node, + + [&] (Genode::Xml_node const &node) -> Explicit_scan & { + Accesspoint::Ssid const ssid = + node.attribute_value("ssid", Accesspoint::Ssid()); + + /* + * Always created the Explicit_scan object but ignore + * invalid ones during SCAN operation to satisfy the + * List_model requirements. + */ + return *new (_explicit_scan_allocator) Explicit_scan(ssid); + }, + [&] (Explicit_scan &explicit_scan) { + Genode::destroy(_explicit_scan_allocator, + &explicit_scan); + }, + [&] (Explicit_scan &explicit_scan, Genode::Xml_node const &node) { + /* + * Intentionally left empty as we never have to update the + * object as it only contains the SSID that also serves as + * identifier. + */ + }); + + _dispatch_action_if_needed(); + } + + void _handle_config_update() { _config_update(false); } + + /* + * Timeout handling + */ + + Timer::Connection _timer; + + Timer::One_shot_timeout _scan_timeout { + _timer, *this, &Wifi::Manager::_handle_scan_timeout }; + + Timer::One_shot_timeout _quality_timeout { + _timer, *this, &Wifi::Manager::_handle_quality_timeout }; + + enum class Timer_type : uint8_t { SCAN, SIGNAL_POLL }; + + bool _arm_timer(Timer_type const type) + { + auto seconds_from_type = [&] (Timer_type const type) { + switch (type) { + case Timer_type::SCAN: return _config.scan_interval; + case Timer_type::SIGNAL_POLL: return _config.update_quality_interval; + } + return 0u; + }; + + Microseconds const us { seconds_from_type(type) * 1000'000u }; + if (!us.value) + return false; + + if (_config.verbose) { + auto name_from_type = [&] (Timer_type const type) { + switch (type) { + case Timer_type::SCAN: return "scan"; + case Timer_type::SIGNAL_POLL: return "signal-poll"; + } + return ""; + }; + + log("Arm timer for ", name_from_type(type), ": ", us); + } + + switch (type) { + case Timer_type::SCAN: _scan_timeout.schedule(us); break; + case Timer_type::SIGNAL_POLL: _quality_timeout.schedule(us); break; + } + return true; + } + + bool _arm_scan_timer() + { + if (_join.state == Join_state::State::CONNECTED) + return false; + + return _arm_timer(Timer_type::SCAN); + } + + bool _arm_poll_timer() + { + if (_join.state != Join_state::State::CONNECTED) + return false; + + return _arm_timer(Timer_type::SIGNAL_POLL); + } + + void _try_arming_any_timer() + { + _arm_scan_timer(); + _arm_poll_timer(); + } + + void _handle_scan_timeout(Genode::Duration) + { + if (_join.rfkilled) { + if (_config.verbose) + log("Scanning: suspend due to RFKILL"); + return; + } + + if (!_arm_scan_timer()) { + if (_config.verbose) + log("Timer: scanning disabled"); + return; + } + + Scan_cmd &scan_cmd = *new (_actions_alloc) Scan_cmd(_msg); + _explicit_scan_list.for_each([&] (Explicit_scan const &explicit_scan) { + explicit_scan.with_ssid([&] (Accesspoint::Ssid const &ssid) { + scan_cmd.append_ssid(ssid); + }); + }); + _queue_action(scan_cmd, _config.verbose); + + _dispatch_action_if_needed(); + } + + void _handle_quality_timeout(Genode::Duration) + { + if (_join.rfkilled) { + if (_config.verbose) + log("Quality polling: suspend due to RFKIL"); + return; + } + + if (!_arm_poll_timer()) { + if (_config.verbose) + log("Timer: signal-strength polling disabled"); + return; + } + + _queue_action(*new (_actions_alloc) Rssi_query(_msg), _config.verbose); + + _dispatch_action_if_needed(); + } + + /* + * CTRL interface event handling + */ + + Constructible _state_reporter { }; + Constructible _ap_reporter { }; + + enum class Bssid_offset : unsigned { + /* by the power of wc -c, I have the start pos... */ + CONNECT = 37, CONNECTING = 33, DISCONNECT = 30, }; + + Accesspoint::Bssid const _extract_bssid(char const *msg, Bssid_offset offset) + { + char bssid[32] = { }; + + size_t const len = 17; + size_t const start = (size_t)offset; + + memcpy(bssid, msg + start, len); + return Accesspoint::Bssid((char const*)bssid); + } + + Accesspoint::Ssid const _extract_ssid(char const *msg) + { + char ssid[64] = { }; + size_t const start = 58; + + /* XXX assume "SME:.*SSID='xx xx' ...)", so look for the + * closing ' but we _really_ should use something like + * printf_encode/printf_deccode functions + * (see wpa_supplicant/src/utils/common.c) and + * remove our patch… + */ + size_t const len = Util::next_char(msg, start, 0x27); + if (!len || len >= 33) + return Accesspoint::Ssid(); + + memcpy(ssid, msg + start, len); + + return Accesspoint::Ssid((char const *)ssid); + } + + enum class Auth_result : unsigned { + OK, FAILED, INVALIDED }; + + Auth_result _auth_result(char const *msg) + { + enum { REASON_OFFSET = 55, }; + unsigned reason = 0; + ascii_to((msg + REASON_OFFSET), reason); + switch (reason) { + case 2: /* prev auth no longer valid */ + return Auth_result::INVALIDED; + case 15: /* 4-way handshake timeout/failed */ + return Auth_result::FAILED; + default: + return Auth_result::OK; + } + } + + struct Join_state + { + enum class State : unsigned { + DISCONNECTED, CONNECTING, CONNECTED }; + + Accesspoint ap { }; + + State state { DISCONNECTED }; + + bool auth_failure { false }; + bool not_found { false }; + bool rfkilled { false }; + + enum { MAX_REAUTH_ATTEMPTS = 3 }; + unsigned reauth_attempts { 0 }; + + enum { MAX_NOT_FOUND_IGNORE_ATTEMPTS = 3 }; + unsigned ignore_not_found { 0 }; + + void print(Output &out) const + { + auto state_string = [&] (State const state) { + switch (state) { + case State::DISCONNECTED: return "disconnected"; + case State::CONNECTED: return "connected"; + case State::CONNECTING: return "connecting"; + } + return ""; + }; + Genode::print(out, state_string(state), " " + "ssid: '", ap.ssid, "' " + "bssid: ", ap.bssid, " " + "freq: ", ap.freq, " " + "quality: ", ap.quality, " " + "auth_failure: ", auth_failure, " " + "reauth_attempts: ", reauth_attempts, " " + "not_found: ", not_found, " " + "ignore_not_found: ", ignore_not_found, " " + "rfkilled: ", rfkilled); + } + + void generate_state_report_if_needed(Expanding_reporter &reporter, + Join_state const &old) + { + /* + * Explicitly check for the all changes provoked by + * actions or events. + */ + if (state == old.state + && ap.quality == old.ap.quality + && ap.ssid == old.ap.ssid + && ap.bssid == old.ap.bssid + && ap.freq == old.ap.freq) + return; + + reporter.generate([&] (Xml_generator &xml) { + xml.node("accesspoint", [&] () { + xml.attribute("ssid", ap.ssid); + xml.attribute("bssid", ap.bssid); + xml.attribute("freq", ap.freq); + + if (state == Join_state::State::CONNECTED) + xml.attribute("state", "connected"); + else + + if (state == Join_state::State::DISCONNECTED) { + xml.attribute("state", "disconnected"); + xml.attribute("rfkilled", rfkilled); + xml.attribute("auth_failure", auth_failure); + xml.attribute("not_found", not_found); + } else + + if (state == Join_state::State::CONNECTING) + xml.attribute("state", "connecting"); + + /* + * Only add the attribute when we have something + * to report so that a consumer of the state report + * may take appropriate actions. + */ + if (ap.quality) + xml.attribute("quality", ap.quality); + }); + }); + } + }; + + Join_state _join { }; + + bool _single_network() const + { + unsigned count = 0; + _network_list.for_each([&] (Network const &network) { + network.with_accesspoint([&] (Accesspoint const &ap) { + ++count; }); }); + return count == 1; + } + + void _handle_events() + { + Join_state const old_join = _join; + + _msg.with_new_event([&] (char const *msg) { + + /* + * CTRL-EVENT-SCAN-RESULTS + */ + if (results_available(msg)) { + + /* + * We might have to pull the socketcall task out of poll_all() + * because otherwise we might be late and wpa_supplicant has + * already removed all scan results due to BSS age settings. + */ + wifi_kick_socketcall(); + + _queue_action(*new (_actions_alloc) + Scan_results_cmd(_msg, *_ap_reporter), _config.verbose); + } else + + /* + * SME: Trying to authenticate with ... + */ + if (connecting_to_network(msg)) { + + _join.state = Join_state::State::CONNECTING; + _join.ap = Accesspoint(_extract_bssid(msg, Bssid_offset::CONNECTING), + _extract_ssid(msg)); + _join.auth_failure = false; + _join.not_found = false; + } else + + /* + * CTRL-EVENT-NETWORK-NOT-FOUND + */ + if (network_not_found(msg)) { + + /* + * In case there is only one auto-connect network configured + * generate a disconnect event so that a management component + * can deal with that situation. However, we do not disable the + * network to allow for automatically rejoining a reapparing + * network that was previously not found. + * + * This may happen when an accesspoint is power-cycled or when + * there is a key management mismatch due to operator error. + * Unfortunately we cannot easily distinguish a wrongly prepared + * where the 'protection' attribute does not match + * as we do not have the available accesspoints at hand to compare + * that. + */ + if ((_join.state == Join_state::State::CONNECTING) && _single_network()) { + + /* + * Ignore the event for a while as it may happen that hidden + * networks may take some time. + */ + if (++_join.ignore_not_found >= Join_state::MAX_NOT_FOUND_IGNORE_ATTEMPTS) { + _join.ignore_not_found = 0; + + _network_list.for_each([&] (Network &network) { + network.with_accesspoint([&] (Accesspoint &ap) { + + if (ap.ssid != _join.ap.ssid) + return; + + _join.state = Join_state::State::DISCONNECTED; + _join.ap = Accesspoint(); + _join.not_found = true; + }); + }); + } + } + } else + + /* + * CTRL-EVENT-DISCONNECTED ... reason=... + */ + if (disconnected_from_network(msg)) { + + Join_state::State const old_state = _join.state; + + Auth_result const auth_result = _auth_result(msg); + + _join.auth_failure = auth_result != Auth_result::OK; + _join.state = Join_state::State::DISCONNECTED; + _join.not_found = false; + + Accesspoint::Bssid const bssid = + _extract_bssid(msg, Bssid_offset::DISCONNECT); + + if (bssid != _join.ap.bssid) + warning(bssid, " does not match stored ", _join.ap.bssid); + + /* + * Use a simplistic heuristic to ignore re-authentication requests + * and hope for the supplicant to do its magic. + */ + if ((old_state == Join_state::State::CONNECTED) && _join.auth_failure) + if (++_join.reauth_attempts <= Join_state::MAX_REAUTH_ATTEMPTS) { + log("ignore deauth from: ", bssid); + return; + } + _join.reauth_attempts = 0; + + _network_list.for_each([&] (Network &network) { + network.with_accesspoint([&] (Accesspoint &ap) { + + if (ap.ssid != _join.ap.ssid) + return; + + if (!_join.auth_failure) + return; + + /* + * Prevent the supplicant from trying to join the network + * again. At this point intervention by the management + * component is needed. + */ + + _queue_action(*new (_actions_alloc) + Update_network_cmd(_msg, ap, + Update_network_cmd::Op::DISABLE_ONLY), + _config.verbose); + }); + }); + } else + + /* + * CTRL-EVENT-CONNECTED - Connection to ... + */ + if (connected_to_network(msg)) { + + _join.state = Join_state::State::CONNECTED; + _join.ap.bssid = _extract_bssid(msg, Bssid_offset::CONNECT); + _join.auth_failure = false; + _join.not_found = false; + _join.reauth_attempts = 0; + + /* collect further information like frequency and so on */ + _queue_action(*new (_actions_alloc) Status_query(_msg), + _config.verbose); + + _arm_poll_timer(); + } + }); + + _notify_blockade.wakeup(); + + _join.generate_state_report_if_needed(*_state_reporter, old_join); + + _dispatch_action_if_needed(); + } + + /* + * CTRL interface command handling + */ + + void _handle_cmds() + { + Join_state const old_join = _join; + + _msg.with_new_reply([&] (char const *msg) { + + _with_pending_action([&] (Action &action) { + + /* + * Check response first as we ended up here due + * to an already submitted cmd. + */ + switch (action.type) { + + case Action::Type::COMMAND: + action.check(msg); + break; + + case Action::Type::QUERY: + action.response(msg, _join.ap); + break; + } + + /* + * We always switch to the next state after checking and + * handling the response from the CTRL interface. + */ + action.execute(); + + if (!action.complete()) + return Pending_action_result::INCOMPLETE; + + switch (action.command) { + case Action::Command::ADD: + { + Add_network_cmd const &add_cmd = + *dynamic_cast(&action); + + bool handled = false; + Accesspoint const &added_ap = add_cmd.accesspoint(); + _network_list.for_each([&] (Network &network) { + network.with_accesspoint([&] (Accesspoint &ap) { + if (ap.ssid != added_ap.ssid) + return; + + if (ap.stored()) { + error("accesspoint for SSID '", ap.ssid, "' " + "already stored ", ap.id); + return; + } + + ap.id = added_ap.id; + handled = true; + }); + }); + + /* + * We have to guard against having the accesspoint removed via a config + * update while we are still adding it to the supplicant by removing the + * + * network directly afterwards. + */ + if (!handled) { + _queue_action(*new (_actions_alloc) + Remove_network_cmd(_msg, added_ap.id), _config.verbose); + } else + + if (handled && _single_network()) + /* + * To accomodate a management component that only deals + * with one network, e.g. the sculpt_manager, generate a + * fake connecting event. Either a connected or disconnected + * event will bring us to square one. + */ + if ((_join.state != Join_state::State::CONNECTED) && !_join.rfkilled) { + _network_list.for_each([&] (Network const &network) { + network.with_accesspoint([&] (Accesspoint const &ap) { + + _join.ap = ap; + _join.state = Join_state::State::CONNECTING; + }); + }); + } + + break; + } + default: /* ignore the rest */ + break; + } + + return Pending_action_result::COMPLETE; + }); + }); + + _notify_blockade.wakeup(); + + _join.generate_state_report_if_needed(*_state_reporter, old_join); + + _dispatch_action_if_needed(); + } + + /** + * Constructor + */ + Manager(Env &env) + : + _network_allocator(env.ram(), env.rm()), + _explicit_scan_allocator(env.ram(), env.rm()), + _actions_alloc(env.ram(), env.rm()), + _cmd_handler(env.ep(), *this, &Wifi::Manager::_handle_cmds), + _events_handler(env.ep(), *this, &Wifi::Manager::_handle_events), + _rfkill_handler(env.ep(), *this, &Wifi::Manager::_handle_rfkill), + _config_rom(env, "wifi_config"), + _config_sigh(env.ep(), *this, &Wifi::Manager::_handle_config_update), + _timer(env) + { + _config_rom.sigh(_config_sigh); + + /* set/initialize as unblocked */ + _notify_blockade.wakeup(); + + /* + * Both Report sessions are mandatory, let the driver fail in + * case they cannot be created. + */ + { + _ap_reporter.construct(env, "accesspoints", "accesspoints"); + _ap_reporter->generate([&] (Genode::Xml_generator &) { }); + } + + { + _state_reporter.construct(env, "state", "state"); + _state_reporter->generate([&] (Genode::Xml_generator &xml) { + xml.node("accesspoint", [&] () { + xml.attribute("state", "disconnected"); + }); + }); + } + + /* read in list of APs */ + _config_update(true); + + /* get initial RFKILL state */ + _handle_rfkill(); + + /* kick-off initial scanning */ + _handle_scan_timeout(Duration(Microseconds(0))); + } + + /** + * Trigger RFKILL notification + * + * Used by the wifi driver to notify the manager. + */ + void rfkill_notify() override { + _rfkill_handler.local_submit(); } + + /** + * Return message buffer + * + * Used for communication with the CTRL interface + */ + Msg_buffer &msg_buffer() { return _msg; } +}; + +#endif /* _WIFI_MANAGER_H_ */ diff --git a/repos/dde_linux/src/driver/wifi/util.h b/repos/dde_linux/src/driver/wifi/util.h index 0db3931afc..2285fd12fa 100644 --- a/repos/dde_linux/src/driver/wifi/util.h +++ b/repos/dde_linux/src/driver/wifi/util.h @@ -1,5 +1,5 @@ /* - * \brief Wifi front end utilities + * \brief Wifi manager utilities * \author Josef Soentgen * \date 2018-07-23 */ @@ -59,9 +59,9 @@ namespace Util { } } - /********************************** - ** Front end specific utilities ** - **********************************/ + /******************************** + ** Manager-specific utilities ** + ********************************/ inline unsigned approximate_quality(char const *str) { diff --git a/repos/dde_linux/src/include/lx_emul/nic.h b/repos/dde_linux/src/include/lx_emul/nic.h new file mode 100644 index 0000000000..307b2835ee --- /dev/null +++ b/repos/dde_linux/src/include/lx_emul/nic.h @@ -0,0 +1,31 @@ +/* + * \brief Lx_emul support for NICs + * \author Stefan Kalkowski + * \date 2024-10-15 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef _LX_EMUL__NIC_H_ +#define _LX_EMUL__NIC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +extern void lx_emul_nic_init(void); +extern void lx_emul_nic_handle_io(void); +extern void lx_emul_nic_set_mac_address(const unsigned char *mac, + unsigned long size); + +#ifdef __cplusplus +} +#endif + +#endif /* _LX_EMUL__USB_H_ */ + diff --git a/repos/dde_linux/src/include/lx_emul/shmem_file.h b/repos/dde_linux/src/include/lx_emul/shmem_file.h index fcced61a15..ec81ecb0e0 100644 --- a/repos/dde_linux/src/include/lx_emul/shmem_file.h +++ b/repos/dde_linux/src/include/lx_emul/shmem_file.h @@ -91,8 +91,15 @@ err_inode: } +#if LINUX_VERSION_CODE < KERNEL_VERSION(6,4,0) +#define folio_cast struct page *shmem_read_mapping_page_gfp(struct address_space *mapping, pgoff_t index, gfp_t gfp) +#else +#define folio_cast (struct folio *) +struct folio *shmem_read_folio_gfp(struct address_space *mapping, + pgoff_t index, gfp_t gfp) +#endif { struct page *p; struct shmem_file_buffer *private_data; @@ -103,17 +110,27 @@ struct page *shmem_read_mapping_page_gfp(struct address_space *mapping, private_data = mapping->private_data; p = private_data->pages; - return (p + index); + return folio_cast(p + index); } #include +#if LINUX_VERSION_CODE < KERNEL_VERSION(6,4,0) void __pagevec_release(struct pagevec * pvec) { /* XXX check if we have to call release_pages */ pagevec_reinit(pvec); } +#else +void __folio_batch_release(struct folio_batch *fbatch) +{ + lx_emul_trace(__func__); + + /* XXX check if we have to call release_pages */ + folio_batch_reinit(fbatch); +} +#endif #include diff --git a/repos/dde_linux/src/include/lx_kit/device.h b/repos/dde_linux/src/include/lx_kit/device.h index d54dcea977..affb640dd4 100644 --- a/repos/dde_linux/src/include/lx_kit/device.h +++ b/repos/dde_linux/src/include/lx_kit/device.h @@ -142,6 +142,16 @@ class Lx_kit::Device : List::Element void _for_each_clock(FN const & fn) { for (Clock * c = _clocks.first(); c; c = c->next()) fn(*c); } + protected: + + Device(Platform::Connection &plat, + Name name) + : + _platform(plat), _name(name), _type("") + { } + + virtual ~Device() { } + public: const char * compatible(); @@ -171,7 +181,8 @@ class Lx_kit::Device : List::Element bool irq_unmask(unsigned irq); void irq_mask(unsigned irq); void irq_ack(unsigned irq); - int pending_irq(); + + virtual int pending_irq(); bool read_config(unsigned reg, unsigned len, unsigned *val); bool write_config(unsigned reg, unsigned len, unsigned val); @@ -210,6 +221,8 @@ class Lx_kit::Device_list : List Device_list(Entrypoint & ep, Heap & heap, Platform::Connection & platform); + + void insert(Device const *device) { List::insert(device); } }; #endif /* _LX_KIT__DEVICE_H_ */ diff --git a/repos/dde_linux/src/lib/libnl/include/linux/types.h b/repos/dde_linux/src/lib/libnl/include/linux/types.h index ceeaa161de..205a9cea66 100644 --- a/repos/dde_linux/src/lib/libnl/include/linux/types.h +++ b/repos/dde_linux/src/lib/libnl/include/linux/types.h @@ -1,16 +1,16 @@ #ifndef _LINUX_TYPES_H #define _LINUX_TYPES_H -#include +#include -typedef signed char __s8; -typedef unsigned char __u8; -typedef signed short __s16; -typedef unsigned short __u16; -typedef signed int __s32; -typedef unsigned int __u32; -typedef int64_t __s64; -typedef uint64_t __u64; +typedef genode_int8_t __s8; +typedef genode_uint8_t __u8; +typedef genode_int16_t __s16; +typedef genode_uint16_t __u16; +typedef genode_int32_t __s32; +typedef genode_uint32_t __u32; +typedef genode_int64_t __s64; +typedef genode_uint64_t __u64; typedef __u16 __be16; typedef __u32 __be32; diff --git a/repos/dde_linux/src/lib/libnl/include/spec/32bit/platform/types.h b/repos/dde_linux/src/lib/libnl/include/spec/32bit/platform/types.h deleted file mode 100644 index a1a46aba16..0000000000 --- a/repos/dde_linux/src/lib/libnl/include/spec/32bit/platform/types.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * \brief Emulation of the Linux userland API - * \author Josef Soentgen - * \date 2014-07-25 - * - * The content of this file, in particular data structures, is partially - * derived from Linux headers. - */ - -/* - * Copyright (C) 2014-2017 Genode Labs GmbH - * - * This file is distributed under the terms of the GNU General Public License - * version 2. - */ - -#ifndef _32BIT__PLATFORM__TYPES_H_ -#define _32BIT__PLATFORM__TYPES_H_ - - -typedef long long int64_t; -typedef unsigned long long uint64_t; - -#endif /* _32BIT__PLATFORM__TYPES_H_ */ diff --git a/repos/dde_linux/src/lib/libnl/include/spec/64bit/platform/types.h b/repos/dde_linux/src/lib/libnl/include/spec/64bit/platform/types.h deleted file mode 100644 index fa956526cb..0000000000 --- a/repos/dde_linux/src/lib/libnl/include/spec/64bit/platform/types.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * \brief Emulation of the Linux userland API - * \author Josef Soentgen - * \date 2014-07-25 - * - * The content of this file, in particular data structures, is partially - * derived from Linux headers. - */ - -/* - * Copyright (C) 2014-2017 Genode Labs GmbH - * - * This file is distributed under the terms of the GNU General Public License - * version 2. - */ - -#ifndef _64BIT__PLATFORM__TYPES_H_ -#define _64BIT__PLATFORM__TYPES_H_ - - -typedef long int64_t; -typedef unsigned long uint64_t; - -#endif /* _64BIT__PLATFORM__TYPES_H_ */ diff --git a/repos/dde_linux/src/lib/lx_emul/nic.c b/repos/dde_linux/src/lib/lx_emul/nic.c new file mode 100644 index 0000000000..2f5d702c32 --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/nic.c @@ -0,0 +1,258 @@ +/* + * \brief PC Ethernet driver + * \author Norman Feske + * \author Christian Helmuth + * \author Stefan Kalkowski + * \date 2024-10-15 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include +#include +#include +#include + + +static struct genode_uplink *dev_genode_uplink(struct net_device *dev) +{ + return (struct genode_uplink *)dev->ifalias; +} + + +struct genode_uplink_rx_context +{ + struct net_device *dev; +}; + + +struct genode_uplink_tx_packet_context +{ + struct sk_buff *skb; +}; + + +static unsigned long uplink_tx_packet_content(struct genode_uplink_tx_packet_context *ctx, + char *dst, unsigned long dst_len) +{ + struct sk_buff * const skb = ctx->skb; + + skb_push(skb, ETH_HLEN); + + if (dst_len < skb->len) { + printk("uplink_tx_packet_content: packet exceeds uplink packet size\n"); + memset(dst, 0, dst_len); + return 0; + } + + skb_copy_from_linear_data(skb, dst, skb->len); + + /* clear unused part of the destination buffer */ + memset(dst + skb->len, 0, dst_len - skb->len); + + return skb->len; +} + + +static rx_handler_result_t handle_rx(struct sk_buff **pskb) +{ + struct sk_buff *skb = *pskb; + struct net_device *dev = skb->dev; + struct genode_uplink_tx_packet_context ctx = { .skb = skb }; + struct genode_uplink *uplink = dev_genode_uplink(dev); + + if (!uplink) + return RX_HANDLER_PASS; + + { + bool progress = genode_uplink_tx_packet(uplink, + uplink_tx_packet_content, + &ctx); + if (!progress) + printk("handle_rx: uplink saturated, dropping packet\n"); + } + + kfree_skb(skb); + return RX_HANDLER_CONSUMED; +} + + +/** + * Create Genode uplink for given net device + * + * The uplink is registered at the dev->ifalias pointer. + */ +static void handle_create_uplink(struct net_device *dev) +{ + struct genode_uplink_args args; + + if (dev_genode_uplink(dev)) + return; + + if (!netif_carrier_ok(dev)) + return; + + printk("create uplink for net device %s\n", &dev->name[0]); + + memset(&args, 0, sizeof(args)); + + if (dev->addr_len != sizeof(args.mac_address)) { + printk("error: net device has unexpected addr_len %u\n", dev->addr_len); + return; + } + + { + unsigned i; + for (i = 0; i < dev->addr_len; i++) + args.mac_address[i] = dev->dev_addr[i]; + } + + args.label = &dev->name[0]; + + dev->ifalias = (struct dev_ifalias *)genode_uplink_create(&args); +} + + +static void handle_destroy_uplink(struct net_device *dev) +{ + struct genode_uplink *uplink = dev_genode_uplink(dev); + + if (!uplink) + return; + + if (netif_carrier_ok(dev)) + return; + + genode_uplink_destroy(uplink); + + dev->ifalias = NULL; +} + + +static genode_uplink_rx_result_t uplink_rx_one_packet(struct genode_uplink_rx_context *ctx, + char const *ptr, unsigned long len) +{ + struct sk_buff *skb = alloc_skb(len, GFP_KERNEL); + + if (!skb) { + printk("alloc_skb failed\n"); + return GENODE_UPLINK_RX_RETRY; + } + + skb_copy_to_linear_data(skb, ptr, len); + skb_put(skb, len); + skb->dev = ctx->dev; + + if (dev_queue_xmit(skb) < 0) { + printk("lx_user: failed to xmit packet\n"); + return GENODE_UPLINK_RX_REJECTED; + } + + return GENODE_UPLINK_RX_ACCEPTED; +} + + +/* + * custom MAC address + */ +static unsigned char mac_address[6]; +static bool mac_address_configured = false; + +static void handle_mac_address(struct net_device *dev) +{ + int err; + struct sockaddr addr; + struct genode_mac_address dev_addr; + + if (mac_address_configured || !netif_device_present(dev)) return; + + if (mac_address[0] || mac_address[1] || mac_address[2] || + mac_address[3] || mac_address[4] || mac_address[5]) { + memcpy(&addr.sa_data, mac_address, ETH_ALEN); + addr.sa_family = dev->type; + err = dev_set_mac_address(dev, &addr, NULL); + if (err < 0) + printk("Warning: Could not set configured MAC address: %pM (err=%d)\n", + mac_address, err); + } + + memcpy(dev_addr.addr, dev->dev_addr, sizeof(dev_addr)); + genode_mac_address_register(dev->name, dev_addr); + + mac_address_configured =true; +} + + +static int nic_task_function(void *arg) +{ + for (;;) { + + struct net_device *dev; + + for_each_netdev(&init_net, dev) { + + handle_mac_address(dev); + + /* enable link sensing, repeated calls are handled by testing IFF_UP */ + dev_open(dev, 0); + + /* install rx handler once */ + if (!netdev_is_rx_handler_busy(dev)) + netdev_rx_handler_register(dev, handle_rx, NULL); + + /* respond to cable plug/unplug */ + handle_create_uplink(dev); + handle_destroy_uplink(dev); + + /* transmit packets received from the uplink session */ + if (netif_carrier_ok(dev)) { + + struct genode_uplink_rx_context ctx = { .dev = dev }; + + while (genode_uplink_rx(dev_genode_uplink(dev), + uplink_rx_one_packet, + &ctx)); + } + }; + + /* block until lx_emul_task_unblock */ + lx_emul_task_schedule(true); + } + return 0; +} + + +static struct task_struct *nic_task_struct_ptr; + + +void lx_emul_nic_init(void) +{ + pid_t pid; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,3,0) + pid = kernel_thread(nic_task_function, NULL, "user_task", CLONE_FS | CLONE_FILES); +#else + pid = kernel_thread(nic_task_function, NULL, CLONE_FS | CLONE_FILES); +#endif + + nic_task_struct_ptr = find_task_by_pid_ns(pid, NULL); +} + + +void lx_emul_nic_handle_io(void) +{ + if (nic_task_struct_ptr) lx_emul_task_unblock(nic_task_struct_ptr); +} + + +void lx_emul_nic_set_mac_address(const unsigned char *mac, unsigned long size) +{ + memcpy(mac_address, mac, min(sizeof(mac_address), size)); + mac_address_configured = false; +} diff --git a/repos/dde_linux/src/lib/lx_emul/pin.cc b/repos/dde_linux/src/lib/lx_emul/pin.cc index 2b477d3b4a..0cb9796a2c 100644 --- a/repos/dde_linux/src/lib/lx_emul/pin.cc +++ b/repos/dde_linux/src/lib/lx_emul/pin.cc @@ -24,19 +24,25 @@ namespace { using namespace Genode; - class Global_irq_controller : Noncopyable + class Global_irq_controller : Lx_kit::Device, Noncopyable { private: Lx_kit::Env &_env; - unsigned _pending_irq = 0; + int _pending_irq { -1 }; public: struct Number { unsigned value; }; - Global_irq_controller(Lx_kit::Env &env) : _env(env) { } + Global_irq_controller(Lx_kit::Env &env) + : + Lx_kit::Device(env.platform, "pin_irq"), + _env(env) + { + _env.devices.insert(this); + } void trigger_irq(Number number) { @@ -45,6 +51,14 @@ namespace { _env.scheduler.unblock_irq_handler(); _env.scheduler.schedule(); } + + int pending_irq() override + { + int irq = _pending_irq; + _pending_irq = -1; + + return irq; + } }; using Pin_name = Session_label; diff --git a/repos/dde_linux/src/lib/lx_emul/start.c b/repos/dde_linux/src/lib/lx_emul/start.c index e64b6732f0..aad3ba6a19 100644 --- a/repos/dde_linux/src/lib/lx_emul/start.c +++ b/repos/dde_linux/src/lib/lx_emul/start.c @@ -132,8 +132,6 @@ int lx_emul_init_task_function(void * dtb) * Here we do the minimum normally done start_kernel() of init/main.c */ - lx_emul_setup_arch(dtb); - jump_label_init(); kmem_cache_init(); wait_bit_init(); @@ -143,6 +141,12 @@ int lx_emul_init_task_function(void * dtb) maple_tree_init(); #endif + /* + * unflatten_device tree requires memblock, so kmem_cache_init has to be + * called before lx_emul_setup_arch on ARM platforms + */ + lx_emul_setup_arch(dtb); + workqueue_init_early(); skb_init(); diff --git a/repos/dde_linux/src/lib/lx_emul/usb.c b/repos/dde_linux/src/lib/lx_emul/usb.c index a91d6e8188..e7ddb74e24 100644 --- a/repos/dde_linux/src/lib/lx_emul/usb.c +++ b/repos/dde_linux/src/lib/lx_emul/usb.c @@ -129,7 +129,12 @@ static void release_device(struct usb_per_dev_data * data) usb_driver_release_interface(&usb_drv, iface); } } + + if (usb_lock_device_for_reset(data->dev, NULL)) + return; + usb_reset_device(data->dev); + usb_unlock_device(data->dev); } diff --git a/repos/dde_linux/src/lib/wifi/lx_emul.c b/repos/dde_linux/src/lib/wifi/lx_emul.c index a8c0712862..05e3d1f58b 100644 --- a/repos/dde_linux/src/lib/wifi/lx_emul.c +++ b/repos/dde_linux/src/lib/wifi/lx_emul.c @@ -179,7 +179,7 @@ int request_firmware_common(const struct firmware **firmware_p, { struct firmware *fw; - if (!*firmware_p) + if (!firmware_p) return -1; fw = kzalloc(sizeof(struct firmware), GFP_KERNEL); @@ -460,10 +460,10 @@ static int rfkill_task_function(void *arg) bool rfkilled = !!rfkill_get_global_sw_state(RFKILL_TYPE_WLAN); - if (rfkilled != _rfkill_state.blocked) + if (rfkilled != _rfkill_state.blocked) { rfkill_switch_all(RFKILL_TYPE_WLAN, !!_rfkill_state.blocked); - - _rfkill_state.rfkilled = rfkilled; + _rfkill_state.rfkilled = !!_rfkill_state.blocked; + } lx_emul_task_schedule(true); } diff --git a/repos/dde_linux/src/lib/wifi/socket_call.cc b/repos/dde_linux/src/lib/wifi/socket_call.cc index a21ca8582d..a646e724f9 100644 --- a/repos/dde_linux/src/lib/wifi/socket_call.cc +++ b/repos/dde_linux/src/lib/wifi/socket_call.cc @@ -54,7 +54,7 @@ enum : int { }; -static int convert_errno_from_linux(int linux_errno) +extern "C" int convert_errno_from_linux(int linux_errno) { if (linux_errno >= 0) return linux_errno; @@ -100,9 +100,7 @@ static int convert_errno_from_linux(int linux_errno) case ENODEV: return -(int)Libc::Errno::BSD_ENODEV; case ENOENT: return -(int)Libc::Errno::BSD_ENOENT; case ENOEXEC: return -(int)Libc::Errno::BSD_ENOEXEC; - case ENOLINK: - error("ENOLINK (", (int) ENOLINK, ") -> ", (int)Libc::Errno::BSD_ENOLINK); - return -(int)Libc::Errno::BSD_ENOLINK; + case ENOLINK: return -(int)Libc::Errno::BSD_ENOLINK; case ENOMEM: return -(int)Libc::Errno::BSD_ENOMEM; case ENOMSG: return -(int)Libc::Errno::BSD_ENOMSG; case ENOPROTOOPT: return -(int)Libc::Errno::BSD_ENOPROTOOPT; diff --git a/repos/dde_linux/src/lib/wifi/symbol.map b/repos/dde_linux/src/lib/wifi/symbol.map index b2f8892648..9d6e7cb346 100644 --- a/repos/dde_linux/src/lib/wifi/symbol.map +++ b/repos/dde_linux/src/lib/wifi/symbol.map @@ -18,6 +18,7 @@ /* interface for libnl/wpa_driver_nl82011 */ wifi_if*; + convert_errno_from_linux; local: diff --git a/repos/dde_linux/src/lib/wifi/wlan.cc b/repos/dde_linux/src/lib/wifi/wlan.cc index 518c3648ba..c7d44eb7eb 100644 --- a/repos/dde_linux/src/lib/wifi/wlan.cc +++ b/repos/dde_linux/src/lib/wifi/wlan.cc @@ -342,7 +342,11 @@ void Wifi::set_rfkill(bool blocked) */ lx_emul_task_unblock(uplink_task_struct_ptr); Lx_kit::env().scheduler.execute(); +} + +void Wifi::rfkill_notify() +{ if (_wlan_ptr->rfkill_helper.constructed()) _wlan_ptr->rfkill_helper->submit_notification(); } diff --git a/repos/dde_linux/src/lib/wpa_driver_nl80211/rfkill_genode.cc b/repos/dde_linux/src/lib/wpa_driver_nl80211/rfkill_genode.cc index c7749c9df4..b85106b9b4 100644 --- a/repos/dde_linux/src/lib/wpa_driver_nl80211/rfkill_genode.cc +++ b/repos/dde_linux/src/lib/wpa_driver_nl80211/rfkill_genode.cc @@ -54,6 +54,8 @@ static void rfkill_receive(int sock, void *eloop_ctx, void *sock_ctx) } else { rfkill->cfg->unblocked_cb(rfkill->cfg->ctx); } + + Wifi::rfkill_notify(); } } diff --git a/repos/dde_linux/src/lib/wpa_supplicant/ctrl_iface_genode.c b/repos/dde_linux/src/lib/wpa_supplicant/ctrl_iface_genode.c deleted file mode 100644 index fc5d359665..0000000000 --- a/repos/dde_linux/src/lib/wpa_supplicant/ctrl_iface_genode.c +++ /dev/null @@ -1,250 +0,0 @@ -/* - * \brief WPA Supplicant frontend - * \author Josef Soentgen - * \date 2018-07-18 - */ - -/* - * Copyright (C) 2018 Genode Labs GmbH - * - * This file is distributed under the terms of the GNU General Public License - * version 2. - */ - -/* - * based on: - * - * WPA Supplicant / UNIX domain socket -based control interface - * Copyright (c) 2004-2014, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -/* wpa_supplicant includes */ -#include "includes.h" -#include "utils/common.h" -#include "utils/eloop.h" -#include "utils/list.h" -#include "common/ctrl_iface_common.h" -#include "eapol_supp/eapol_supp_sm.h" -#include "config.h" -#include "wpa_supplicant_i.h" -#include "ctrl_iface.h" - -/* rep includes */ -#include - -typedef unsigned unaligned_unsigned __attribute__ ((aligned (1))); - -struct ctrl_iface_priv { - struct wpa_supplicant *wpa_s; - int fd; - int level; - - /* TODO replace w/ Msg_buffer */ - char *send_buffer; - size_t send_buffer_size; - unaligned_unsigned *send_id; - - char *recv_buffer; - size_t recv_buffer_size; - unaligned_unsigned *recv_id; - - unsigned last_recv_id; - - char *event_buffer; - size_t event_buffer_size; - unaligned_unsigned *event_id; -}; - - -struct ctrl_iface_global_priv { - struct wpa_global *global; -}; - - -extern void nl_set_wpa_ctrl_fd(void); - - -void wpa_ctrl_set_fd() -{ - nl_set_wpa_ctrl_fd(); -} - - -static void send_reply(struct ctrl_iface_priv *priv, char const *txt, size_t len) -{ - char *msg = priv->send_buffer; - size_t mlen = priv->send_buffer_size; - - if (len >= mlen) { - len = mlen - 1; - } - - memcpy(msg, txt, len); - msg[len] = 0; - (*priv->send_id)++; -} - - -/* - * This function is called by wpa_supplicant whenever it receives a - * command via the CTRL interface, i.e. the front end has sent a new - * message. - */ -static void wpa_supplicant_ctrl_iface_receive(int fd, void *eloop_ctx, - void *sock_ctx) -{ - struct wpa_supplicant *wpa_s = eloop_ctx; - struct ctrl_iface_priv *priv = sock_ctx; - - char *msg = priv->recv_buffer; - - unsigned const recv_id = *priv->recv_id; - - char *reply = NULL; - size_t reply_len = 0; - - if (msg[0] == 0 || recv_id == priv->last_recv_id) { return; } - - priv->last_recv_id = recv_id; - - reply = wpa_supplicant_ctrl_iface_process(wpa_s, msg, - &reply_len); - - if (reply) { - wifi_block_for_processing(); - send_reply(priv, reply, reply_len); - wifi_notify_cmd_result(); - os_free(reply); - } else - - if (reply_len == 1) { - wifi_block_for_processing(); - send_reply(priv, "FAIL", 4); - wifi_notify_cmd_result(); - } else - - if (reply_len == 2) { - wifi_block_for_processing(); - send_reply(priv, "OK", 2); - wifi_notify_cmd_result(); - } -} - - -static void send_event(struct ctrl_iface_priv *priv, char const *txt, size_t len) -{ - char *msg = priv->event_buffer; - size_t mlen = priv->event_buffer_size; - - if (len >= mlen) { - len = mlen - 1; - } - - memcpy(msg, txt, len); - msg[len] = 0; - (*priv->event_id)++; -} - - -/* - * This function is called by wpa_supplicant whenever it wants to - * forward some message. We filter these messages and forward only - * those, which are of interest to the front end. - */ -static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, - enum wpa_msg_type type, - const char *txt, size_t len) -{ - /* there is not global support */ - if (type == WPA_MSG_ONLY_GLOBAL) { return; } - - struct wpa_supplicant *wpa_s = ctx; - if (wpa_s == NULL) { return; } - - struct ctrl_iface_priv *priv = wpa_s->ctrl_iface; - if (!priv || level < priv->level) { return; } - - /* - * Filter messages and only forward events the front end cares - * about or rather knows how to handle. - */ - int const forward = - strncmp(txt, "CTRL-EVENT-SCAN-RESULTS", 23) == 0 - || strncmp(txt, "CTRL-EVENT-CONNECTED", 20) == 0 - || strncmp(txt, "CTRL-EVENT-DISCONNECTED", 23) == 0 - || strncmp(txt, "CTRL-EVENT-NETWORK-NOT-FOUND", 28) == 0 - /* needed to detect connecting state */ - || strncmp(txt, "SME: Trying to authenticate", 27) == 0 - ; - if (!forward) { return; } - - wifi_notify_event(); - send_event(priv, txt, len); -} - - -struct ctrl_iface_priv * -wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) -{ - struct ctrl_iface_priv *priv; - - priv = os_zalloc(sizeof(*priv)); - if (priv == NULL) { return NULL; } - - if (wpa_s->conf->ctrl_interface == NULL) { - return priv; - } - - struct Msg_buffer *msg_buffer = (struct Msg_buffer*)wifi_get_buffer(); - priv->recv_buffer = (char *)msg_buffer->send; - priv->recv_buffer_size = sizeof(msg_buffer->send); - priv->send_buffer = (char *)msg_buffer->recv; - priv->send_buffer_size = sizeof(msg_buffer->recv); - priv->send_id = &msg_buffer->recv_id; - priv->recv_id = &msg_buffer->send_id; - - priv->event_buffer = (char *)msg_buffer->event; - priv->event_buffer_size = sizeof(msg_buffer->event); - priv->event_id = &msg_buffer->event_id; - - priv->level = MSG_INFO; - priv->fd = WPA_CTRL_FD; - - eloop_register_read_sock(priv->fd, - wpa_supplicant_ctrl_iface_receive, - wpa_s, priv); - - wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); - return priv; -} - - -void wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s, - struct ctrl_iface_priv *priv) -{ - (void)wpa_s; - - os_free(priv); -} - - -void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv) { } - - -struct ctrl_iface_global_priv * -wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) -{ - struct ctrl_iface_global_priv *priv; - - priv = os_zalloc(sizeof(*priv)); - return priv; -} - - -void wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *p) -{ - os_free(p); -} diff --git a/repos/dde_linux/src/lib/wpa_supplicant/ctrl_iface_genode.cc b/repos/dde_linux/src/lib/wpa_supplicant/ctrl_iface_genode.cc new file mode 100644 index 0000000000..9dfac61e1d --- /dev/null +++ b/repos/dde_linux/src/lib/wpa_supplicant/ctrl_iface_genode.cc @@ -0,0 +1,240 @@ +/* + * \brief Genode-specific WPA supplicant ctrl_iface + * \author Josef Soentgen + * \date 2018-07-18 + */ + +/* + * Copyright (C) 2018 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +/* + * based on: + * + * WPA Supplicant / UNIX domain socket -based control interface + * Copyright (c) 2004-2014, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +/* wpa_supplicant includes */ +extern "C" { +#include "includes.h" +#include "utils/common.h" +#include "utils/eloop.h" +#include "utils/list.h" +#include "common/ctrl_iface_common.h" +#include "eapol_supp/eapol_supp_sm.h" +#include "config.h" +#include "wpa_supplicant_i.h" +#include "ctrl_iface.h" +} + +/* rep includes */ +#include + + +static Wifi::Msg_buffer *_msg_buffer; + + +void Wifi::ctrl_init(Msg_buffer &buffer) +{ + _msg_buffer = &buffer; +} + + +struct ctrl_iface_priv { + struct wpa_supplicant *wpa_s; + int fd; + int level; + + Wifi::Msg_buffer *buffer; + unsigned last_send_id; +}; + + +struct ctrl_iface_global_priv { + struct wpa_global *global; +}; + + +extern "C" +void nl_set_wpa_ctrl_fd(void); + + +void wpa_ctrl_set_fd() +{ + nl_set_wpa_ctrl_fd(); +} + + +static void send_reply(Wifi::Msg_buffer &buffer, char const *txt, size_t len) +{ + buffer.block_for_processing(); + + /* XXX hack to trick poll() into returning faster */ + wpa_ctrl_set_fd(); + + if (len >= sizeof(buffer.recv)) + len = sizeof(buffer.recv) - 1; + + memcpy(buffer.recv, txt, len); + buffer.recv[len] = 0; + buffer.recv_id++; + + buffer.notify_response(); +} + + +/* + * This function is called by wpa_supplicant whenever it receives a + * command via the CTRL interface, i.e. the manager has sent a new + * message. + */ +static void wpa_supplicant_ctrl_iface_receive(int fd, void *eloop_ctx, + void *sock_ctx) +{ + struct wpa_supplicant *wpa_s = static_cast(eloop_ctx); + struct ctrl_iface_priv *priv = static_cast(sock_ctx); + + Wifi::Msg_buffer &buffer = *priv->buffer; + + char *reply = NULL; + size_t reply_len = 0; + + if (buffer.send[0] == 0 || buffer.send_id == priv->last_send_id) + return; + + priv->last_send_id = buffer.send_id; + + reply = wpa_supplicant_ctrl_iface_process(wpa_s, + buffer.send, + &reply_len); + + if (reply) { + send_reply(buffer, reply, reply_len); + os_free(reply); + } else + + if (reply_len == 1) { + send_reply(buffer, "FAIL", 4); + } else + + if (reply_len == 2) { + send_reply(buffer, "OK", 2); + } +} + + +static void send_event(Wifi::Msg_buffer &buffer, char const *txt, size_t len) +{ + buffer.block_for_processing(); + + /* XXX hack to trick poll() into returning faster */ + wpa_ctrl_set_fd(); + + if (len >= sizeof(buffer.event)) + len = sizeof(buffer.event) - 1; + + memcpy(buffer.event, txt, len); + buffer.event[len] = 0; + buffer.event_id++; + + buffer.notify_event(); +} + + +/* + * This function is called by wpa_supplicant whenever it wants to + * forward some message. We filter these messages and forward only + * those, which are of interest to the Wifi manager. + */ +static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, + enum wpa_msg_type type, + const char *txt, size_t len) +{ + /* there is not global support */ + if (type == WPA_MSG_ONLY_GLOBAL) + return; + + struct wpa_supplicant *wpa_s = static_cast(ctx); + if (wpa_s == NULL) + return; + + struct ctrl_iface_priv *priv = wpa_s->ctrl_iface; + if (!priv || level < priv->level) + return; + + /* + * Filter messages and only forward events the manager cares + * about or rather knows how to handle. + */ + bool const forward = + strncmp(txt, "CTRL-EVENT-SCAN-RESULTS", 23) == 0 + || strncmp(txt, "CTRL-EVENT-CONNECTED", 20) == 0 + || strncmp(txt, "CTRL-EVENT-DISCONNECTED", 23) == 0 + || strncmp(txt, "CTRL-EVENT-NETWORK-NOT-FOUND", 28) == 0 + /* needed to detect connecting state */ + || strncmp(txt, "SME: Trying to authenticate", 27) == 0; + if (!forward) + return; + + Wifi::Msg_buffer &buffer = *priv->buffer; + send_event(buffer, txt, len); +} + + +extern "C" struct ctrl_iface_priv * +wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) +{ + struct ctrl_iface_priv *priv = (ctrl_iface_priv*)os_zalloc(sizeof(*priv)); + if (priv == NULL) { return NULL; } + + if (wpa_s->conf->ctrl_interface == NULL) { + return priv; + } + + priv->buffer = _msg_buffer; + priv->level = MSG_INFO; + priv->fd = Wifi::CTRL_FD; + + eloop_register_read_sock(priv->fd, + wpa_supplicant_ctrl_iface_receive, + wpa_s, priv); + + wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); + return priv; +} + +extern "C" +void wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s, + struct ctrl_iface_priv *priv) +{ + (void)wpa_s; + + os_free(priv); +} + + +extern "C" +void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv) { } + + +extern "C" struct ctrl_iface_global_priv * +wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) +{ + struct ctrl_iface_global_priv *priv = + (ctrl_iface_global_priv*)os_zalloc(sizeof(*priv)); + return priv; +} + + +extern "C" +void wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *p) +{ + os_free(p); +} diff --git a/repos/dde_linux/src/lib/wpa_supplicant/main.c b/repos/dde_linux/src/lib/wpa_supplicant/main.c index 0a18ba610f..7bc61b7108 100644 --- a/repos/dde_linux/src/lib/wpa_supplicant/main.c +++ b/repos/dde_linux/src/lib/wpa_supplicant/main.c @@ -1,5 +1,5 @@ /* - * \brief WPA Supplicant frontend + * \brief Custom WPA Supplicant main routine * \author Josef Soentgen * \date 2014-12-08 */ @@ -45,8 +45,7 @@ int wpa_main(void) memset(¶ms, 0, sizeof(params)); - // TODO use CTRL interface for setting debug level - params.wpa_debug_level = 1 ? MSG_DEBUG : MSG_INFO; + params.wpa_debug_level = MSG_ERROR; params.ctrl_interface = "GENODE"; global = wpa_supplicant_init(¶ms); diff --git a/repos/dde_linux/src/lib/wpa_supplicant/symbol.map b/repos/dde_linux/src/lib/wpa_supplicant/symbol.map index 9110d727b2..6db93374fe 100644 --- a/repos/dde_linux/src/lib/wpa_supplicant/symbol.map +++ b/repos/dde_linux/src/lib/wpa_supplicant/symbol.map @@ -7,21 +7,27 @@ /* needed by wifi driver */ wpa_main; wpa_reporter_init; - wpa_ctrl_set_fd; + *wpa_ctrl_set_fd*; + *ctrl_init*; /* needed by wpa_driver_nl80211 */ __hide_aliasing_typecast; + channel_width_to_int; eloop_*; + fc2str*; get_hdr_bssid; + get_ie*; + get_ml_ie; ieee80211_freq_to_chan; ieee80211_radiotap_*; + ieee802_11_defrag; + ieee802_11_parse_elems; + is_6ghz_freq; + is_same_band; os_*; + sha1_vector*; wpa_*; wpabuf_*; - sha1_vector*; - get_ie*; - fc2str*; - is_6ghz_freq; local: diff --git a/repos/dde_rump/recipes/pkg/ext2_fs/hash b/repos/dde_rump/recipes/pkg/ext2_fs/hash index 8698e52120..e9296d4b5f 100644 --- a/repos/dde_rump/recipes/pkg/ext2_fs/hash +++ b/repos/dde_rump/recipes/pkg/ext2_fs/hash @@ -1 +1 @@ -2024-08-28 cd657483ba93236252970c2b67cac318ecda0f76 +2024-12-10 ac76eef4118d804b780b7580fa05d5755a21ae24 diff --git a/repos/dde_rump/recipes/src/vfs_rump/hash b/repos/dde_rump/recipes/src/vfs_rump/hash index 733ddcad1d..c9b1717fba 100644 --- a/repos/dde_rump/recipes/src/vfs_rump/hash +++ b/repos/dde_rump/recipes/src/vfs_rump/hash @@ -1 +1 @@ -2024-08-28 c1c8f14f76d62c6edeaffa136657552a557465ad +2024-12-10 55f332a8a4411482acdcfbb1fbf23011ff06744d diff --git a/repos/demo/include/launchpad/launchpad.h b/repos/demo/include/launchpad/launchpad.h index 0ab3a47f69..fb1e1a7419 100644 --- a/repos/demo/include/launchpad/launchpad.h +++ b/repos/demo/include/launchpad/launchpad.h @@ -135,8 +135,10 @@ class Launchpad_child : public Genode::Child_policy, Binary_name binary_name() const override { return _elf_name; } - Genode::Pd_session &ref_pd() override { return _env.pd(); } - Genode::Pd_session_capability ref_pd_cap() const override { return _env.pd_session_cap(); } + Genode::Ram_allocator &session_md_ram() override { return _env.pd(); } + + Genode::Pd_account &ref_account() override { return _env.pd(); } + Genode::Capability ref_account_cap() const override { return _env.pd_session_cap(); } void init(Genode::Pd_session &session, Genode::Pd_session_capability cap) override diff --git a/repos/demo/include/scout/graphics_backend_impl.h b/repos/demo/include/scout/graphics_backend_impl.h index 9f02aacb7b..c8d49b561b 100644 --- a/repos/demo/include/scout/graphics_backend_impl.h +++ b/repos/demo/include/scout/graphics_backend_impl.h @@ -45,9 +45,7 @@ class Scout::Graphics_backend_impl : public Graphics_backend Genode::Dataspace_capability _init_fb_ds(Area max_size) { - Framebuffer::Mode const mode { .area = { max_size.w, max_size.h*2 }}; - - _gui.buffer(mode, false); + _gui.buffer({ .area = { max_size.w, max_size.h*2 }, .alpha = false }); return _gui.framebuffer.dataspace(); } @@ -58,37 +56,22 @@ class Scout::Graphics_backend_impl : public Graphics_backend Point _position; Area _view_size; - Canvas_base *_canvas[2]; bool _flip_state = { false }; Gui::Top_level_view _view { _gui, { _position, _view_size } }; - void _update_viewport() - { - using Command = Gui::Session::Command; - - Gui::Rect rect(_position, _view_size); - _gui.enqueue(_view.id(), rect); - - Gui::Point offset(0, _flip_state ? -_max_size.h : 0); - _gui.enqueue(_view.id(), offset); - - _gui.execute(); - } - - void _refresh_view(Rect rect) - { - int const y_offset = _flip_state ? _max_size.h : 0; - _gui.framebuffer.refresh(rect.x1(), rect.y1() + y_offset, - rect.w(), rect.h()); - } - template PT *_base(unsigned idx) { return (PT *)_fb_ds.local_addr() + idx*_max_size.count(); } + using PT = Genode::Pixel_rgb888; + + Canvas _canvas_0, _canvas_1; + + Canvas_base *_canvas[2] { &_canvas_0, &_canvas_1 }; + unsigned _front_idx() const { return _flip_state ? 1 : 0; } unsigned _back_idx() const { return _flip_state ? 0 : 1; } @@ -108,15 +91,10 @@ class Scout::Graphics_backend_impl : public Graphics_backend _gui(gui), _max_size(max_size), _position(position), - _view_size(view_size) - { - using PT = Genode::Pixel_rgb888; - static Canvas canvas_0(_base(0), max_size, alloc); - static Canvas canvas_1(_base(1), max_size, alloc); - - _canvas[0] = &canvas_0; - _canvas[1] = &canvas_1; - } + _view_size(view_size), + _canvas_0(_base(0), max_size, alloc), + _canvas_1(_base(1), max_size, alloc) + { } /******************************** @@ -128,34 +106,22 @@ class Scout::Graphics_backend_impl : public Graphics_backend void copy_back_to_front(Rect rect) override { + Point const from = rect.p1() + Point { 0, int( _back_idx()*_max_size.h) }; + Point const to = rect.p1() + Point { 0, int(_front_idx()*_max_size.h) }; - using PT = Genode::Pixel_rgb888; - - PT const *src = _base( _back_idx()); - PT *dst = _base(_front_idx()); - - unsigned long const offset = rect.y1()*_max_size.w + rect.x1(); - - src += offset; - dst += offset; - - blit(src, (unsigned)sizeof(PT)*_max_size.w, dst, - (int)sizeof(PT)*_max_size.w, - (int)sizeof(PT)*rect.w(), rect.h()); - - _refresh_view(rect); + _gui.framebuffer.blit({ from, rect.area }, to); } void swap_back_and_front() override { _flip_state = !_flip_state; - _update_viewport(); + _gui.framebuffer.panning({ 0, int(_front_idx()*_max_size.h) }); } void position(Point p) override { _position = p; - _update_viewport(); + _view.at(p); } void bring_to_front() override @@ -166,6 +132,7 @@ class Scout::Graphics_backend_impl : public Graphics_backend void view_area(Area area) override { _view_size = area; + _view.area(area); } }; diff --git a/repos/demo/recipes/src/demo/hash b/repos/demo/recipes/src/demo/hash index 33a7f5b195..f43413be51 100644 --- a/repos/demo/recipes/src/demo/hash +++ b/repos/demo/recipes/src/demo/hash @@ -1 +1 @@ -2024-08-28 14eede134747889773a1c019754dcd2b3dfcb370 +2024-12-10 a3ea43f1df828757d65692f65c98381790eea07a diff --git a/repos/demo/src/server/liquid_framebuffer/main.cc b/repos/demo/src/server/liquid_framebuffer/main.cc index f3ef47dd00..01955f9c89 100644 --- a/repos/demo/src/server/liquid_framebuffer/main.cc +++ b/repos/demo/src/server/liquid_framebuffer/main.cc @@ -125,7 +125,8 @@ namespace Liquid_fb { } -class Liquid_fb::Main : public Scout::Event_handler +class Liquid_fb::Main : public Scout::Event_handler, + private Input::Session_component::Action { private: @@ -162,7 +163,16 @@ class Liquid_fb::Main : public Scout::Event_handler _graphics_backend { _env.rm(), _gui, _heap, _max_size, _initial_position, _initial_size }; - Input::Session_component _input_session_component { _env, _env.ram() }; + Input::Session_component _input_session_component { + _env.ep(), _env.ram(), _env.rm(), *this }; + + /** + * Input::Session_component::Action interface + */ + void exclusive_input_requested(bool enabled) override + { + _gui.input.exclusive(enabled); + } bool const _window_content_initialized = (init_window_content(_env.ram(), _env.rm(), _heap, _input_session_component, diff --git a/repos/demo/src/server/liquid_framebuffer/services.cc b/repos/demo/src/server/liquid_framebuffer/services.cc index 208ee1ff86..bec5a210c2 100644 --- a/repos/demo/src/server/liquid_framebuffer/services.cc +++ b/repos/demo/src/server/liquid_framebuffer/services.cc @@ -239,10 +239,10 @@ class Framebuffer::Session_component : public Genode::Rpc_object public: - Session_component(Genode::Env &env, Window_content &window_content) + Session_component(Env &env, Window_content &window_content) : _timer(env), _window_content(window_content) { } - Genode::Dataspace_capability dataspace() override + Dataspace_capability dataspace() override { _window_content.realloc_framebuffer(); return _window_content.fb_ds_cap(); @@ -250,21 +250,36 @@ class Framebuffer::Session_component : public Genode::Rpc_object Mode mode() const override { - return Mode { .area = _window_content.mode_size() }; + return { .area = _window_content.mode_size(), .alpha = false }; } - void mode_sigh(Genode::Signal_context_capability sigh) override { - _window_content.mode_sigh(sigh); } + void mode_sigh(Signal_context_capability sigh) override + { + _window_content.mode_sigh(sigh); + } - void sync_sigh(Genode::Signal_context_capability sigh) override + void sync_sigh(Signal_context_capability sigh) override { _timer.sigh(sigh); _timer.trigger_periodic(10*1000); } - void refresh(int x, int y, int w, int h) override + void sync_source(Session_label const &) override { } + + void refresh(Rect rect) override { - _window_content.redraw_area(x, y, w, h); + _window_content.redraw_area(rect.x1(), rect.y1(), rect.w(), rect.h()); + } + + Blit_result blit(Blit_batch const &) override + { + warning("Framebuffer::Session::blit not supported"); + return Blit_result::OK; + } + + void panning(Point) override + { + warning("Framebuffer::Session::panning not supported"); } }; @@ -285,7 +300,27 @@ void init_services(Genode::Env &env, Input::Session_component &input_component) using namespace Genode; static Framebuffer::Session_component fb_session(env, *_window_content); - static Static_root fb_root(env.ep().manage(fb_session)); + + env.ep().manage(fb_session); + + struct Fb_root : Static_root + { + Framebuffer::Session_component &_fb_session; + + Fb_root(Framebuffer::Session_component &fb_session) + : + Static_root(fb_session.cap()), + _fb_session(fb_session) + { } + + void close(Genode::Capability) override + { + _fb_session.sync_sigh(Genode::Signal_context_capability()); + _fb_session.mode_sigh(Genode::Signal_context_capability()); + } + }; + + static Fb_root fb_root { fb_session }; static Input::Root_component input_root(env.ep().rpc_ep(), input_component); diff --git a/repos/demo/src/server/nitlog/main.cc b/repos/demo/src/server/nitlog/main.cc index 8b4ef8d1ff..b2efdf9ad2 100644 --- a/repos/demo/src/server/nitlog/main.cc +++ b/repos/demo/src/server/nitlog/main.cc @@ -366,7 +366,7 @@ struct Nitlog::Main void _init_gui_buffer() { - _gui.buffer(Framebuffer::Mode { .area = { _win_w, _win_h } }, false); + _gui.buffer({ .area = { _win_w, _win_h }, .alpha = false }); } bool const _gui_buffer_initialized = (_init_gui_buffer(), true); @@ -444,7 +444,7 @@ struct Nitlog::Main void _handle_timer() { if (_log_window.draw()) - _gui.framebuffer.refresh(0, 0, _win_w, _win_h); + _gui.framebuffer.refresh({ { 0, 0 }, { _win_w, _win_h } }); } Main(Env &env) : _env(env) diff --git a/repos/gems/include/dialog/sandboxed_runtime.h b/repos/gems/include/dialog/sandboxed_runtime.h index 33f10fd029..8385edc86d 100644 --- a/repos/gems/include/dialog/sandboxed_runtime.h +++ b/repos/gems/include/dialog/sandboxed_runtime.h @@ -102,7 +102,7 @@ class Dialog::Sandboxed_runtime : Noncopyable { Start_name const name; Ram_quota const initial_ram { 4*1024*1024 }; - Cap_quota const initial_caps { 100 }; + Cap_quota const initial_caps { 130 }; Ram_quota ram = initial_ram; Cap_quota caps = initial_caps; diff --git a/repos/gems/include/gems/gui_buffer.h b/repos/gems/include/gems/gui_buffer.h index cfc87a17a9..5fc015dc5b 100644 --- a/repos/gems/include/gems/gui_buffer.h +++ b/repos/gems/include/gems/gui_buffer.h @@ -15,14 +15,8 @@ #define _INCLUDE__GEMS__GUI_BUFFER_H_ /* Genode includes */ -#include #include -#include #include -#include -#include -#include -#include struct Gui_buffer : Genode::Noncopyable @@ -36,50 +30,38 @@ struct Gui_buffer : Genode::Noncopyable using Point = Genode::Surface_base::Point; using Ram_ds = Genode::Attached_ram_dataspace; using size_t = Genode::size_t; + using uint8_t = Genode::uint8_t; - Genode::Ram_allocator &ram; - Genode::Region_map &rm; + Genode::Ram_allocator &_ram; + Genode::Region_map &_rm; - Gui::Connection &gui; + Gui::Connection &_gui; Framebuffer::Mode const mode; - bool const use_alpha; + /* + * Make the GUI mode twice as high as the requested mode. The upper part + * of the GUI framebuffer contains the front buffer, the lower part + * contains the back buffer. + */ + Framebuffer::Mode const _gui_mode { .area = { mode.area.w, mode.area.h*2 }, + .alpha = mode.alpha }; + + Genode::Surface_window const _backbuffer { .y = mode.area.h, .h = mode.area.h }; Pixel_rgb888 const reset_color; - /** - * Return dataspace capability for virtual framebuffer - */ - Genode::Dataspace_capability _ds_cap(Gui::Connection &gui) - { - /* setup virtual framebuffer mode */ - gui.buffer(mode, use_alpha); - - return gui.framebuffer.dataspace(); - } - - Genode::Attached_dataspace fb_ds { rm, _ds_cap(gui) }; - - size_t pixel_surface_num_bytes() const - { - return size().count()*sizeof(Pixel_rgb888); - } - - size_t alpha_surface_num_bytes() const - { - return use_alpha ? size().count() : 0; - } - - Ram_ds pixel_surface_ds { ram, rm, pixel_surface_num_bytes() }; - Ram_ds alpha_surface_ds { ram, rm, alpha_surface_num_bytes() }; + Genode::Attached_dataspace _fb_ds { + _rm, ( _gui.buffer(_gui_mode), _gui.framebuffer.dataspace() ) }; enum class Alpha { OPAQUE, ALPHA }; - static Genode::Color default_reset_color() - { - return Genode::Color(127, 127, 127, 255); - } + /* + * Do not use black by default to limit the bleeding of black into + * antialiased drawing operations applied onto an initially transparent + * background. + */ + static constexpr Genode::Color default_reset_color = { 127, 127, 127, 255 }; /** * Constructor @@ -87,39 +69,42 @@ struct Gui_buffer : Genode::Noncopyable Gui_buffer(Gui::Connection &gui, Area size, Genode::Ram_allocator &ram, Genode::Region_map &rm, Alpha alpha = Alpha::ALPHA, - Genode::Color reset_color = default_reset_color()) + Genode::Color reset_color = default_reset_color) : - ram(ram), rm(rm), gui(gui), + _ram(ram), _rm(rm), _gui(gui), mode({ .area = { Genode::max(1U, size.w), - Genode::max(1U, size.h) } }), - use_alpha(alpha == Alpha::ALPHA), + Genode::max(1U, size.h) }, + .alpha = (alpha == Alpha::ALPHA) }), reset_color(reset_color.r, reset_color.g, reset_color.b, reset_color.a) { reset_surface(); } /** - * Return size of virtual framebuffer + * Return size of the drawing surface */ Area size() const { return mode.area; } - template - void with_alpha_surface(FN const &fn) + void with_alpha_surface(auto const &fn) { - Area const alpha_size = use_alpha ? size() : Area(0, 0); - Alpha_surface alpha(alpha_surface_ds.local_addr(), alpha_size); - fn(alpha); + if (!_gui_mode.alpha) { + Alpha_surface dummy { nullptr, Gui::Area { } }; + fn(dummy); + return; + } + _gui_mode.with_alpha_surface(_fb_ds, [&] (Alpha_surface &surface) { + surface.with_window(_backbuffer, [&] (Alpha_surface &surface) { + fn(surface); }); }); } - template - void with_pixel_surface(FN const &fn) + void with_pixel_surface(auto const &fn) { - Pixel_surface pixel(pixel_surface_ds.local_addr(), size()); - fn(pixel); + _gui_mode.with_pixel_surface(_fb_ds, [&] (Pixel_surface &surface) { + surface.with_window(_backbuffer, [&] (Pixel_surface &surface) { + fn(surface); }); }); } - template - void apply_to_surface(FN const &fn) + void apply_to_surface(auto const &fn) { with_alpha_surface([&] (Alpha_surface &alpha) { with_pixel_surface([&] (Pixel_surface &pixel) { @@ -128,18 +113,11 @@ struct Gui_buffer : Genode::Noncopyable void reset_surface() { - if (use_alpha) - with_alpha_surface([&] (Alpha_surface &alpha) { - Genode::memset(alpha.addr(), 0, alpha_surface_num_bytes()); }); + with_alpha_surface([&] (Alpha_surface &alpha) { + Genode::memset(alpha.addr(), 0, alpha.size().count()); }); with_pixel_surface([&] (Pixel_surface &pixel) { - /* - * Initialize color buffer with 50% gray - * - * We do not use black to limit the bleeding of black into antialiased - * drawing operations applied onto an initially transparent background. - */ Pixel_rgb888 *dst = pixel.addr(); Pixel_rgb888 const color = reset_color; @@ -148,71 +126,40 @@ struct Gui_buffer : Genode::Noncopyable }); } - template - void _convert_back_to_front(DST_PT *front_base, - Genode::Texture const &texture, - Rect const clip_rect) - { - Genode::Surface surface(front_base, size()); - - surface.clip(clip_rect); - - Blit_painter::paint(surface, texture, Point()); - } - void _update_input_mask() { - if (!use_alpha) - return; + with_alpha_surface([&] (Alpha_surface &alpha) { - size_t const num_pixels = size().count(); + using Input_surface = Genode::Surface; - unsigned char * const alpha_base = fb_ds.local_addr() - + mode.bytes_per_pixel()*num_pixels; + _gui_mode.with_input_surface(_fb_ds, [&] (Input_surface &input) { + input.with_window(_backbuffer, [&] (Input_surface &input) { - unsigned char * const input_base = alpha_base + num_pixels; + uint8_t const * src = (uint8_t *)alpha.addr(); + uint8_t * dst = (uint8_t *)input.addr(); - unsigned char const *src = alpha_base; - unsigned char *dst = input_base; + /* + * Set input mask for all pixels where the alpha value is + * above a given threshold. The threshold is defined such + * that typical drop shadows are below the value. + */ + uint8_t const threshold = 100; + size_t const num_pixels = Genode::min(alpha.size().count(), + input.size().count()); - /* - * Set input mask for all pixels where the alpha value is above a - * given threshold. The threshold is defined such that typical - * drop shadows are below the value. - */ - unsigned char const threshold = 100; - - for (unsigned i = 0; i < num_pixels; i++) - *dst++ = (*src++) > threshold; + for (unsigned i = 0; i < num_pixels; i++) + *dst++ = (*src++) > threshold; + }); + }); + }); } void flush_surface() { - // XXX track dirty rectangles - Rect const clip_rect(Genode::Surface_base::Point(0, 0), size()); + _update_input_mask(); - { - /* represent back buffer as texture */ - Genode::Texture - pixel_texture(pixel_surface_ds.local_addr(), - nullptr, size()); - Pixel_rgb888 *pixel_base = fb_ds.local_addr(); - - _convert_back_to_front(pixel_base, pixel_texture, clip_rect); - } - - if (use_alpha) { - Genode::Texture - alpha_texture(alpha_surface_ds.local_addr(), - nullptr, size()); - - Pixel_alpha8 *alpha_base = fb_ds.local_addr() - + mode.bytes_per_pixel()*size().count(); - - _convert_back_to_front(alpha_base, alpha_texture, clip_rect); - - _update_input_mask(); - } + /* copy lower part of virtual framebuffer to upper part */ + _gui.framebuffer.blit({ { 0, int(size().h) }, size() }, { 0, 0 }); } }; diff --git a/repos/gems/include/gems/vfs_font.h b/repos/gems/include/gems/vfs_font.h index 52be3c4e65..3fdf2ab41f 100644 --- a/repos/gems/include/gems/vfs_font.h +++ b/repos/gems/include/gems/vfs_font.h @@ -60,11 +60,22 @@ class Genode::Vfs_font : public Text_painter::Font Glyph_header() { } - Glyph glyph() const { return Glyph { .width = _width, - .height = _height, - .vpos = _vpos, - .advance = _advance(), - .values = _values }; } + Advance_info advance_info() const + { + return { .width = _width, .advance = _advance() }; + } + + void with_glyph(Text_painter::Area const bb, auto const &fn) const + { + /* consider glyph bounds exceeding the font's bounding box */ + unsigned const clipped_h = _width ? unsigned(bb.count() / _width) : 0u; + + fn(Glyph { .width = _width, + .height = min(unsigned(_height), clipped_h), + .vpos = _vpos, + .advance = _advance(), + .values = _values }); + } } __attribute__((packed)); @@ -149,7 +160,8 @@ class Genode::Vfs_font : public Text_painter::Font { _glyphs_file.read(_file_pos(c), _buffer); - fn.apply(_buffer.header.glyph()); + _buffer.header.with_glyph(_bounding_box, [&] (Glyph const &glyph) { + fn.apply(glyph); }); } Advance_info advance_info(Codepoint c) const override @@ -158,9 +170,7 @@ class Genode::Vfs_font : public Text_painter::Font _glyphs_file.read(_file_pos(c), header_buffer); - Glyph const glyph = _buffer.header.glyph(); - - return Advance_info { .width = glyph.width, .advance = glyph.advance }; + return _buffer.header.advance_info(); } unsigned baseline() const override { return _baseline; } diff --git a/repos/gems/include/nano3d/scene.h b/repos/gems/include/nano3d/scene.h index 7728a8c20f..196f8788c5 100644 --- a/repos/gems/include/nano3d/scene.h +++ b/repos/gems/include/nano3d/scene.h @@ -86,10 +86,9 @@ class Nano3d::Scene * visible view because it contains the visible buffer, the * front buffer, and the back buffer. */ - bool const use_alpha = true; - unsigned const height = size.h*NUM_BUFFERS; - gui.buffer(Framebuffer::Mode { .area = { size.w, height } }, - use_alpha); + gui.buffer({ .area = { .w = size.w, + .h = size.h*NUM_BUFFERS }, + .alpha = true }); return gui.framebuffer; } diff --git a/repos/gems/lib/mk/dialog.mk b/repos/gems/lib/mk/dialog.mk index 7b20a82d7f..487487db5d 100644 --- a/repos/gems/lib/mk/dialog.mk +++ b/repos/gems/lib/mk/dialog.mk @@ -2,3 +2,5 @@ SRC_CC += sandboxed_runtime.cc text_area_widget.cc LIBS += sandbox vpath %.cc $(REP_DIR)/src/lib/dialog + +SHARED_LIB = yes diff --git a/repos/gems/lib/symbols/dialog b/repos/gems/lib/symbols/dialog new file mode 100644 index 0000000000..ab4197ecb1 --- /dev/null +++ b/repos/gems/lib/symbols/dialog @@ -0,0 +1,44 @@ +_ZN6Dialog16Text_area_widget10_handle_upEv T +_ZN6Dialog16Text_area_widget11_handle_endEv T +_ZN6Dialog16Text_area_widget12_handle_downEv T +_ZN6Dialog16Text_area_widget12_handle_homeEv T +_ZN6Dialog16Text_area_widget12_handle_leftEv T +_ZN6Dialog16Text_area_widget12handle_eventERKNS_5EventERNS0_6ActionE T +_ZN6Dialog16Text_area_widget13_handle_rightEv T +_ZN6Dialog16Text_area_widget14_handle_deleteEv T +_ZN6Dialog16Text_area_widget14_handle_pageupEv T +_ZN6Dialog16Text_area_widget14move_cursor_toERKNS_2AtE T +_ZN6Dialog16Text_area_widget15_handle_newlineEv T +_ZN6Dialog16Text_area_widget16_handle_pagedownEv T +_ZN6Dialog16Text_area_widget16_move_charactersERN6Genode13Dynamic_arrayINS0_9CharacterEEES5_ T +_ZN6Dialog16Text_area_widget16append_characterEN6Genode9CodepointE T +_ZN6Dialog16Text_area_widget17_delete_selectionEv T +_ZN6Dialog16Text_area_widget17_handle_backspaceEv T +_ZN6Dialog16Text_area_widget17_handle_printableEN6Genode9CodepointE T +_ZN6Dialog16Text_area_widget17_insert_printableEN6Genode9CodepointE T +_ZN6Dialog16Text_area_widget25_sanitize_scroll_positionEv T +_ZN6Dialog16Text_area_widget25insert_at_cursor_positionEN6Genode9CodepointE T +_ZN6Dialog16Text_area_widget4dragERKNS_10Dragged_atE T +_ZN6Dialog16Text_area_widget5clackERKNS_10Clacked_atERNS0_6ActionE T +_ZN6Dialog16Text_area_widget5clearEv T +_ZN6Dialog16Text_area_widget5clickERKNS_10Clicked_atE T +_ZN6Dialog17Sandboxed_runtime13_handle_hoverEv T +_ZN6Dialog17Sandboxed_runtime19_handle_gui_serviceEv T +_ZN6Dialog17Sandboxed_runtime19_handle_rom_serviceEv T +_ZN6Dialog17Sandboxed_runtime19apply_sandbox_stateERKN6Genode8Xml_nodeE T +_ZN6Dialog17Sandboxed_runtime22_handle_report_serviceEv T +_ZN6Dialog17Sandboxed_runtime4View13_handle_hoverEv T +_ZN6Dialog17Sandboxed_runtime4View19_handle_input_eventERKN5Input5EventE T +_ZN6Dialog17Sandboxed_runtime4View27_try_handle_click_and_clackEv T +_ZN6Dialog17Sandboxed_runtime4View6_leaveEv T +_ZN6Dialog17Sandboxed_runtime4ViewD1Ev T +_ZN6Dialog17Sandboxed_runtime4ViewD2Ev T +_ZN6Dialog17Sandboxed_runtimeC1ERN6Genode3EnvERNS1_9AllocatorERNS1_7SandboxERKNS0_4AttrE T +_ZN6Dialog17Sandboxed_runtimeC2ERN6Genode3EnvERNS1_9AllocatorERNS1_7SandboxERKNS0_4AttrE T +_ZNK6Dialog16Text_area_widget21gen_clipboard_contentERN6Genode13Xml_generatorE T +_ZNK6Dialog16Text_area_widget4viewERNS_5ScopeIJNS_4VboxEEEE T +_ZNK6Dialog16Text_area_widget9Selection18view_selected_lineERNS_5ScopeIJNS_4HboxENS_5FloatENS_5LabelEEEEN6Genode13Dynamic_arrayINS9_INS0_9CharacterEEEE5IndexERKSB_ T +_ZNK6Dialog17Sandboxed_runtime15Menu_view_state14gen_start_nodeERN6Genode13Xml_generatorERKNS2_10DictionaryINS0_4ViewENS2_6StringILm20EEEEE T +_ZNK6Dialog17Sandboxed_runtime15gen_start_nodesERN6Genode13Xml_generatorE T +_ZNK6Dialog17Sandboxed_runtime4View21_gen_menu_view_dialogERN6Genode13Xml_generatorE T +_ZNK6Dialog17Sandboxed_runtime4View21_gen_menu_view_routesERN6Genode13Xml_generatorE T diff --git a/repos/gems/recipes/api/dialog/content.mk b/repos/gems/recipes/api/dialog/content.mk new file mode 100644 index 0000000000..6bb9c5903d --- /dev/null +++ b/repos/gems/recipes/api/dialog/content.mk @@ -0,0 +1,10 @@ +MIRROR_FROM_REP_DIR := include/dialog lib/symbols/dialog + +content: $(MIRROR_FROM_REP_DIR) LICENSE + +$(MIRROR_FROM_REP_DIR): + $(mirror_from_rep_dir) + +LICENSE: + cp $(GENODE_DIR)/LICENSE $@ + diff --git a/repos/gems/recipes/api/dialog/hash b/repos/gems/recipes/api/dialog/hash new file mode 100644 index 0000000000..09dcef595b --- /dev/null +++ b/repos/gems/recipes/api/dialog/hash @@ -0,0 +1 @@ +2025-01-03 57d2347a8300897aa8a5175ebb976232dafe4e7b diff --git a/repos/gems/recipes/api/gems/hash b/repos/gems/recipes/api/gems/hash index 55edc00338..4234b6281c 100644 --- a/repos/gems/recipes/api/gems/hash +++ b/repos/gems/recipes/api/gems/hash @@ -1 +1 @@ -2024-08-28 9f92618dfcef016aaca5b1963ae33f40626d54de +2024-11-19 ad2e9aed3d7bc42713836999ef73700296bfe4a5 diff --git a/repos/gems/recipes/api/nano3d/hash b/repos/gems/recipes/api/nano3d/hash index 5042f6258b..8c1a3acb49 100644 --- a/repos/gems/recipes/api/nano3d/hash +++ b/repos/gems/recipes/api/nano3d/hash @@ -1 +1 @@ -2024-08-28 2e647171d0de1b6dddb31cc95899999dff02b086 +2024-10-07 e10d9f51cbda23d1e49cd3877eac383f5ec21f6d diff --git a/repos/gems/recipes/pkg/backdrop/hash b/repos/gems/recipes/pkg/backdrop/hash index 45a7258365..8bd84cf5ac 100644 --- a/repos/gems/recipes/pkg/backdrop/hash +++ b/repos/gems/recipes/pkg/backdrop/hash @@ -1 +1 @@ -2024-08-28 ef02c87b0fda9b5c79c169914cfced6ad709c928 +2024-12-10 2331ab258b8693a25f0ed076caf8b64409b0057f diff --git a/repos/gems/recipes/pkg/cpu_load_display/hash b/repos/gems/recipes/pkg/cpu_load_display/hash index 06ac3c3d13..42142386ff 100644 --- a/repos/gems/recipes/pkg/cpu_load_display/hash +++ b/repos/gems/recipes/pkg/cpu_load_display/hash @@ -1 +1 @@ -2024-08-28 5194783789dffe2786da57a9f04403b1540b39b3 +2024-12-10 80b7035543eb588baa89b5617f7c4e30dc0ac787 diff --git a/repos/gems/recipes/pkg/dbg_download/hash b/repos/gems/recipes/pkg/dbg_download/hash index 5a6967bc23..cc69c0ee3c 100644 --- a/repos/gems/recipes/pkg/dbg_download/hash +++ b/repos/gems/recipes/pkg/dbg_download/hash @@ -1 +1 @@ -2024-08-28 66beef21dd430e1acd854d550f60f7cdd6673d5f +2024-12-10 6cfb903adb9b3a37335b8a153735ea5f2add9479 diff --git a/repos/gems/recipes/pkg/depot_download/hash b/repos/gems/recipes/pkg/depot_download/hash index ae5121d65f..301adc4e59 100644 --- a/repos/gems/recipes/pkg/depot_download/hash +++ b/repos/gems/recipes/pkg/depot_download/hash @@ -1 +1 @@ -2024-08-28 e99d0ffe15f9b990a2700776dc7acc9571c163db +2024-12-10 a8b9d2d9dd065af5c04cd1f30de1fa71c5e88a2e diff --git a/repos/gems/recipes/pkg/drivers_nic-pc/hash b/repos/gems/recipes/pkg/drivers_nic-pc/hash index 1c009d98f5..a76962d2f4 100644 --- a/repos/gems/recipes/pkg/drivers_nic-pc/hash +++ b/repos/gems/recipes/pkg/drivers_nic-pc/hash @@ -1 +1 @@ -2024-11-08 accf26bc6d6834544423c03089e4ff8055b10f54 +2024-12-10 26477dd8676b62817d164d071160f668a91ddc29 diff --git a/repos/gems/recipes/pkg/file_vault/hash b/repos/gems/recipes/pkg/file_vault/hash index 7500555f86..f234b8d6e1 100644 --- a/repos/gems/recipes/pkg/file_vault/hash +++ b/repos/gems/recipes/pkg/file_vault/hash @@ -1 +1 @@ -2024-08-28 c7cf8c9ad08fbaf1195454e8a12f0610177bc448 +2024-12-10 7e3d8b208623ee10fd0ad66a7ea3ca7568588670 diff --git a/repos/gems/recipes/pkg/fonts_fs/hash b/repos/gems/recipes/pkg/fonts_fs/hash index 8088fa762e..37e4e47929 100644 --- a/repos/gems/recipes/pkg/fonts_fs/hash +++ b/repos/gems/recipes/pkg/fonts_fs/hash @@ -1 +1 @@ -2024-08-28 00bbb74b8b3db75992e0b3ceb500cd1ce80f74ac +2024-12-10 f3e78ab0f567830d43357ec5d426a63ec7227199 diff --git a/repos/gems/recipes/pkg/goa-linux/hash b/repos/gems/recipes/pkg/goa-linux/hash index 7c35a7c82a..d559c9cd22 100644 --- a/repos/gems/recipes/pkg/goa-linux/hash +++ b/repos/gems/recipes/pkg/goa-linux/hash @@ -1 +1 @@ -2024-08-28 66cf8dd5c0739e6818f0cd51c2b53fff848573f8 +2024-12-10 8a4e1382b17220274f1de1b0c9896dceee443bda diff --git a/repos/gems/recipes/pkg/goa/archives b/repos/gems/recipes/pkg/goa/archives index a48986b2d9..9c43233eab 100644 --- a/repos/gems/recipes/pkg/goa/archives +++ b/repos/gems/recipes/pkg/goa/archives @@ -7,6 +7,7 @@ _/src/compat-libc _/src/coreutils _/src/event_filter _/src/file_terminal +_/src/fs_query _/src/fs_report _/src/fs_rom _/src/gui_fb @@ -28,12 +29,16 @@ _/src/sed _/src/stdcxx _/src/stdin2out _/src/terminal +_/src/terminal_crosslink _/src/terminal_log _/src/vfs +_/src/vfs_audit +_/src/vfs_block _/src/vfs_import _/src/vfs_jitterentropy _/src/vfs_lwip _/src/vfs_pipe +_/src/vfs_rump _/src/vfs_ttf _/src/vim _/src/zlib diff --git a/repos/gems/recipes/pkg/goa/hash b/repos/gems/recipes/pkg/goa/hash index 4fb6106cec..d217eda59a 100644 --- a/repos/gems/recipes/pkg/goa/hash +++ b/repos/gems/recipes/pkg/goa/hash @@ -1 +1 @@ -2024-08-28 b6eb36b8998fda9e3f8f295538baf76b0b7c31b3 +2024-12-10 dde12ebb8894f0152a11c7b4c50b589e2dd6c8fe diff --git a/repos/gems/recipes/pkg/motif_decorator/hash b/repos/gems/recipes/pkg/motif_decorator/hash index 3b417deef2..8891bda06f 100644 --- a/repos/gems/recipes/pkg/motif_decorator/hash +++ b/repos/gems/recipes/pkg/motif_decorator/hash @@ -1 +1 @@ -2024-08-28 5ac652162ed3f6c852aa07c196b11ec148b8baee +2024-12-10 f6e7dcb77f24f2f69afe225449744ca3f78e94ac diff --git a/repos/gems/recipes/pkg/motif_decorator/runtime b/repos/gems/recipes/pkg/motif_decorator/runtime index 485bd0b5fc..8a93670391 100644 --- a/repos/gems/recipes/pkg/motif_decorator/runtime +++ b/repos/gems/recipes/pkg/motif_decorator/runtime @@ -1,4 +1,4 @@ - + diff --git a/repos/gems/recipes/pkg/motif_wm/hash b/repos/gems/recipes/pkg/motif_wm/hash index 28fe31667f..fcaa6ee2ed 100644 --- a/repos/gems/recipes/pkg/motif_wm/hash +++ b/repos/gems/recipes/pkg/motif_wm/hash @@ -1 +1 @@ -2024-08-28 0d1a81603266603d1d2bc80089fbdd183fc6d89b +2024-12-10 bf64013f34ef01064fe3d5987a71261e97122723 diff --git a/repos/gems/recipes/pkg/nano3d/hash b/repos/gems/recipes/pkg/nano3d/hash index f413a06853..269f63493a 100644 --- a/repos/gems/recipes/pkg/nano3d/hash +++ b/repos/gems/recipes/pkg/nano3d/hash @@ -1 +1 @@ -2024-08-28 4760b4a0b9e51ce6437bfa0b4ca2ccfc5490bdff +2024-12-10 694f2a65b464870028354ca9e73a877b80b3ae56 diff --git a/repos/gems/recipes/pkg/osci/hash b/repos/gems/recipes/pkg/osci/hash index 0af17af12c..f1e1b2762e 100644 --- a/repos/gems/recipes/pkg/osci/hash +++ b/repos/gems/recipes/pkg/osci/hash @@ -1 +1 @@ -2024-08-28 ab13c3aab45db919cccf37dfeddc1d84942862a1 +2024-12-10 cabdf37416c957c805a56818741bb03f1df5ef91 diff --git a/repos/gems/recipes/pkg/rom_osci/hash b/repos/gems/recipes/pkg/rom_osci/hash index 9801adb246..08a954e776 100644 --- a/repos/gems/recipes/pkg/rom_osci/hash +++ b/repos/gems/recipes/pkg/rom_osci/hash @@ -1 +1 @@ -2024-08-28 d458670e38599a23e2edf21f8d5c8e686a25f13c +2024-12-10 293004c1e767a5fc2d5ac496c458e957f3fe8950 diff --git a/repos/gems/recipes/pkg/screenshot_trigger/hash b/repos/gems/recipes/pkg/screenshot_trigger/hash index a4b363c272..60e89efc97 100644 --- a/repos/gems/recipes/pkg/screenshot_trigger/hash +++ b/repos/gems/recipes/pkg/screenshot_trigger/hash @@ -1 +1 @@ -2024-08-28 e4e8816f6e757b7dcc294956335e3d92f4aeb6d3 +2024-12-10 d8ef08caaec6af88d1228832f4afe797e36342a8 diff --git a/repos/gems/recipes/pkg/sculpt/README b/repos/gems/recipes/pkg/sculpt/README index 555d27342b..b9335b4a6f 100644 --- a/repos/gems/recipes/pkg/sculpt/README +++ b/repos/gems/recipes/pkg/sculpt/README @@ -1,7 +1,7 @@ ============================= - Sculpt Operating System 24.04 + Sculpt Operating System 24.10 ============================= @@ -61,7 +61,7 @@ Your feedback is appreciated! [https://www.genode-labs.com] A printable PDF version of this document is available at the -[https://genode.org/documentation/sculpt-24.04.pdf - Genode website]. +[https://genode.org/documentation/sculpt-24.10.pdf - Genode website]. Hardware requirements and preparations @@ -557,7 +557,7 @@ connectivity. Most importantly, however, it allows the user to access the _config_ and _report_ file systems. Both file systems are readily accessible under the "Files" tab of the panel. The file browser allows you to traverse directory hierarchies, inspect individual files, and edit files. -Alternatively to the "Files" tab, Sculpt 24.04 features a command-line +Alternatively to the "Files" tab, Sculpt 24.10 features a command-line interface. To spawn this command-line interface, click on the "ram fs" component in the graph and select "Inspect". In the panel, a third tab named "Inspect" appears, which hosts the command-line interface. @@ -680,24 +680,6 @@ emulating a scroll wheel by moving the pointer while pressing the middle mouse button (''). -Display settings ----------------- - -If you are running the Intel graphics driver, you can inspect the connected -displays and their supported resolutions by taking a look at the report at -_/report/runtime/intel_fb/connectors_. This report is updated -whenever a display is connected or disconnected. You can use this -information to enable or disable a display in the driver's configuration, -which you can find at _/config/fb_. - -For a quick test, change the attributes 'height="768"' to 'force_height="768"' -and 'width="1024"' to 'force_width="1024"'. When saving the file, the screen -real-estate will forcibly be limited to the specified size. This is helpful -during presentations where the projector has a lower resolution than the -laptop's internal display. By specifying the beamer's resolution, both the -laptop and the beamer show the same content. - - Exploring the drivers and Leitzentrale subsystems ------------------------------------------------- @@ -1477,7 +1459,7 @@ _/config/presets/_. To keep your custom preset available after reboot, follow the pattern described in Section [Making customizations permanent] by copying the file to -_/config/24.04/presets/_ at your Sculpt partition. +_/config/24.10/presets/_ at your Sculpt partition. Installation on disk @@ -1555,6 +1537,102 @@ One way to do that is by changing the system state in _/config/system_ to "reset". +Window management +================= + +The best starting point for realizing a Sculpt-OS-based desktop scenario +is the window-manager preset. Applications connected to the window manager +(wm) appear with window decorations that can be used to arrange, maximize, +or close the window. The window size of a resizeable application can be +changed by dragging the window border. + +Some applications like games may grab the pointer when clicking into their +window. One can regain the control over the pointer at any time by pressing +the 'Super' key. Other useful key combinations are 'Super-Tab' to switch the +keyboard focus between windows, and 'Super-Return' to toggle the maximized +state of the currently focused window. + +One can switch between virtual desktops using the key combinations 'Super+1', +'Super+2', 'Super+3', etc. New windows always appear at the first virtual +desktop. To move a window to a different one, use the system shell to edit +_/rw/recall/window_layouter/recall/rules_. Look out for the '' rule +for the window, and change the target attribute to another screen, e.g., +"screen_2". By editing the rules file, one can do further window manipulations: + +* Changing the order to rules to change the window-stacking order. +* Move or resize a window by changing the corresponding xpos, ypos, width, and + height attributes. +* Maximize/un-maximize a window by setting the maximized attribute + to "yes" or "no". + +As the rules file is a regular file, one can create a backup of the current +window layout by copying the file, and switch between different layouts by +overwriting the rules file by a different version. The window layout is +preserved across reboots because the rules file is a regular file stored on +the used file system, except when using the RAM file system. + + +Multi-monitor support +===================== + +Sculpt OS supports the use of multiple monitors on PCs with Intel graphics. +By default, all connected monitors display the same mirrored image. +This default can be tweaked using the configuration dialog hosted in the +_intel fb_ node of the component graph. + +[image sculpt_24_10_intel_fb] + +The dialog displays a list of present monitors labeled after their respective +connectors. A mode can be selected for each connector when clicking on the +connector entry. In-between the entries there are two buttons. The link +button (showing two vertical lines) is a toggle that defines whether the two +adjacent entries are mirrored or operated as discrete monitors. It is enabled +by default so that all monitors participate in the mirroring. By deselecting +the last enabled link button, the entry below the button becomes a discrete +(non-mirrored) monitor. + +The swap button allows for changing the order of the monitors, which has two +effects. First, the resolution of the very first monitor defines the size for +mirrored image. Hence, by changing the order of mirrored monitors, one can +pick the preferred image size. Second, the order of discrete monitors +defines the layout of a panorama, which spans the mirrored image on the left +followed by each discrete monitor towards the right. + +When using discrete monitors, Sculpt OS places the Leitzentrale GUI on the monitor +that currently hosts the mouse pointer. When moving the pointer from one +monitor to another, the GUI moves with it. Should the monitors have different +resolutions, Sculpt OS automatically adjusts the system-global font configuration +according to the monitor used. Should this effect on all users of the +system-global font configuration (like terminal windows hosted on yet another +monitor) be undesired, one can define a static font configuration by placing +a snapshot of _/config/managed/fonts_ to _/config/fonts_. + +If a monitor supports brightness control, the brightness can by adjusted in +the mode selection of the monitor. The mode selection also offers the option +to switch off the monitor, except for the monitor currently hosting the +Leitzentrale GUI. As a note of caution, there is currently no safety mechanism +against locking oneself out of the user interface by selecting a mode not +properly handled by a single connected monitor. + +The framebuffer-driver configuration as driven by the interactive dialog +can be found at _/config/managed/fb_. It is meant to be taken as starting +point for a manually managed configuration at _/config/fb_. Therefore, several +multi-monitor profiles (like office, home, train) can be realized by merely +replacing this file. +The panorama is defined at the _/config/managed/nitpicker_ configuration, +specifically the '' node. The '' node assigns the +viewports on the panorama as captured by the framebuffer driver. Sculpt OS +manages the panorama only if the '' node of _/config/nitpicker_ +is empty. By filling the '' node with custom policies, arbitrary +panorama layouts can be realized using the attributes 'xpos', 'ypos', 'width', +and 'height'. + +For diagnostic purposes, the _/report/runtime/intel_fb/connectors_ report +contains the connector state as currently observed by the framebuffer driver. +Furthermore, _/report/nitpicker/panorama_ contains the information about +the panorama and the components participating in capturing the panorama. + + Audio ===== @@ -1689,11 +1767,11 @@ download at [https://genode.org]. ! git clone https://github.com/genodelabs/genode.git ! cd genode - ! git checkout -b sculpt-24.04 sculpt-24.04 + ! git checkout -b sculpt-24.10 sculpt-24.10 # Download the support for the NOVA microkernel - ! ./tool/depot/download genodelabs/bin/x86_64/base-nova/2024-04-26 + ! ./tool/depot/download genodelabs/bin/x86_64/base-nova/2024-10-30 The content is downloaded to the _public/_ directory and extracted to the _depot/_ directory. @@ -1701,8 +1779,8 @@ download at [https://genode.org]. # Download all ingredients for the Sculpt boot image ! ./tool/depot/download \ - ! genodelabs/pkg/x86_64/sculpt/2024-04-26 \ - ! genodelabs/pkg/x86_64/sculpt_drivers-pc/2024-04-26 + ! genodelabs/pkg/x86_64/sculpt/2024-10-30 \ + ! genodelabs/pkg/x86_64/sculpt_drivers-pc/2024-10-30 # Create a build directory diff --git a/repos/gems/recipes/pkg/sculpt/hash b/repos/gems/recipes/pkg/sculpt/hash index 4ab713f00a..0b30329965 100644 --- a/repos/gems/recipes/pkg/sculpt/hash +++ b/repos/gems/recipes/pkg/sculpt/hash @@ -1 +1 @@ -2024-08-28 efe6cd4c63380ded30b7944afc007bb850de9c16 +2024-12-10 23989d36ce92a2d5ad8a46045e9de5f748d32c36 diff --git a/repos/gems/recipes/pkg/sculpt_distribution-pc/hash b/repos/gems/recipes/pkg/sculpt_distribution-pc/hash index 9d562679b7..3242607fc6 100644 --- a/repos/gems/recipes/pkg/sculpt_distribution-pc/hash +++ b/repos/gems/recipes/pkg/sculpt_distribution-pc/hash @@ -1 +1 @@ -2024-08-28 d35f206e7d6fcdd019dda4f2f471e2fb529035cb +2024-12-10 72043fd604d902d5d110c585469c559b627481b0 diff --git a/repos/gems/recipes/pkg/sculpt_distribution/hash b/repos/gems/recipes/pkg/sculpt_distribution/hash index c28ca3e7bc..514737d156 100644 --- a/repos/gems/recipes/pkg/sculpt_distribution/hash +++ b/repos/gems/recipes/pkg/sculpt_distribution/hash @@ -1 +1 @@ -2024-08-28 062100bdb91d2a89fe549d0ca653311e88fbaa48 +2024-12-10 f4f146eb4ab7c42e202d4592c295f5ea9a5d0a80 diff --git a/repos/gems/recipes/pkg/sculpt_drivers-pc/hash b/repos/gems/recipes/pkg/sculpt_drivers-pc/hash index 1df55d6cd4..798345999f 100644 --- a/repos/gems/recipes/pkg/sculpt_drivers-pc/hash +++ b/repos/gems/recipes/pkg/sculpt_drivers-pc/hash @@ -1 +1 @@ -2024-08-28 70fb780a3b943bc41bab9ebf1e139985536cbda8 +2024-12-10 83a0717a1eac7432c18564b449737a156d6f227a diff --git a/repos/gems/recipes/pkg/sticks_blue_backdrop/hash b/repos/gems/recipes/pkg/sticks_blue_backdrop/hash index 1238363862..874a453e04 100644 --- a/repos/gems/recipes/pkg/sticks_blue_backdrop/hash +++ b/repos/gems/recipes/pkg/sticks_blue_backdrop/hash @@ -1 +1 @@ -2024-08-28 f594df98660636ff12bd6039051837baf52d3da0 +2024-12-10 254be4540e5ee8ed1c2035f04e013c643c104abe diff --git a/repos/gems/recipes/pkg/sticks_blue_backdrop/runtime b/repos/gems/recipes/pkg/sticks_blue_backdrop/runtime index dd3b7074ee..f49b8b961f 100644 --- a/repos/gems/recipes/pkg/sticks_blue_backdrop/runtime +++ b/repos/gems/recipes/pkg/sticks_blue_backdrop/runtime @@ -1,4 +1,4 @@ - + diff --git a/repos/gems/recipes/pkg/terminal/hash b/repos/gems/recipes/pkg/terminal/hash index d5b9203a3c..ca5a605f8e 100644 --- a/repos/gems/recipes/pkg/terminal/hash +++ b/repos/gems/recipes/pkg/terminal/hash @@ -1 +1 @@ -2024-08-28 c8a23f229431fcf97358edaab5b1cc8b757be61e +2024-12-10 9a939261eba41cb34748e9bf0b611037f3be7bb4 diff --git a/repos/gems/recipes/pkg/terminal/runtime b/repos/gems/recipes/pkg/terminal/runtime index fa2d11abf1..3d634faf0a 100644 --- a/repos/gems/recipes/pkg/terminal/runtime +++ b/repos/gems/recipes/pkg/terminal/runtime @@ -1,4 +1,4 @@ - + diff --git a/repos/gems/recipes/pkg/test-depot_query_index/hash b/repos/gems/recipes/pkg/test-depot_query_index/hash index 2c170302b4..a2b071cbea 100644 --- a/repos/gems/recipes/pkg/test-depot_query_index/hash +++ b/repos/gems/recipes/pkg/test-depot_query_index/hash @@ -1 +1 @@ -2024-08-28 1945fdeeb41ab8aa2e85f326b605a83004c5b789 +2024-12-10 23d88707fd9bb388dd04148062e72125991b8158 diff --git a/repos/gems/recipes/pkg/test-file_vault/hash b/repos/gems/recipes/pkg/test-file_vault/hash index a007820498..20141b14fd 100644 --- a/repos/gems/recipes/pkg/test-file_vault/hash +++ b/repos/gems/recipes/pkg/test-file_vault/hash @@ -1 +1 @@ -2024-08-28 4b09ba801fb71acac101ffcef51e464b5ae0817c +2024-12-10 73689b38ac3de066d8e079030c5b921e0a45995a diff --git a/repos/gems/recipes/pkg/test-file_vault_no_entropy/hash b/repos/gems/recipes/pkg/test-file_vault_no_entropy/hash index 6941adb290..b7b977fcf6 100644 --- a/repos/gems/recipes/pkg/test-file_vault_no_entropy/hash +++ b/repos/gems/recipes/pkg/test-file_vault_no_entropy/hash @@ -1 +1 @@ -2024-08-28 dbcd5df91cd813738081d8b5a52fe76ec3169b63 +2024-12-10 9057d257a8ccff10e35626860466c7b7fea8aef7 diff --git a/repos/gems/recipes/pkg/test-fs_tool/hash b/repos/gems/recipes/pkg/test-fs_tool/hash index d8c4c55176..4968e49ea4 100644 --- a/repos/gems/recipes/pkg/test-fs_tool/hash +++ b/repos/gems/recipes/pkg/test-fs_tool/hash @@ -1 +1 @@ -2024-08-28 05730ef204996d86a51e42305fb7a0840d3139cb +2024-12-10 a6ff69ef90ae427a17233b407b25e017b93a09c8 diff --git a/repos/gems/recipes/pkg/test-libc_vfs_audit/hash b/repos/gems/recipes/pkg/test-libc_vfs_audit/hash index d068d84527..ef302ab601 100644 --- a/repos/gems/recipes/pkg/test-libc_vfs_audit/hash +++ b/repos/gems/recipes/pkg/test-libc_vfs_audit/hash @@ -1 +1 @@ -2024-08-28 90c78c2cc96ef24c2387b5986f2a61b46132ff36 +2024-12-10 84c5ea804a45e6fa72ddce8c70bf8b5a80f234ad diff --git a/repos/gems/recipes/pkg/themed_decorator/hash b/repos/gems/recipes/pkg/themed_decorator/hash index 3aabd0d6b7..2f0829b7d3 100644 --- a/repos/gems/recipes/pkg/themed_decorator/hash +++ b/repos/gems/recipes/pkg/themed_decorator/hash @@ -1 +1 @@ -2024-08-28 bd55579c99712a624c5ce9a4e44aed5d9fae1052 +2024-12-10 02135f8e3c8596782a73e510365b357cb4f33b83 diff --git a/repos/gems/recipes/pkg/themed_wm/hash b/repos/gems/recipes/pkg/themed_wm/hash index a33c1edd51..9542c834a1 100644 --- a/repos/gems/recipes/pkg/themed_wm/hash +++ b/repos/gems/recipes/pkg/themed_wm/hash @@ -1 +1 @@ -2024-08-28 64afc4082fce3637ccb43b5ff296d36729ca7327 +2024-12-10 e264316f974e0b434d8f6465f29ccc9e8cd85cae diff --git a/repos/gems/recipes/pkg/touch_keyboard/hash b/repos/gems/recipes/pkg/touch_keyboard/hash index 6cddbd5733..b15e299b15 100644 --- a/repos/gems/recipes/pkg/touch_keyboard/hash +++ b/repos/gems/recipes/pkg/touch_keyboard/hash @@ -1 +1 @@ -2024-08-28 ac307c27d772bcaebb1669f7e052c1c2db233713 +2024-12-10 8c4b668cdca1ca8b54752e67cb765150a5ea1360 diff --git a/repos/gems/recipes/pkg/trace_fs/hash b/repos/gems/recipes/pkg/trace_fs/hash index cbc41bf0f6..9c914b4d71 100644 --- a/repos/gems/recipes/pkg/trace_fs/hash +++ b/repos/gems/recipes/pkg/trace_fs/hash @@ -1 +1 @@ -2024-08-28 a1037d9fa41db2dfd182169d158b0885e1248aaf +2024-12-10 ad3ca233590cf620f20234ae0fe95e5117d29c81 diff --git a/repos/gems/recipes/pkg/trace_recorder/hash b/repos/gems/recipes/pkg/trace_recorder/hash index 3e1a6b37d0..fa34f70b3b 100644 --- a/repos/gems/recipes/pkg/trace_recorder/hash +++ b/repos/gems/recipes/pkg/trace_recorder/hash @@ -1 +1 @@ -2024-08-28 a6857dd53f38f1d8197e21a77466162e07554e71 +2024-12-10 26533ef759741686bcef8fa057dfc276af56f28b diff --git a/repos/gems/recipes/pkg/unconfigured_nano3d/hash b/repos/gems/recipes/pkg/unconfigured_nano3d/hash index 80d6b6058a..0195723a11 100644 --- a/repos/gems/recipes/pkg/unconfigured_nano3d/hash +++ b/repos/gems/recipes/pkg/unconfigured_nano3d/hash @@ -1 +1 @@ -2024-08-28 323a0e88d9b19c25ce710e034f4fae9091b75a51 +2024-12-10 a926cce68b4eb8a6721881703cf3a47c4be0d397 diff --git a/repos/gems/recipes/pkg/window_layouter/hash b/repos/gems/recipes/pkg/window_layouter/hash index 29decd9d8b..73284e610a 100644 --- a/repos/gems/recipes/pkg/window_layouter/hash +++ b/repos/gems/recipes/pkg/window_layouter/hash @@ -1 +1 @@ -2024-08-28 0d98cc1f2f68904f796e5d15e8213a1fd843bc03 +2024-12-10 749e59fb153f6a578cb40e556e6e4cd6b0f285e2 diff --git a/repos/gems/recipes/pkg/window_layouter/runtime b/repos/gems/recipes/pkg/window_layouter/runtime index c4034a9062..15ffb76358 100644 --- a/repos/gems/recipes/pkg/window_layouter/runtime +++ b/repos/gems/recipes/pkg/window_layouter/runtime @@ -1,4 +1,4 @@ - + @@ -49,7 +49,7 @@ - + diff --git a/repos/gems/recipes/pkg/wm/hash b/repos/gems/recipes/pkg/wm/hash index 8547860908..716e5e9a69 100644 --- a/repos/gems/recipes/pkg/wm/hash +++ b/repos/gems/recipes/pkg/wm/hash @@ -1 +1 @@ -2024-08-28 563b0ffcd7c4100dba6e7dae1e24fd179f7e1f88 +2024-12-10 ea7acae1e47b5753a4e5a45a862f564a47b44af3 diff --git a/repos/gems/recipes/pkg/wm/runtime b/repos/gems/recipes/pkg/wm/runtime index d37fdf039f..4545d796c0 100644 --- a/repos/gems/recipes/pkg/wm/runtime +++ b/repos/gems/recipes/pkg/wm/runtime @@ -1,4 +1,4 @@ - + diff --git a/repos/gems/recipes/raw/motif_wm/decorator_init.config b/repos/gems/recipes/raw/motif_wm/decorator_init.config index 10ac1836c0..8d0e912d0d 100644 --- a/repos/gems/recipes/raw/motif_wm/decorator_init.config +++ b/repos/gems/recipes/raw/motif_wm/decorator_init.config @@ -9,7 +9,7 @@ - + </controls> <default-policy/> diff --git a/repos/gems/recipes/raw/motif_wm/hash b/repos/gems/recipes/raw/motif_wm/hash index 84df4f4607..5ed1e0d9bb 100644 --- a/repos/gems/recipes/raw/motif_wm/hash +++ b/repos/gems/recipes/raw/motif_wm/hash @@ -1 +1 @@ -2022-04-27 945e936c1b8c4328ee1745b2218699e29c55a276 +2024-10-07 68458ebc4b4f508958f2d55058c76e6de2d2ad73 diff --git a/repos/gems/recipes/raw/motif_wm/layouter.config b/repos/gems/recipes/raw/motif_wm/layouter.config index 4611a48a59..1560e09e17 100644 --- a/repos/gems/recipes/raw/motif_wm/layouter.config +++ b/repos/gems/recipes/raw/motif_wm/layouter.config @@ -15,7 +15,7 @@ <assign label_prefix="" target="screen_1" xpos="any" ypos="any"/> </rules> - <press key="KEY_SCREEN"> + <press key="KEY_SCREEN" action="release_grab"> <press key="KEY_TAB" action="next_window"> <release key="KEY_TAB"> <release key="KEY_SCREEN" action="raise_window"/> diff --git a/repos/gems/recipes/raw/motif_wm/wm.config b/repos/gems/recipes/raw/motif_wm/wm.config index 7a31d0009c..29aaabbc08 100644 --- a/repos/gems/recipes/raw/motif_wm/wm.config +++ b/repos/gems/recipes/raw/motif_wm/wm.config @@ -46,8 +46,8 @@ </config> </start> - <start name="wm" caps="250"> - <resource name="RAM" quantum="6M"/> + <start name="wm" caps="100"> + <resource name="RAM" quantum="2M"/> <provides> <service name="Gui"/> <service name="Report"/> <service name="ROM"/> </provides> @@ -70,7 +70,7 @@ </route> </start> - <start name="layouter"> + <start name="layouter" caps="120"> <binary name="window_layouter"/> <resource name="RAM" quantum="4M"/> <route> @@ -89,7 +89,7 @@ <start name="decorator" caps="450"> <binary name="init"/> - <resource name="RAM" quantum="12M"/> + <resource name="RAM" quantum="20M"/> <route> <service name="ROM" label="config"> <parent label="decorator_init.config"/> </service> diff --git a/repos/gems/recipes/raw/themed_wm/decorator_init.config b/repos/gems/recipes/raw/themed_wm/decorator_init.config index efe0bec858..9e8bf6b7ca 100644 --- a/repos/gems/recipes/raw/themed_wm/decorator_init.config +++ b/repos/gems/recipes/raw/themed_wm/decorator_init.config @@ -8,9 +8,9 @@ <service name="Timer"/> <service name="Report"/> </parent-provides> - <start name="decorator" caps="400"> + <start name="decorator" caps="320"> <binary name="themed_decorator"/> - <resource name="RAM" quantum="12M"/> + <resource name="RAM" quantum="11M"/> <config> <libc/> <vfs> <tar name="plain_decorator_theme.tar"/> </vfs> diff --git a/repos/gems/recipes/raw/themed_wm/hash b/repos/gems/recipes/raw/themed_wm/hash index cabcec9ab0..a414d17016 100644 --- a/repos/gems/recipes/raw/themed_wm/hash +++ b/repos/gems/recipes/raw/themed_wm/hash @@ -1 +1 @@ -2022-04-27 8ed349741e0beafb6f0473cb9f19ebd21dcef2f7 +2024-10-07 d5b44206be832ec30f7ec3028b70c3434c0971b3 diff --git a/repos/gems/recipes/raw/window_layouter/hash b/repos/gems/recipes/raw/window_layouter/hash index a379fc03fc..7112a3e90b 100644 --- a/repos/gems/recipes/raw/window_layouter/hash +++ b/repos/gems/recipes/raw/window_layouter/hash @@ -1 +1 @@ -2020-02-19 f8e677270d4386d000c8758cc401e7a9df82001d +2024-10-29 57d38bd73ebb281b2dfa779f03d47af88ba4515c diff --git a/repos/gems/recipes/raw/window_layouter/window_layouter.config b/repos/gems/recipes/raw/window_layouter/window_layouter.config index 4611a48a59..1560e09e17 100644 --- a/repos/gems/recipes/raw/window_layouter/window_layouter.config +++ b/repos/gems/recipes/raw/window_layouter/window_layouter.config @@ -15,7 +15,7 @@ <assign label_prefix="" target="screen_1" xpos="any" ypos="any"/> </rules> - <press key="KEY_SCREEN"> + <press key="KEY_SCREEN" action="release_grab"> <press key="KEY_TAB" action="next_window"> <release key="KEY_TAB"> <release key="KEY_SCREEN" action="raise_window"/> diff --git a/repos/gems/recipes/raw/wm/hash b/repos/gems/recipes/raw/wm/hash index 05b725f987..fba8f33a5e 100644 --- a/repos/gems/recipes/raw/wm/hash +++ b/repos/gems/recipes/raw/wm/hash @@ -1 +1 @@ -2020-06-21 beadfa2f974b9944ab9807c27c119c718abbd01f +2024-10-07 f9bdc38c7b4158ee82feab00283fbd133caa5eb5 diff --git a/repos/gems/recipes/raw/wm/wm.config b/repos/gems/recipes/raw/wm/wm.config index a967d99475..56235b11c2 100644 --- a/repos/gems/recipes/raw/wm/wm.config +++ b/repos/gems/recipes/raw/wm/wm.config @@ -74,8 +74,8 @@ </config> </start> - <start name="wm" caps="250"> - <resource name="RAM" quantum="8M"/> + <start name="wm" caps="150"> + <resource name="RAM" quantum="2M"/> <provides> <service name="Gui"/> <service name="Report"/> <service name="ROM"/> </provides> diff --git a/repos/gems/recipes/src/backdrop/hash b/repos/gems/recipes/src/backdrop/hash index 9be6f75810..163e9d6ac2 100644 --- a/repos/gems/recipes/src/backdrop/hash +++ b/repos/gems/recipes/src/backdrop/hash @@ -1 +1 @@ -2024-08-28 c06b592ecd63ca0fcd084c7f52db87907824f9a6 +2024-12-10 e84247e53c9bca6106e387e1829a8293f9163f5b diff --git a/repos/gems/recipes/src/cpu_load_display/hash b/repos/gems/recipes/src/cpu_load_display/hash index 9a2b82ec06..d8cd2a5346 100644 --- a/repos/gems/recipes/src/cpu_load_display/hash +++ b/repos/gems/recipes/src/cpu_load_display/hash @@ -1 +1 @@ -2024-08-28 852adfdf56d6b9c867391372af9418bcca9e9782 +2024-12-10 282a07f65edfd48daf82cb015a8ef3217cb924bf diff --git a/repos/gems/recipes/src/dbg_download/hash b/repos/gems/recipes/src/dbg_download/hash index 2dcddeed57..02e6264adb 100644 --- a/repos/gems/recipes/src/dbg_download/hash +++ b/repos/gems/recipes/src/dbg_download/hash @@ -1 +1 @@ -2024-08-28 f20ef23315abc0c081b8866b96bbafe2703a3ddb +2024-12-10 11b1ec97e8ebc727801208d4d1c5c1066e7037ed diff --git a/repos/gems/recipes/src/decorator/hash b/repos/gems/recipes/src/decorator/hash index 96b6b1ee6d..697e583e81 100644 --- a/repos/gems/recipes/src/decorator/hash +++ b/repos/gems/recipes/src/decorator/hash @@ -1 +1 @@ -2024-08-28 284d5916381cd8e3c9138dd6a8b70a03a01e9987 +2024-12-10 3974fb75e5260c9fd495f0ac3f20308651307f2b diff --git a/repos/gems/recipes/src/depot_deploy/hash b/repos/gems/recipes/src/depot_deploy/hash index a92fae9be7..a4e859dc26 100644 --- a/repos/gems/recipes/src/depot_deploy/hash +++ b/repos/gems/recipes/src/depot_deploy/hash @@ -1 +1 @@ -2024-08-28 ff82926d17f2a113ebf64b118d3f9dae69ca039a +2024-12-10 e59f7d94ebe9103f7ce3e91f24c3abd7f8d08e99 diff --git a/repos/gems/recipes/src/depot_download_manager/hash b/repos/gems/recipes/src/depot_download_manager/hash index 7aa2597b27..924805adb2 100644 --- a/repos/gems/recipes/src/depot_download_manager/hash +++ b/repos/gems/recipes/src/depot_download_manager/hash @@ -1 +1 @@ -2024-08-28 0a7a376cb38f151dd6f90b33cf13f996d00650cc +2024-12-10 c09f1624b4dd9a900be48e4fdd9df46c07ff4d7b diff --git a/repos/gems/recipes/src/depot_query/hash b/repos/gems/recipes/src/depot_query/hash index 3c9c6a417e..0c83b5aa05 100644 --- a/repos/gems/recipes/src/depot_query/hash +++ b/repos/gems/recipes/src/depot_query/hash @@ -1 +1 @@ -2024-08-28 e34136da1d1c2333537f83c8142a30248f614137 +2024-12-10 8b76180e49e619f1eff26dfef7f611abd3443684 diff --git a/repos/gems/recipes/src/depot_remove/hash b/repos/gems/recipes/src/depot_remove/hash index a18377990f..c164ee150a 100644 --- a/repos/gems/recipes/src/depot_remove/hash +++ b/repos/gems/recipes/src/depot_remove/hash @@ -1 +1 @@ -2024-08-28 10bcd3381e68f6464b49121f49b7c77adc056a90 +2024-12-10 acc159a472a8521f1c49585ae7961b6c9e7816c8 diff --git a/repos/gems/recipes/src/dialog/content.mk b/repos/gems/recipes/src/dialog/content.mk new file mode 100644 index 0000000000..df9d8db1b6 --- /dev/null +++ b/repos/gems/recipes/src/dialog/content.mk @@ -0,0 +1,7 @@ +SRC_DIR = src/lib/dialog +include $(GENODE_DIR)/repos/base/recipes/src/content.inc + +content: lib/mk/dialog.mk + +lib/mk/dialog.mk: + $(mirror_from_rep_dir) diff --git a/repos/gems/recipes/src/dialog/hash b/repos/gems/recipes/src/dialog/hash new file mode 100644 index 0000000000..40866ee1d6 --- /dev/null +++ b/repos/gems/recipes/src/dialog/hash @@ -0,0 +1 @@ +2025-01-03 2bb7885b49ed39d7aef08fea9d9ce82c88d47fd9 diff --git a/repos/gems/recipes/src/dialog/used_apis b/repos/gems/recipes/src/dialog/used_apis new file mode 100644 index 0000000000..eccc788b70 --- /dev/null +++ b/repos/gems/recipes/src/dialog/used_apis @@ -0,0 +1,9 @@ +base +os +gems +framebuffer_session +input_session +gui_session +report_session +dialog +sandbox diff --git a/repos/gems/recipes/src/file_terminal/hash b/repos/gems/recipes/src/file_terminal/hash index 09288f02aa..70a98ccaef 100644 --- a/repos/gems/recipes/src/file_terminal/hash +++ b/repos/gems/recipes/src/file_terminal/hash @@ -1 +1 @@ -2024-08-28 ab6934f75137b81262596d539f5adaf199a3e175 +2024-12-10 709855fd1b9956415ea29cf7d8b1c0cb32444cb7 diff --git a/repos/gems/recipes/src/file_vault/hash b/repos/gems/recipes/src/file_vault/hash index c2264d1d75..ec5d2a3405 100644 --- a/repos/gems/recipes/src/file_vault/hash +++ b/repos/gems/recipes/src/file_vault/hash @@ -1 +1 @@ -2024-08-28 fb0b48bcf12b88a78a2f6227cfa9348119d12470 +2024-12-10 c8df763de7d2a1935906f5fd710852cab1297c6c diff --git a/repos/gems/recipes/src/file_vault_gui/hash b/repos/gems/recipes/src/file_vault_gui/hash index 48a497722b..a582cc6960 100644 --- a/repos/gems/recipes/src/file_vault_gui/hash +++ b/repos/gems/recipes/src/file_vault_gui/hash @@ -1 +1 @@ -2024-08-28 9c2500ebce81ac440a0489a9544f5f97e8c39858 +2024-12-10 30ca16bbfeeaf9798050920443fdf22c388a1175 diff --git a/repos/gems/recipes/src/fs_query/hash b/repos/gems/recipes/src/fs_query/hash index 55d4a82a6a..4b2726db93 100644 --- a/repos/gems/recipes/src/fs_query/hash +++ b/repos/gems/recipes/src/fs_query/hash @@ -1 +1 @@ -2024-08-28 24276c7b5b4e6a97db749cb13e6d88a26bc9f49e +2024-12-10 ffe25169f242f9ef72a099d602d661c9fb3564a8 diff --git a/repos/gems/recipes/src/fs_tool/hash b/repos/gems/recipes/src/fs_tool/hash index 2589084966..c4cd37ecbb 100644 --- a/repos/gems/recipes/src/fs_tool/hash +++ b/repos/gems/recipes/src/fs_tool/hash @@ -1 +1 @@ -2024-08-28 e45f6a0c4449de35d602a3f67d79becdc4d15e12 +2024-12-10 f218ca96a9717ceafc57223c7e8f66c344802af4 diff --git a/repos/gems/recipes/src/gpt_write/hash b/repos/gems/recipes/src/gpt_write/hash index 2203f2c3a5..5d7cb40f27 100644 --- a/repos/gems/recipes/src/gpt_write/hash +++ b/repos/gems/recipes/src/gpt_write/hash @@ -1 +1 @@ -2024-08-28 2021d89c85c3463b1d2661c32aacc407a366b735 +2024-12-10 eed7b704b9b0d9c8b049e817cb1b08b3ccb6db50 diff --git a/repos/gems/recipes/src/gui_fader/hash b/repos/gems/recipes/src/gui_fader/hash index b690aa506a..9c40166e23 100644 --- a/repos/gems/recipes/src/gui_fader/hash +++ b/repos/gems/recipes/src/gui_fader/hash @@ -1 +1 @@ -2024-08-28 74213c19b72937426ed9ffe9c40a7990dce7bee1 +2024-12-10 5c25ad9d1a6d9860cd722de943bbfe8dbd4d7feb diff --git a/repos/gems/recipes/src/menu_view/hash b/repos/gems/recipes/src/menu_view/hash index 4d8b90dd6d..1082dd5fde 100644 --- a/repos/gems/recipes/src/menu_view/hash +++ b/repos/gems/recipes/src/menu_view/hash @@ -1 +1 @@ -2024-08-28 105bc681ae0ca76606695ec9b6235cbe2ea53796 +2024-12-10 37c4f7488f5ddfe8777faf9e820890706d9d920a diff --git a/repos/gems/recipes/src/mixer_gui_qt/hash b/repos/gems/recipes/src/mixer_gui_qt/hash index b4297d5336..e42d146a89 100644 --- a/repos/gems/recipes/src/mixer_gui_qt/hash +++ b/repos/gems/recipes/src/mixer_gui_qt/hash @@ -1 +1 @@ -2024-08-28 55ccba2abbcda46250b243075b5727fae4389675 +2024-12-10 4f57c91115e0322f7ae64f0f21753db1df973753 diff --git a/repos/gems/recipes/src/mixer_gui_qt6/hash b/repos/gems/recipes/src/mixer_gui_qt6/hash index 890e2682a8..aca045cd6d 100644 --- a/repos/gems/recipes/src/mixer_gui_qt6/hash +++ b/repos/gems/recipes/src/mixer_gui_qt6/hash @@ -1 +1 @@ -2024-08-28 1df576794d8dd2da27d253ab417e35bcd3b9dae3 +2024-12-10 763884c319c4ace890dd9d3d54ef07c51a837e9b diff --git a/repos/gems/recipes/src/nano3d/hash b/repos/gems/recipes/src/nano3d/hash index 9f4c09cae9..d9133a1946 100644 --- a/repos/gems/recipes/src/nano3d/hash +++ b/repos/gems/recipes/src/nano3d/hash @@ -1 +1 @@ -2024-08-28 c4725e2f3c20c6479e4fc8d380b70bd9aa3a1642 +2024-12-10 b14d61d3d29b0e68970ad83ca8b59aaa8e7806fd diff --git a/repos/gems/recipes/src/osci/hash b/repos/gems/recipes/src/osci/hash index 175623d71d..2e296f9c61 100644 --- a/repos/gems/recipes/src/osci/hash +++ b/repos/gems/recipes/src/osci/hash @@ -1 +1 @@ -2024-08-28 286362662b44fbbc485e3bb335ca10ea2ec121ff +2024-12-10 5f8e4313c51a1fe1a73936aac487cc48b4276b41 diff --git a/repos/gems/recipes/src/rom_osci/hash b/repos/gems/recipes/src/rom_osci/hash index fa392b43d1..9e563751b0 100644 --- a/repos/gems/recipes/src/rom_osci/hash +++ b/repos/gems/recipes/src/rom_osci/hash @@ -1 +1 @@ -2024-08-28 69bc3feb42a0ef8436a93d76698961d5f9e888aa +2024-12-10 b8056eef705e729465adc75b86607ae6795a76b9 diff --git a/repos/gems/recipes/src/screenshot_trigger/hash b/repos/gems/recipes/src/screenshot_trigger/hash index 8ebdf5b7b0..131d23ab29 100644 --- a/repos/gems/recipes/src/screenshot_trigger/hash +++ b/repos/gems/recipes/src/screenshot_trigger/hash @@ -1 +1 @@ -2024-08-28 287a862f194666c01add094c9bb00166f48fa537 +2024-12-10 80753cd96b9da29fa2ec2140aa022c5a3dbf5cd1 diff --git a/repos/gems/recipes/src/sculpt_manager/hash b/repos/gems/recipes/src/sculpt_manager/hash index e765bed632..5fa4416639 100644 --- a/repos/gems/recipes/src/sculpt_manager/hash +++ b/repos/gems/recipes/src/sculpt_manager/hash @@ -1 +1 @@ -2024-08-28 e0f6afc6782b432ee03b634299fc14c8c8822c62 +2024-12-10 4796bd5def5c9796e0988bea4a70ed1273aac0ae diff --git a/repos/gems/recipes/src/tcp_terminal/hash b/repos/gems/recipes/src/tcp_terminal/hash index acda98c155..d87695e8fb 100644 --- a/repos/gems/recipes/src/tcp_terminal/hash +++ b/repos/gems/recipes/src/tcp_terminal/hash @@ -1 +1 @@ -2024-08-28 499af9b0030e0f127fe0267e90336d76e5caf101 +2024-12-10 ad3571544920386e6f4606644df184f279315b12 diff --git a/repos/gems/recipes/src/terminal/hash b/repos/gems/recipes/src/terminal/hash index 1056435590..658dcf9f15 100644 --- a/repos/gems/recipes/src/terminal/hash +++ b/repos/gems/recipes/src/terminal/hash @@ -1 +1 @@ -2024-08-28 638415a10a23e9128fb63214e576daf9b20fca34 +2024-12-10 e90c6277d4cc7feb4f57fa6a38ffc336a6440c8d diff --git a/repos/gems/recipes/src/test-tiled_wm/hash b/repos/gems/recipes/src/test-tiled_wm/hash index 0dcf03bd2a..01158bf133 100644 --- a/repos/gems/recipes/src/test-tiled_wm/hash +++ b/repos/gems/recipes/src/test-tiled_wm/hash @@ -1 +1 @@ -2024-08-28 efb459e98c9c807e7c4524fa8bd82859bd126609 +2024-12-10 954cd17a47ee6fc13d1755f8844e061871159132 diff --git a/repos/gems/recipes/src/test-tiled_wm_qt6/hash b/repos/gems/recipes/src/test-tiled_wm_qt6/hash index d8e4758bde..9e7d7ceef5 100644 --- a/repos/gems/recipes/src/test-tiled_wm_qt6/hash +++ b/repos/gems/recipes/src/test-tiled_wm_qt6/hash @@ -1 +1 @@ -2024-08-28 182c37e66f22bd76aa7ccbcfe0229cfd9fa14302 +2024-12-10 77d9dec5b1ec5851956aa05f0887353b12436d4e diff --git a/repos/gems/recipes/src/text_area/hash b/repos/gems/recipes/src/text_area/hash index 2fc55f7d37..b23187f8e6 100644 --- a/repos/gems/recipes/src/text_area/hash +++ b/repos/gems/recipes/src/text_area/hash @@ -1 +1 @@ -2024-08-28 c489c9eb56f1635d53c45a6fa6c58bcdf79bad0f +2024-12-10 3e568be6fb0ecc2a5e7f3e0cc8e7debce557ae67 diff --git a/repos/gems/recipes/src/themed_decorator/hash b/repos/gems/recipes/src/themed_decorator/hash index 7cb76c7288..bccd349c3d 100644 --- a/repos/gems/recipes/src/themed_decorator/hash +++ b/repos/gems/recipes/src/themed_decorator/hash @@ -1 +1 @@ -2024-08-28 e1f78de7a91d9a006e1ba0beef267803990375ad +2024-12-10 cc307c1429f3d6adc354eba1f1120ccdcdb18173 diff --git a/repos/gems/recipes/src/touch_keyboard/hash b/repos/gems/recipes/src/touch_keyboard/hash index b0420c8514..c6cfc99649 100644 --- a/repos/gems/recipes/src/touch_keyboard/hash +++ b/repos/gems/recipes/src/touch_keyboard/hash @@ -1 +1 @@ -2024-08-28 c8d7ebed1ff069ba7ae982287376f20393660d86 +2024-12-10 9cd78ec70366ffe20ba1a5c773ef2e60c4f7553b diff --git a/repos/gems/recipes/src/trace_recorder/hash b/repos/gems/recipes/src/trace_recorder/hash index 8908f05593..de3c23a71c 100644 --- a/repos/gems/recipes/src/trace_recorder/hash +++ b/repos/gems/recipes/src/trace_recorder/hash @@ -1 +1 @@ -2024-08-28 0837827edb214e9c2e6c0a37b6a68379185e915f +2024-12-10 d8bdf9c540f5133d8090e65269659b01a67593e5 diff --git a/repos/gems/recipes/src/trace_recorder_policy/hash b/repos/gems/recipes/src/trace_recorder_policy/hash index 43b816986a..516dfe38cd 100644 --- a/repos/gems/recipes/src/trace_recorder_policy/hash +++ b/repos/gems/recipes/src/trace_recorder_policy/hash @@ -1 +1 @@ -2024-08-28 cae0a592c2b6a0a7bf0c4a49eb60e2e408f238a2 +2024-12-10 155556bc03e19f15a9d2c6bb93587d3e9401fdc2 diff --git a/repos/gems/recipes/src/tresor/hash b/repos/gems/recipes/src/tresor/hash index aa545d39f4..d08d42f2c3 100644 --- a/repos/gems/recipes/src/tresor/hash +++ b/repos/gems/recipes/src/tresor/hash @@ -1 +1 @@ -2024-08-28 059ec3712d55a0f917d427e41b54645c4f4ba40a +2024-12-10 3fe9f971c9b8696240d7aa77862cca10e3cf0582 diff --git a/repos/gems/recipes/src/vfs_audit/hash b/repos/gems/recipes/src/vfs_audit/hash index 6655a25db3..e5407b34cd 100644 --- a/repos/gems/recipes/src/vfs_audit/hash +++ b/repos/gems/recipes/src/vfs_audit/hash @@ -1 +1 @@ -2024-08-28 6c95d8f4b5bd58bc6e9de30ca53e28906acdbabf +2024-12-10 68ca33922c2fe8ea1b5ae1822849a5043a5e80a7 diff --git a/repos/gems/recipes/src/vfs_gpu/hash b/repos/gems/recipes/src/vfs_gpu/hash index d6f88edcd7..55c7e26203 100644 --- a/repos/gems/recipes/src/vfs_gpu/hash +++ b/repos/gems/recipes/src/vfs_gpu/hash @@ -1 +1 @@ -2024-08-28 6fd7c6d7e2da470df4fbe6ed855fbd8876b5a37d +2024-12-10 9cd378c6736f6c8b412bfb1336ebe52ec1f18b56 diff --git a/repos/gems/recipes/src/vfs_import/hash b/repos/gems/recipes/src/vfs_import/hash index 737d84def7..653f6c40f0 100644 --- a/repos/gems/recipes/src/vfs_import/hash +++ b/repos/gems/recipes/src/vfs_import/hash @@ -1 +1 @@ -2024-08-28 429b3e4545dcdee5014676fa1ad0bd6716e49707 +2024-12-10 8c4f1188d10eedcfb9763f60adca853c6d475887 diff --git a/repos/gems/recipes/src/vfs_oss/hash b/repos/gems/recipes/src/vfs_oss/hash index aea33776bb..8fdd0997d8 100644 --- a/repos/gems/recipes/src/vfs_oss/hash +++ b/repos/gems/recipes/src/vfs_oss/hash @@ -1 +1 @@ -2024-08-28 c5491cc8eff3aba76fa285aab1babadd819a1dc5 +2024-12-10 bb0379f2ddd28957a6d9ceb0029d82b3bd1813a8 diff --git a/repos/gems/recipes/src/vfs_pipe/hash b/repos/gems/recipes/src/vfs_pipe/hash index 985b205a01..0250b340cd 100644 --- a/repos/gems/recipes/src/vfs_pipe/hash +++ b/repos/gems/recipes/src/vfs_pipe/hash @@ -1 +1 @@ -2024-08-28 9535e2e705d816992383e07e9ee7e253507e883e +2024-12-10 543fa4df91d914fe585d35f8cebcefe0708899a9 diff --git a/repos/gems/recipes/src/vfs_trace/hash b/repos/gems/recipes/src/vfs_trace/hash index d7f0c3c43c..ea46c996fd 100644 --- a/repos/gems/recipes/src/vfs_trace/hash +++ b/repos/gems/recipes/src/vfs_trace/hash @@ -1 +1 @@ -2024-08-28 c6ada446ea2a4eaf88f7fe2ef75d8abdcedf1a48 +2024-12-10 fad0dcc5edf3e1a430663be6b3b3de81034b7512 diff --git a/repos/gems/recipes/src/vfs_ttf/hash b/repos/gems/recipes/src/vfs_ttf/hash index e82e6f968f..87aede4014 100644 --- a/repos/gems/recipes/src/vfs_ttf/hash +++ b/repos/gems/recipes/src/vfs_ttf/hash @@ -1 +1 @@ -2024-08-28 8c7c798ac0d1d7e29c1fd8f9bb6ba75d471075bb +2024-12-10 5ebc8fbed543900ece9295e76498d2e00d5ac703 diff --git a/repos/gems/recipes/src/window_layouter/hash b/repos/gems/recipes/src/window_layouter/hash index 8384091dde..dee9bf7776 100644 --- a/repos/gems/recipes/src/window_layouter/hash +++ b/repos/gems/recipes/src/window_layouter/hash @@ -1 +1 @@ -2024-08-28 334a2e6d83cb4a7b1e949d3afffc06abf3a6395d +2024-12-10 8da572807862e6ad18d03f4fee9ae15c8502e5d2 diff --git a/repos/gems/recipes/src/wm/hash b/repos/gems/recipes/src/wm/hash index 1a2dcdae2b..f94c94bb0e 100644 --- a/repos/gems/recipes/src/wm/hash +++ b/repos/gems/recipes/src/wm/hash @@ -1 +1 @@ -2024-08-28 b88935dca6b2b5a2762b2c6ea750b5655af1e643 +2024-12-10 3ab906e9ff02f0bcf5966eee9b14c40faa02c2db diff --git a/repos/gems/run/depot_autopilot.run b/repos/gems/run/depot_autopilot.run index 46f5bf6f7f..58e8ee3b5f 100644 --- a/repos/gems/run/depot_autopilot.run +++ b/repos/gems/run/depot_autopilot.run @@ -653,6 +653,7 @@ set default_test_pkgs { test-spark_secondary_stack test-alarm test-black_hole + test-callable test-clipboard test-depot_query_index test-ds_ownership @@ -672,6 +673,7 @@ set default_test_pkgs { test-init_loop test-ldso test-libc + test-libc_alarm test-libc_connect_lwip test-libc_connect_lxip test-libc_connect_vfs_server_lwip @@ -681,6 +683,7 @@ set default_test_pkgs { test-libc_fifo_pipe test-libc_fork test-libc_getenv + test-libc_kqueue test-libc_pipe test-libc_vfs test-libc_vfs_audit @@ -840,7 +843,7 @@ init_previous_results # set max_nr_of_tests_per_boot 0 if {[have_spec sel4]} { - set max_nr_of_tests_per_boot 20 + set max_nr_of_tests_per_boot 22 } # generic preparation for each system boot diff --git a/repos/gems/run/dialog.run b/repos/gems/run/dialog.run index 348bb5d5e4..07c4e7797e 100644 --- a/repos/gems/run/dialog.run +++ b/repos/gems/run/dialog.run @@ -109,7 +109,7 @@ set fd [open [run_dir]/genode/focus w] puts $fd "<focus label=\"test-dialog -> \"/>" close $fd -build { test/dialog app/menu_view } +build { test/dialog app/menu_view lib/dialog } build_boot_image [build_artifacts] diff --git a/repos/gems/run/nano3d.run b/repos/gems/run/nano3d.run index d4cebff5c0..34cc8c1412 100644 --- a/repos/gems/run/nano3d.run +++ b/repos/gems/run/nano3d.run @@ -59,7 +59,7 @@ install_config { </config> </start> - <start name="backdrop"> + <start name="backdrop" caps="130"> <resource name="RAM" quantum="20M"/> <config> <libc/> diff --git a/repos/gems/run/sculpt.run b/repos/gems/run/sculpt.run index 5435e2759a..94019ecdd8 100644 --- a/repos/gems/run/sculpt.run +++ b/repos/gems/run/sculpt.run @@ -7,7 +7,7 @@ # # Note: the string must be exactly 5 bytes long. # -proc sculpt_version { } { return "24.06" } +proc sculpt_version { } { return "24.10" } proc assert_platform_supported { } { @@ -15,6 +15,7 @@ proc assert_platform_supported { } { if {[have_board pc]} return if {[have_board imx8q_evk]} return if {[have_board mnt_reform2]} return + if {[have_board mnt_pocket]} return if {[have_board linux]} return if {[have_board pinephone]} return @@ -188,13 +189,28 @@ proc driver_routes { } { <service name="ROM" label="mmc.dtb"> <parent label="imx8mq_sd_card-mnt_reform2.dtb"/> </service> <service name="ROM" label="nic"> <parent label="fec_nic"/> </service> <service name="ROM" label="nic.dtb"> <parent label="fec_nic-mnt_reform2.dtb"/> </service> - <service name="ROM" label="usb"> <parent label="imx8mq_usb_host"/> </service> - <service name="ROM" label="usb.dtb"> <parent label="imx8mq_usb_host-mnt_reform2.dtb"/> </service> + <service name="ROM" label="usb"> <parent label="imx8m_usb_host"/> </service> + <service name="ROM" label="usb.dtb"> <parent label="imx8m_usb_host-mnt_reform2.dtb"/> </service> <service name="ROM" label="wifi.lib.so"> <parent label="imx8mq_wifi.lib.so"/> </service> <service name="ROM" label="wifi_firmware.tar"> <parent label="imx8mq_wifi_firmware.tar"/> </service> <service name="I2c"> <child name="drivers"/> </service> } + set result(mnt_pocket) { + <service name="ROM" label="fb"> <parent label="imx8mq_fb"/> </service> + <service name="ROM" label="fb.dtb"> <parent label="imx8mq_fb-mnt_pocket.dtb"/> </service> + <service name="ROM" label="mmc"> <parent label="imx8mq_sd_card"/> </service> + <service name="ROM" label="mmc.dtb"> <parent label="imx8mq_sd_card-mnt_pocket.dtb"/> </service> + <service name="ROM" label="nic"> <parent label="stmmac_nic"/> </service> + <service name="ROM" label="nic.dtb"> <parent label="stmmac_nic-mnt_pocket.dtb"/> </service> + <service name="ROM" label="usb"> <parent label="imx8m_usb_host"/> </service> + <service name="ROM" label="usb.dtb"> <parent label="imx8m_usb_host-mnt_pocket.dtb"/> </service> + <service name="ROM" label="wifi.dtb"> <parent label="wifi-mnt_pocket.dtb"/> </service> + <service name="ROM" label="wifi.lib.so"> <parent label="imx8mp_qcacld2_wifi.lib.so"/> </service> + <service name="ROM" label="wifi_firmware.tar"> <parent label="imx8mp_qcacld2_wifi_firmware.tar"/> </service> + <service name="I2c"> <child name="drivers"/> </service> + } + set result(imx8q_evk) { <service name="ROM" label="nic"> <parent label="fec_nic"/> </service> <service name="ROM" label="nic.dtb"> <parent label="fec_nic-imx8q_evk.dtb"/> </service> @@ -459,7 +475,7 @@ install_config { </start> <start name="nitpicker" caps="1000" priority="-1"> - <resource name="RAM" quantum="12M"/> + <resource name="RAM" quantum="18M"/> <resource name="CPU" quantum="10"/> <affinity xpos="1" width="1"/> <!-- decouple nitpicker from boot CPU --> <provides> @@ -467,9 +483,11 @@ install_config { </provides> <route> <service name="ROM" label="config"> - <child name="config_fs_rom" label="nitpicker"/> </service> + <child name="config_fs_rom" label="managed/nitpicker"/> </service> <service name="ROM" label="focus"> <child name="nit_focus"/> </service> + <service name="Report" label="panorama"> + <child name="fs_report"/> </service> <service name="Report" label="keystate"> <child name="report_logger"/> </service> <service name="Report"> <child name="report_rom"/> </service> @@ -713,8 +731,8 @@ install_config { } [log_route] [driver_routes] { <service name="Event" label="leitzentrale"> <child name="leitzentrale"/> </service> <service name="Event"> <child name="event_filter"/> </service> - <service name="Capture" label="global"> <child name="nitpicker"/> </service> <service name="Capture" label="leitzentrale"> <child name="leitzentrale"/> </service> + <service name="Capture"> <child name="nitpicker"/> </service> <service name="Pin_state"> <child name="drivers"/> </service> <service name="Pin_control"> <child name="drivers"/> </service> <service name="Terminal"> <child name="terminal_monitor"/> </service> @@ -830,7 +848,7 @@ set fd [open [managed_config_path depot_query] w] puts $fd "<query/>" close $fd -foreach config { fonts wifi runtime event_filter system } { +foreach config { fonts wifi runtime event_filter system nitpicker } { set ingredient [single_ingredient $config "default"] if {$ingredient != ""} { set from [ingredient_path $config $ingredient] @@ -1102,9 +1120,13 @@ if {[have_board linux]} { # The Linux version of core does not export a platform_info ROM module. # install_boot_module "platform_info" {<platform/>} +} + +if {[have_spec linux] || [have_spec fiasco] || [have_spec foc]} { # - # Managed dataspaces as used by cached_fs_rom are not supported on Linux. + # Managed dataspaces as used by cached_fs_rom are not supported fully + # on all kernels. # copy_file [run_dir]/genode/fs_rom [run_dir]/genode/cached_fs_rom } diff --git a/repos/gems/run/sculpt/index b/repos/gems/run/sculpt/index index 5a6596288f..309cfc2833 100644 --- a/repos/gems/run/sculpt/index +++ b/repos/gems/run/sculpt/index @@ -14,18 +14,18 @@ </index> <index name="Tools"> - <pkg path="system_shell" info="command-line interface to the system"/> - <pkg path="system_clock-pc" info="real-time-clock service" arch="x86_64"/> - <pkg path="qt5_textedit" info="Qt5-based text editor"/> - <pkg path="report_dump" info="save periodic snapshots of the report fs"/> - <pkg path="recall_fs" info="component-specific file-system view"/> - <pkg path="file_vault" info="encrypted file store"/> - <pkg path="black_hole" info="pseudo service provider"/> - <pkg path="usb_webcam" info="USB webcam"/> - <pkg path="bsd_audio" info="audio driver" arch="x86_64"/> - <pkg path="mixer" info="audio mixer"/> - <pkg path="terminal" info="graphical terminal"/> - <pkg path="gdb_x86" info="GNU debugger" arch="x86_64"/> + <pkg path="system_shell" info="command-line interface to the system"/> + <pkg path="system_clock-pc" info="real-time-clock service" arch="x86_64"/> + <pkg path="qt5_textedit" info="Qt5-based text editor"/> + <pkg path="report_dump" info="save periodic snapshots of the report fs"/> + <pkg path="recall_fs" info="component-specific file-system view"/> + <pkg path="file_vault" info="encrypted file store"/> + <pkg path="black_hole" info="pseudo service provider"/> + <pkg path="usb_webcam" info="USB webcam"/> + <pkg path="bsd_audio" info="audio driver" arch="x86_64"/> + <pkg path="record_play_mixer" info="audio mixer"/> + <pkg path="terminal" info="graphical terminal"/> + <pkg path="gdb_x86" info="GNU debugger" arch="x86_64"/> </index> <index name="Demos"> diff --git a/repos/gems/run/sculpt_image.run b/repos/gems/run/sculpt_image.run index ea059ddf33..f565a0896e 100644 --- a/repos/gems/run/sculpt_image.run +++ b/repos/gems/run/sculpt_image.run @@ -6,6 +6,7 @@ proc board_supported { } { if {[have_board pinephone]} { return true } if {[have_board pc]} { return true } if {[have_board mnt_reform2]} { return true } + if {[have_board mnt_pocket]} { return true } return false } @@ -45,6 +46,12 @@ if {[have_board mnt_reform2]} { assert_run_arg "--image-uboot-gzip-best" } +if {[have_board mnt_pocket]} { + assert_include image/uboot + assert_include image/mnt_pocket_sdcard + assert_run_arg "--image-uboot-gzip-best" +} + source ${genode_dir}/repos/gems/run/sculpt.run set image_name "sculpt-$board_var-[build_date]" diff --git a/repos/gems/run/tiled_wm.run b/repos/gems/run/tiled_wm.run index e7da79b378..45dc3813fd 100644 --- a/repos/gems/run/tiled_wm.run +++ b/repos/gems/run/tiled_wm.run @@ -1,5 +1,7 @@ source ${genode_dir}/repos/libports/run/qt5_common.inc +build { test/tiled_wm } + import_from_depot [depot_user]/src/qt5_component \ [depot_user]/src/qt5_textedit \ [depot_user]/src/dynamic_rom \ @@ -194,7 +196,7 @@ install_config { <any-service> <parent /> <any-child/> </any-service> </route> </start> - <start name="textedit" caps="250"> + <start name="textedit" caps="350"> <resource name="RAM" quantum="70M"/> <config> <libc stdout="/dev/log" stderr="/dev/log" pipe="/pipe" rtc="/dev/rtc"/> @@ -219,7 +221,7 @@ install_config { </config> } -build_boot_image [qt5_boot_modules] +build_boot_image [list {*}[build_artifacts] {*}[qt5_boot_modules]] append qemu_args " -device nec-usb-xhci,id=xhci -device usb-tablet" diff --git a/repos/gems/run/tiled_wm_qt6.run b/repos/gems/run/tiled_wm_qt6.run index fc6426f35a..2b2cfc589f 100644 --- a/repos/gems/run/tiled_wm_qt6.run +++ b/repos/gems/run/tiled_wm_qt6.run @@ -194,7 +194,7 @@ install_config { <any-service> <parent /> <any-child/> </any-service> </route> </start> - <start name="textedit" caps="250"> + <start name="textedit" caps="350"> <resource name="RAM" quantum="70M"/> <config> <libc stdout="/dev/log" stderr="/dev/log" pipe="/pipe" rtc="/dev/rtc"/> diff --git a/repos/gems/run/wm.run b/repos/gems/run/wm.run index 9db7234587..4b05218668 100644 --- a/repos/gems/run/wm.run +++ b/repos/gems/run/wm.run @@ -63,6 +63,8 @@ install_config { <policy label_prefix="pointer" domain="pointer"/> <default-policy domain="default"/> + + <global-key name="KEY_SCREEN" label="wm -> wm -> decorator" /> </config> </start> @@ -108,7 +110,7 @@ install_config { </route> </start> - <start name="backdrop" priority="-1"> + <start name="backdrop" priority="-1" caps="120"> <resource name="RAM" quantum="24M"/> <config> <libc/> @@ -127,7 +129,7 @@ install_config { </route> </start> - <start name="wm_backdrop" priority="-1"> + <start name="wm_backdrop" priority="-1" caps="120"> <binary name="backdrop" /> <resource name="RAM" quantum="32M"/> <config> @@ -154,7 +156,9 @@ set fd [open [run_dir]/genode/focus w] puts $fd "<focus label=\"wm -> focus\"/>" close $fd -copy_file [genode_dir]/repos/gems/recipes/raw/motif_wm/wm.config [run_dir]/genode/ +copy_file [genode_dir]/repos/gems/recipes/raw/motif_wm/wm.config [run_dir]/genode/ +copy_file [genode_dir]/repos/gems/recipes/raw/motif_wm/layouter.config [run_dir]/genode/ +copy_file [genode_dir]/repos/gems/recipes/raw/motif_wm/decorator_init.config [run_dir]/genode/ build { app/window_layouter app/decorator server/nitpicker server/wm test/nitpicker } diff --git a/repos/gems/sculpt/default-pc.sculpt b/repos/gems/sculpt/default-pc.sculpt index 1cdcee7185..68bf658ab2 100644 --- a/repos/gems/sculpt/default-pc.sculpt +++ b/repos/gems/sculpt/default-pc.sculpt @@ -12,7 +12,7 @@ launcher: audio mixer system_clock acpi_support recall_fs touchpad # selection of accepted depot-package providers depot: genodelabs cnuke alex-ab mstein nfeske cproc chelmuth jschlatow -depot: ssumpf skalk +depot: ssumpf skalk atopia # preconfigured example scenarios presets: empty nano3d window_manager falkon_web_browser goa_testbed diff --git a/repos/gems/sculpt/deploy/falkon_web_browser b/repos/gems/sculpt/deploy/falkon_web_browser index f8915f63a9..0f32302cbf 100644 --- a/repos/gems/sculpt/deploy/falkon_web_browser +++ b/repos/gems/sculpt/deploy/falkon_web_browser @@ -61,7 +61,7 @@ </config> </start> - <start name="falkon-jemalloc" priority="-2" pkg="cproc/pkg/falkon-jemalloc/2024-04-16"> + <start name="falkon-jemalloc" priority="-2" pkg="cproc/pkg/falkon-jemalloc/2024-10-28"> <route> <service name="Nic"> <child name="nic_router"/> </service> <service name="Rtc"> <child name="system_clock"/> </service> diff --git a/repos/gems/sculpt/deploy/webcam b/repos/gems/sculpt/deploy/webcam new file mode 100644 index 0000000000..68d3a4f02b --- /dev/null +++ b/repos/gems/sculpt/deploy/webcam @@ -0,0 +1,24 @@ +<config arch="" info="webcam example"> + + <common_routes> + <service name="ROM" label_last="ld.lib.so"> <parent/> </service> + <service name="ROM" label_last="init"> <parent/> </service> + <service name="CPU"> <parent/> </service> + <service name="PD"> <parent/> </service> + <service name="LOG"> <parent/> </service> + <service name="Timer"> <parent/> </service> + <service name="Capture"> <parent/> </service> + <service name="Gui"> <parent/> </service> + </common_routes> + + <start name="webcam" ram="64M" pkg="usb_webcam"> + <route> + <service name="Usb"> <child name="usb"/> </service> + <any-service> <parent /> </any-service> + </route> + <provides> <service name="Capture"/> <service name="Report"/> </provides> + </start> + + <start name="test-capture"/> +</config> + diff --git a/repos/gems/sculpt/depot/atopia/download b/repos/gems/sculpt/depot/atopia/download new file mode 100644 index 0000000000..fc75210b14 --- /dev/null +++ b/repos/gems/sculpt/depot/atopia/download @@ -0,0 +1 @@ +https://depot.genode.org diff --git a/repos/gems/sculpt/depot/atopia/pubkey b/repos/gems/sculpt/depot/atopia/pubkey new file mode 100644 index 0000000000..f59d385127 --- /dev/null +++ b/repos/gems/sculpt/depot/atopia/pubkey @@ -0,0 +1,52 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQINBGM9aNABEACdVjdMokz8NrtETaRd+ockpQpjeRg8KMRGxH7+p0lttJXjz6Cq +boZcor7nrvKMV8kXnHoJBvMZJvmxRZUnn/9yC8FzU1C2c8UAqJ7cWtQhZevrIMOp +KEufiOythb8ylGhomdyLjCDivsWnijW+Cy9TBQbQROZ54/L3mAv3uCkkbQbhs7Wg +hflEx78FiEDaoe0q/0jF0Argx4/t1ztnUHzyvnWU2VMITvzZcLiSZi49cwi5l6LH +jQHdtcMMMR5E8jWpEUOSBATWrp0gilt4IM0EDYq4OVwiehqR1sxBqZfzgbe+w+KH +IMxd16th2sQtt1ypXd27tts6xakchuWsZ7uH3T6KlLngdafvzfoy8KStppF8mkQK +QIpkgsW1OBRfveRJERAWYPMwAGVQUwyGXFq8d+bb2C9nvQz3S0WyyervMvaMtf8T +lrQL6gtKzyzFiog0i1zDbFtgSe0LmKANVStBnzXZPtHyCmdccvqTb5hyOT/FOe24 +nVDOMHTKSXZ18RkWBHyKCjJoSFOJMv2t2zzJkN90+dKrNrap9C9bGhZ51CxsnWv2 +RI++7fW5zYUW0yN0LwzPIvjRCX5EWkLj4jqgzWtgt/+eU6EPG2S3lkdFr9AIHa0Y +8SI/l1UHFlnfM9/Wzgk5c3/3Wfj6LGTvgyVE4AmdmUsg2HdlY6SUPbck+QARAQAB +tDVCZW5qYW1pbiBMYW1vd3NraSA8YmVuamFtaW4ubGFtb3dza2lAZ2Vub2RlLWxh +YnMuY29tPokCVAQTAQgAPhYhBG5FHmDqtr+LkCkQWni3QG21KBpNBQJjPWjQAhsD +BQkFo5qABQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJEHi3QG21KBpNdkIQAIG2 +nBKUXx+r2DsmgdGYr7q3GiwA23zLwhTae2zvVvpCk4qQZa0/hkfnVCSDY+Yo1amR +rQDMVSE+hbXsj05uNYAZITMeU61/8kJrwRQSQaTYKpfpvVOKTUpD+dWiFEzMiu6H +wYBcgyYfKAcmnPteM/puS41sPJBc2Av+vdzzHdW3ZzppBwGqJlHg8VctfyjkKIyT +FQNvwhEiT5/pvrPjUAZR31tYVxOGvdQRv2fn4zu+ySgTGYdnmCpY0Pxmu4nReZ5u +aIoettzlBWSZpWbTwPr5IseRnWTPaBNS2wUuG8CfA7DduCr61/mR3bPCBaRWqZsC +XM1Of56cPiYfBs/qUA/JIaSk+ISCd5sihgGuCwo0WRCLrsEP+/McEh4gbnsyrpoV +kBSy/2ipQASuMfUca2hmPK42VOVTVWt8rwHJ41DJocwkJa1wGzLvqXcDrZZvYMKE +946qvm3lJ8nBjH1z2vAyElRd66vzQIbQOrMW00NDMXNzDBP8UR8geo6lptk+nbfT +DZiRI3XsaGc8NvNKV83cQ/jxTbynlruY9KdJu+OUn7T4J3l7RZjMHIfMNYmURfKy +fwB53Gp/55fV/pyPw5fjk2PMb5+iNC4jP4HRcTzSGrexCHuEfKe1Jh9SdaysYyxt +IztFPdrqTMoUkW8pGYEC9HXz1uG38P59FvgYxNH8uQINBGM9aNABEADkwh2qneuZ +9OVScywMcsW3uXtheqmsllbUuAl2Xm/lhuKpHMDt43jUVXOoTIIqYIwtAAStfnHG +ytZVxSHk4HugIYqfI/jJesjPwDZnF8xjswaWKbqjn5e6o1poYqsSkH1HJxXgZ9Ui +WUqMPFaNm1XM12XS0eQy0gSwwGzXWplkkBx9l7cvqIQ3rNa9KOKbtn8T9lWdHVZ5 +4VzYAS7Y9eBIRbeJBBGg7iNYTQ/8SAX8T2LSLVpEBIILVrB2GLdOm+mIf21VGoEC +CD6AHORF26g6gTE+lQkE+jevSVZDrUYIbyFZ5mUiwPibYo1ITHlaPrzRNAAQIafz +vMMuMM+S6DgkXma2jbZXVHNfXF9FVkNSuWxIfxZVlCHXLZN1Ddp8eQhX6zbFcuLU +y1nPF22ReyqjlB2F4pWdWYbhb6bJoS1QFTKkOlwCsAUMNpCksYVDZnB+1XMBwEmE +/PhMgNLtrx3dCORRTJelv/PUOy1o0LcMPzf/hzB7pEUInncPN79lX4XOi8dfafhI +cw3721NTVES8Ru183/mHXaC+GcdC13pObLBDulJDadtYV8WLIBJbBmZSEYIstiJZ +/0d5hrphzknxdrlIKz2mVQWRcSsKkArx9Ve7VQH2tPcBm1iKZO2uKQDaCMglCEif +apZgoVHz7vBr+CAtWC30r1pme07QPjocrwARAQABiQI8BBgBCAAmFiEEbkUeYOq2 +v4uQKRBaeLdAbbUoGk0FAmM9aNACGwwFCQWjmoAACgkQeLdAbbUoGk0YCxAAlzlJ ++TLIv5cQlSP1C8PvSNZdvF8XzO2rI+vZrWS6+2i++oFZOReyvYAw2wNhP23fSWTl +LxO1sJ72+h+iNs/udNYnr1HdExIzrFQoJO8saPyV8cQLc8T8XgejyGK/FVwB8xiJ +jzSGjXsB2xNzet278FipLvwl2GQP0VyAxka5ZPaBQaB9cJOKjBl6cVC9TmGnGLin +sfwAEFHvdOK4JRAtpYvF5aQYlgSF2Dvh9hb93U4Z0CmjDhRlim4py13VZ4L9yZMO +scQr20iaGsfU6XNdQZWJ+gsEvWeNoUzH1gVci4uLgLkIDWrctXBUCnLx40HbrbOJ +EOZm1/2hjuHFjFHCxKKGCp8zyvcm2ZCkh1i8xPi2x/rl73WGlhDlxhPp3Ve+oZ6c +jdbOPe+csrnWRNijUNjib1Zhpr4fe9sTEorKrjVc6JpX3WtUvX5PvG6W8opeAP8p +1ec47MtonUfY8SE8a1OqRhHt4e95+mGGonUG4XLS9r572P1awvRvkGSqC8464082 +0iemYv6AKeOjWs6iCnmbBho+VNzJpr1L5Y3ciBIfQoMi8IWcDVYWTzv5pgPUBr0G +/CWd0Grbr6POJrzPJ+iQtAeuGZ/9tUVJH153qaVhwmJW4eb6qSXahAF72MDF8fdV +jmPs+5Q/o4+DWQ0O1pc55VlbrKXF4RFP9J1XJQo= +=TJqO +-----END PGP PUBLIC KEY BLOCK----- diff --git a/repos/gems/sculpt/fb/default b/repos/gems/sculpt/fb/default index f5ed6f1195..daa6eecd19 100644 --- a/repos/gems/sculpt/fb/default +++ b/repos/gems/sculpt/fb/default @@ -1,5 +1,3 @@ <config width="1024" height="768" max_width="3840" max_height="2160"> <report connectors="yes"/> - <!-- <connector name="eDP-1" width="1920" height="1080" enabled="true" brightness="75"/> --> - <!-- <connector name="HDMI-A-1" width="1024" height="768" hz="75" enabled="true"/> --> </config> diff --git a/repos/gems/sculpt/launcher/audio b/repos/gems/sculpt/launcher/audio index c4caf2f4c4..a0041920ed 100644 --- a/repos/gems/sculpt/launcher/audio +++ b/repos/gems/sculpt/launcher/audio @@ -13,6 +13,5 @@ <service name="Record"> <child name="mixer"/> </service> <service name="Play"> <child name="mixer"/> </service> <service name="Report"> <parent/> </service> - <service name="RM"> <parent/> </service> </route> </launcher> diff --git a/repos/gems/sculpt/launcher/test-capture b/repos/gems/sculpt/launcher/test-capture new file mode 100644 index 0000000000..708b5f98a5 --- /dev/null +++ b/repos/gems/sculpt/launcher/test-capture @@ -0,0 +1,9 @@ +<launcher name="test-capture" pkg="test-capture"> + <config period_ms="20" width="640" height="480"> + <view xpos="100" ypos="100"/> <!--view xpos="800" ypos="600"/--> + </config> + <route> + <service name="Capture"> <child name="webcam"/> </service> + <any-service> <parent/> </any-service> + </route> +</launcher> diff --git a/repos/gems/sculpt/launcher/test-vfs_capture b/repos/gems/sculpt/launcher/test-vfs_capture new file mode 100644 index 0000000000..7aaaeb09a6 --- /dev/null +++ b/repos/gems/sculpt/launcher/test-vfs_capture @@ -0,0 +1,10 @@ +<launcher name="test-vfs_capture" pkg="test-vfs_capture"> + <config period_ms="20" width="640" height="480"> + <vfs><dir name="dev"><capture/></dir></vfs> + <view xpos="100" ypos="100"/> <!--view xpos="800" ypos="600"/--> + </config> + <route> + <service name="Capture"> <child name="webcam"/> </service> + <any-service> <parent/> </any-service> + </route> +</launcher> diff --git a/repos/gems/sculpt/launcher/touchpad b/repos/gems/sculpt/launcher/touchpad index 65a2ac0b3b..6becbec54b 100644 --- a/repos/gems/sculpt/launcher/touchpad +++ b/repos/gems/sculpt/launcher/touchpad @@ -1,4 +1,4 @@ -<launcher pkg="chelmuth/pkg/pc_i2c_hid_drv/2024-04-24" priority="-1"> +<launcher pkg="chelmuth/pkg/pc_i2c_hid/2024-10-23" priority="-1"> <config info="Fujtisu U7411 (SYNAPTICS)"/> <!-- <config gpio_pin="266" bus_addr="21" hid_addr="1" info="Fujtisu U7511 (ELAN)"/> diff --git a/repos/gems/sculpt/leitzentrale/default b/repos/gems/sculpt/leitzentrale/default index 323b127b96..39d841370c 100644 --- a/repos/gems/sculpt/leitzentrale/default +++ b/repos/gems/sculpt/leitzentrale/default @@ -77,8 +77,8 @@ <resource name="RAM" quantum="33M"/> <resource name="CPU" quantum="20"/> <provides> <service name="Framebuffer"/> <service name="Input"/> </provides> - <config/> <route> + <service name="ROM" label="config"> <child name="report_rom"/> </service> <service name="Gui"> <child name="fader"/> </service> <any-service> <parent/> </any-service> </route> @@ -120,6 +120,7 @@ <policy label="manager -> window_list" report="wm -> window_list"/> <policy label="manager -> decorator_margins" report="decorator -> decorator_margins"/> <policy label="nitpicker -> focus" report="manager -> focus"/> + <policy label="gui_fb -> config" report="manager -> gui_fb_config"/> <policy label="runtime -> leitzentrale -> diag_dialog" report="manager -> diag_dialog"/> @@ -142,8 +143,8 @@ </config> </start> - <start name="wm" caps="300" priority="-1"> - <resource name="RAM" quantum="4M"/> + <start name="wm" caps="150" priority="-1"> + <resource name="RAM" quantum="2M"/> <provides> <service name="Gui"/> <service name="Report"/> <service name="ROM"/> </provides> @@ -160,7 +161,7 @@ </route> </start> - <start name="decorator" caps="400" priority="-1"> + <start name="decorator" caps="580" priority="-1"> <binary name="themed_decorator"/> <resource name="RAM" quantum="20M"/> <resource name="CPU" quantum="20"/> @@ -178,15 +179,15 @@ </dir> <dir name="dev"> <log/> </dir> </vfs> - <policy label="log" decoration="yes" motion="20"/> - <policy label="runtime -> leitzentrale -> settings_dialog" decoration="no" motion="20"/> - <policy label="runtime -> leitzentrale -> system_dialog" decoration="no" motion="20"/> - <policy label="runtime -> leitzentrale -> file_browser_dialog" decoration="no" motion="30"/> - <policy label="runtime -> leitzentrale -> network_dialog" decoration="no" motion="20"/> - <policy label="runtime -> leitzentrale -> runtime_dialog" decoration="no" motion="30"/> - <policy label="runtime -> leitzentrale -> diag_dialog" decoration="no" motion="30"/> - <policy label="runtime -> leitzentrale -> popup_dialog" decoration="no" motion="20"/> - <policy label="runtime -> leitzentrale -> panel_dialog" decoration="no" motion="20"/> + <policy label="log" decoration="yes" motion="40"/> + <policy label="runtime -> leitzentrale -> settings_dialog" decoration="no" motion="40"/> + <policy label="runtime -> leitzentrale -> system_dialog" decoration="no" motion="40"/> + <policy label="runtime -> leitzentrale -> file_browser_dialog" decoration="no" motion="60"/> + <policy label="runtime -> leitzentrale -> network_dialog" decoration="no" motion="40"/> + <policy label="runtime -> leitzentrale -> runtime_dialog" decoration="no" motion="60"/> + <policy label="runtime -> leitzentrale -> diag_dialog" decoration="no" motion="60"/> + <policy label="runtime -> leitzentrale -> popup_dialog" decoration="no" motion="40"/> + <policy label="runtime -> leitzentrale -> panel_dialog" decoration="no" motion="40"/> <policy label_prefix="logo" decoration="no"/> <default-policy/> </config> @@ -231,6 +232,8 @@ <child name="config_fs_report" label="managed -> nic_router"/> </service> <service name="Report" label="fb_config"> <child name="config_fs_report" label="managed -> fb"/> </service> + <service name="Report" label="nitpicker_config"> + <child name="config_fs_report" label="managed -> nitpicker"/> </service> <service name="Report" label="usb_config"> <child name="config_fs_report" label="managed -> usb"/> </service> <service name="Report" label="system_config"> @@ -264,7 +267,7 @@ </route> </start> - <start name="log_terminal" priority="-1"> + <start name="log_terminal" priority="-1" caps="120"> <binary name="terminal"/> <resource name="RAM" quantum="8M"/> <provides> <service name="Terminal"/> </provides> diff --git a/repos/gems/sculpt/nitpicker/default b/repos/gems/sculpt/nitpicker/default index f48a9807fe..b01371e294 100644 --- a/repos/gems/sculpt/nitpicker/default +++ b/repos/gems/sculpt/nitpicker/default @@ -1,6 +1,6 @@ <config focus="rom"> <capture/> <event/> - <report hover="yes" focus="yes" clicked="yes" keystate="no"/> + <report hover="yes" focus="yes" clicked="yes" keystate="no" panorama="yes"/> <background color="#000000"/> <domain name="overlay" layer="0" label="no" hover="always" focus="transient" content="client"/> @@ -15,7 +15,7 @@ <domain name="follow_touch" layer="6" origin="pointer" label="no" hover="always" content="client" focus="transient" width="720" height="960"/> <domain name="background" layer="7" content="client" label="no" hover="always" focus="transient" /> - <policy label_suffix="-> decorator" domain="decorator"/> + <policy label="runtime -> wm -> wm -> decorator" domain="decorator"/> <policy label_prefix="runtime -> wm" domain="desktop"/> <policy label_prefix="runtime -> themed_wm" domain="desktop"/> <policy label_prefix="runtime -> touch_keyboard" domain="touch_keyboard"/> diff --git a/repos/gems/sculpt/usb/webcam b/repos/gems/sculpt/usb/webcam new file mode 100644 index 0000000000..d940f995e6 --- /dev/null +++ b/repos/gems/sculpt/usb/webcam @@ -0,0 +1,25 @@ +<config bios_handoff="no"> + + <!-- available devices are listed at /report/runtime/usb/devices --> + + <policy label="webcam -> webcam -> usb_webcam -> "> + <device vendor_id="0x5986" product_id="0x366"/> <!-- Lenovo x250 --> + <device vendor_id="0x5986" product_id="0x706"/> <!-- Lenovo x260 --> + <device vendor_id="0x0bda" product_id="0x58db"/> <!-- Lenovo T470 --> + <device vendor_id="0x04f2" product_id="0xb564"/> <!-- Fujitsu S938 --> + + <!-- Logitec C920 --> + <!-- <device vendor_id="0x046d" product_id="0x8e5"/> --> + + <!-- Logitec C270 --> + <!-- <device vendor_id="0x046d" product_id="0x825"/> --> + + <!-- Quickcam --> + <!-- <device vendor_id="0x046d" product_id="0x9c1"/> --> + + <!-- Creative HD VF0770 --> + <!-- <device vendor_id="0x041e" product_id="0x4095"/> --> + </policy> + +</config> + diff --git a/repos/gems/sculpt/webcam-pc.sculpt b/repos/gems/sculpt/webcam-pc.sculpt new file mode 100644 index 0000000000..4a6427c561 --- /dev/null +++ b/repos/gems/sculpt/webcam-pc.sculpt @@ -0,0 +1,6 @@ +drivers: pc +ram_fs: depot +import: pkg/sculpt_drivers-pc pkg/test-capture pkg/test-vfs_capture +deploy: webcam +usb: webcam +launcher: test-capture test-vfs_capture diff --git a/repos/gems/sculpt/wifi/default b/repos/gems/sculpt/wifi/default index 361d2eaff4..6161e61352 100644 --- a/repos/gems/sculpt/wifi/default +++ b/repos/gems/sculpt/wifi/default @@ -1,3 +1,3 @@ -<wifi connected_scan_interval="0" scan_interval="5" rfkill="no" verbose="no"> - <network ssid="" protection="NONE" passphrase=""/> +<wifi scan_interval="5" rfkill="no" verbose="no"> + <!-- <network ssid="" protection="NONE" passphrase=""/> --> </wifi> diff --git a/repos/gems/src/app/backdrop/main.cc b/repos/gems/src/app/backdrop/main.cc index a78883ae4c..5333e63455 100644 --- a/repos/gems/src/app/backdrop/main.cc +++ b/repos/gems/src/app/backdrop/main.cc @@ -47,6 +47,8 @@ struct Backdrop::Main Gui::Connection _gui { _env, "backdrop" }; + Gui::Rect _gui_win { }; + struct Buffer { Gui::Connection &gui; @@ -59,18 +61,13 @@ struct Backdrop::Main Dataspace_capability _ds_cap(Gui::Connection &gui) { /* setup virtual framebuffer mode */ - gui.buffer(mode, false); + gui.buffer(mode); return gui.framebuffer.dataspace(); } Attached_dataspace fb_ds; - Genode::size_t surface_num_bytes() const - { - return size().count()*mode.bytes_per_pixel(); - } - Attached_ram_dataspace surface_ds; /** @@ -79,7 +76,7 @@ struct Backdrop::Main Buffer(Genode::Env &env, Gui::Connection &gui, Framebuffer::Mode mode) : gui(gui), mode(mode), fb_ds(env.rm(), _ds_cap(gui)), - surface_ds(env.ram(), env.rm(), surface_num_bytes()) + surface_ds(env.ram(), env.rm(), mode.num_bytes()) { } /** @@ -100,11 +97,10 @@ struct Backdrop::Main void flush_surface() { /* blit back to front buffer */ - blit(surface_ds.local_addr<void>(), - (unsigned)surface_num_bytes(), - fb_ds.local_addr<void>(), - (unsigned)surface_num_bytes(), - (unsigned)surface_num_bytes(), 1); + unsigned const num_bytes = unsigned(mode.num_bytes()); + blit(surface_ds.local_addr<void>(), num_bytes, + fb_ds.local_addr<void>(), num_bytes, + num_bytes, 1); } }; @@ -118,7 +114,7 @@ struct Backdrop::Main using Command = Gui::Session::Command; _gui.enqueue<Command::Background>(_view_id); - Gui::Rect rect(Gui::Point(), _buffer->size()); + Gui::Rect rect(_gui_win.at, _buffer->size()); _gui.enqueue<Command::Geometry>(_view_id, rect); _gui.enqueue<Command::Back>(_view_id); _gui.execute(); @@ -135,11 +131,6 @@ struct Backdrop::Main Signal_handler<Main> _config_handler = { _env.ep(), *this, &Main::_handle_config_signal }; - void _handle_sync(); - - Signal_handler<Main> _sync_handler = { - _env.ep(), *this, &Main::_handle_sync}; - template <typename PT> void _paint_texture(Surface<PT> &, Texture<PT> const &, Surface_base::Point, bool); @@ -150,8 +141,7 @@ struct Backdrop::Main { _gui.view(_view_id, { }); - _gui.mode_sigh(_config_handler); - + _gui.info_sigh(_config_handler); _config.sigh(_config_handler); _handle_config(); @@ -318,10 +308,14 @@ void Backdrop::Main::_handle_config() { _config.update(); - Framebuffer::Mode const phys_mode = _gui.mode(); - Framebuffer::Mode const - mode { .area = { _config.xml().attribute_value("width", phys_mode.area.w), - _config.xml().attribute_value("height", phys_mode.area.h) } }; + _gui_win = _gui.window().convert<Gui::Rect>( + [&] (Gui::Rect rect) { return rect; }, + [&] (Gui::Undefined) { return Gui::Rect { { }, { 640, 480 } }; }); + + _gui_win.area = { _config.xml().attribute_value("width", _gui_win.w()), + _config.xml().attribute_value("height", _gui_win.h()) }; + + Framebuffer::Mode const mode { .area = _gui_win.area, .alpha = false }; _buffer.construct(_env, _gui, mode); @@ -345,20 +339,10 @@ void Backdrop::Main::_handle_config() } }); - /* schedule buffer refresh */ - _gui.framebuffer.sync_sigh(_sync_handler); -} - - -void Backdrop::Main::_handle_sync() -{ Libc::with_libc([&] () { _buffer->flush_surface(); _update_view(); }); - - /* disable sync signal until the next call of 'handle_config' */ - _gui.framebuffer.sync_sigh(Signal_context_capability()); } diff --git a/repos/gems/src/app/decorator/main.cc b/repos/gems/src/app/decorator/main.cc index 43c284bf8e..7ec8beca58 100644 --- a/repos/gems/src/app/decorator/main.cc +++ b/repos/gems/src/app/decorator/main.cc @@ -17,6 +17,7 @@ #include <base/heap.h> #include <base/attached_rom_dataspace.h> #include <gui_session/connection.h> +#include <timer_session/connection.h> #include <os/pixel_rgb888.h> #include <os/reporter.h> @@ -39,37 +40,84 @@ struct Decorator::Main : Window_factory_base { Env &_env; + Timer::Connection _timer { _env }; + + /* + * Time base for animations, which are computed in steps of 10 ms + */ + struct Ticks { uint64_t cs; /* centi-seconds (10 ms) */ }; + + Ticks _now() + { + return { .cs = _timer.curr_time().trunc_to_plain_ms().value / 10 }; + } + Gui::Connection _gui { _env }; struct Canvas { - Framebuffer::Mode const mode; - Attached_dataspace fb_ds; - Decorator::Canvas<Pixel_rgb888> canvas; + Env &_env; + Gui::Connection &_gui; - Canvas(Env &env, Gui::Connection &gui) - : - mode(gui.mode()), - fb_ds(env.rm(), - (gui.buffer(mode, false), gui.framebuffer.dataspace())), - canvas(fb_ds.local_addr<Pixel_rgb888>(), mode.area, env.ram(), env.rm()) - { } + Gui::Area const scr_area = _gui.panorama().convert<Gui::Area>( + [&] (Gui::Rect rect) { return rect.area; }, + [&] (Gui::Undefined) { return Gui::Area { 1, 1 }; }); + + /* + * The GUI connection's buffer is split into two parts. The upper + * part contains the front buffer displayed by the GUI server + * whereas the lower part contains the back buffer targeted by + * the Decorator::Canvas. + */ + Dataspace_capability _buffer_ds() const + { + _gui.buffer({ .area = { .w = scr_area.w, .h = scr_area.h*2 }, + .alpha = false }); + return _gui.framebuffer.dataspace(); + } + + Attached_dataspace fb_ds { _env.rm(), _buffer_ds() }; + + Pixel_rgb888 *_canvas_pixels_ptr() + { + return fb_ds.local_addr<Pixel_rgb888>() + scr_area.count(); + } + + Decorator::Canvas<Pixel_rgb888> canvas { + _canvas_pixels_ptr(), scr_area, _env.ram(), _env.rm() }; + + Canvas(Env &env, Gui::Connection &gui) : _env(env), _gui(gui) { } }; Reconstructible<Canvas> _canvas { _env, _gui }; + void _back_to_front(Dirty_rect dirty) + { + if (!_canvas.constructed()) + return; + + Rect const canvas_rect { { }, _canvas->scr_area }; + + dirty.flush([&] (Rect const &r) { + + Rect const clipped = Rect::intersect(r, canvas_rect); + Point const from_p1 = clipped.p1() + Point { 0, int(canvas_rect.h()) }; + Point const to_p1 = clipped.p1(); + + _gui.framebuffer.blit({ from_p1, clipped.area }, to_p1); }); + } + Signal_handler<Main> _mode_handler { _env.ep(), *this, &Main::_handle_mode }; void _handle_mode() { _canvas.construct(_env, _gui); - _window_stack.mark_as_dirty(Rect(Point(0, 0), _canvas->mode.area)); + _window_stack.mark_as_dirty(Rect(Point(0, 0), _canvas->scr_area)); Dirty_rect dirty = _window_stack.draw(_canvas->canvas); - dirty.flush([&] (Rect const &r) { - _gui.framebuffer.refresh(r.x1(), r.y1(), r.w(), r.h()); }); + _back_to_front(dirty); } Window_stack _window_stack = { *this }; @@ -104,33 +152,26 @@ struct Decorator::Main : Window_factory_base Animator _animator { }; - /** - * Process the update every 'frame_period' GUI sync signals. The - * 'frame_cnt' holds the counter of the GUI sync signals. - * - * A lower 'frame_period' value makes the decorations more responsive - * but it also puts more load on the system. - * - * If the GUI sync signal fires every 10 milliseconds, a - * 'frame_period' of 2 results in an update rate of 1000/20 = 50 frames per - * second. - */ - unsigned _frame_cnt = 0; - unsigned _frame_period = 2; - - /** - * Install handler for responding to GUI sync events - */ - void _handle_gui_sync(); - - void _trigger_sync_handling() - { - _gui.framebuffer.sync_sigh(_gui_sync_handler); - } + Ticks _previous_sync { }; Signal_handler<Main> _gui_sync_handler = { _env.ep(), *this, &Main::_handle_gui_sync }; + void _handle_gui_sync(); + + bool _gui_sync_enabled = false; + + void _trigger_gui_sync() + { + Ticks const now = _now(); + bool const idle = now.cs - _previous_sync.cs > 3; + + if (!_gui_sync_enabled || idle) { + _previous_sync = now; + _gui_sync_handler.local_submit(); + } + } + Heap _heap { _env.ram(), _env.rm() }; Attached_rom_dataspace _config { _env, "config" }; @@ -150,7 +191,7 @@ struct Decorator::Main : Window_factory_base _config.sigh(_config_handler); _handle_config(); - _gui.mode_sigh(_mode_handler); + _gui.info_sigh(_mode_handler); _window_layout.sigh(_window_layout_handler); _pointer.sigh(_pointer_handler); @@ -267,16 +308,15 @@ void Decorator::Main::_handle_window_layout_update() _window_layout_update_needed = true; - _trigger_sync_handling(); + _trigger_gui_sync(); } void Decorator::Main::_handle_gui_sync() { - if (_frame_cnt++ < _frame_period) - return; + Ticks const now = _now(); - _frame_cnt = 0; + Ticks const passed_ticks { now.cs - _previous_sync.cs }; bool model_updated = false; @@ -300,31 +340,34 @@ void Decorator::Main::_handle_gui_sync() bool const windows_animated = _window_stack.schedule_animated_windows(); - /* - * To make the perceived animation speed independent from the setting of - * 'frame_period', we update the animation as often as the GUI - * sync signal occurs. - */ - for (unsigned i = 0; i < _frame_period; i++) + for (unsigned i = 0; i < passed_ticks.cs; i++) _animator.animate(); - if (!model_updated && !windows_animated) - return; + if (model_updated || windows_animated) { - Dirty_rect dirty = _window_stack.draw(_canvas->canvas); + Dirty_rect dirty = _window_stack.draw(_canvas->canvas); + _back_to_front(dirty); - _window_stack.update_gui_views(); - - _gui.execute(); - - dirty.flush([&] (Rect const &r) { - _gui.framebuffer.refresh(r.x1(), r.y1(), r.w(), r.h()); }); + _window_stack.update_gui_views(); + _gui.execute(); + } /* - * Disable sync handling when becoming idle + * Enable/disable periodic sync depending on animation state */ - if (!_animator.active()) - _gui.framebuffer.sync_sigh(Signal_context_capability()); + if (_gui_sync_enabled) { + if (!_animator.active()) { + _gui.framebuffer.sync_sigh(Signal_context_capability()); + _gui_sync_enabled = false; + } + } else { + if (_animator.active()) { + _gui.framebuffer.sync_sigh(_gui_sync_handler); + _gui_sync_enabled = true; + } + } + + _previous_sync = now; } diff --git a/repos/gems/src/app/decorator/window_element.h b/repos/gems/src/app/decorator/window_element.h index 6865fb5f17..d51cf99b71 100644 --- a/repos/gems/src/app/decorator/window_element.h +++ b/repos/gems/src/app/decorator/window_element.h @@ -99,10 +99,10 @@ class Decorator::Window_element : public Animator::Item /* medium fade-in when gaining the focus or hover highlight */ if ((!_state.focused && state.focused) || (!_state.highlighted && state.highlighted)) - return 15; + return 30; /* slow fade-out when leaving focus or hover highlight */ - return 20; + return 40; } public: diff --git a/repos/gems/src/app/file_vault_gui/target.mk b/repos/gems/src/app/file_vault_gui/target.mk index 895dbff4cc..dea67fd30b 100644 --- a/repos/gems/src/app/file_vault_gui/target.mk +++ b/repos/gems/src/app/file_vault_gui/target.mk @@ -1,6 +1,6 @@ TARGET = file_vault_gui SRC_CC = main.cc -LIBS += base dialog +LIBS += base dialog sandbox INC_DIR += $(call select_from_repositories,/src/app/file_vault/include) INC_DIR += $(call select_from_repositories,/src/lib/tresor/include) diff --git a/repos/gems/src/app/fs_query/for_each_subdir_name.h b/repos/gems/src/app/fs_query/for_each_subdir_name.h index 3a300f33bd..be20df8676 100644 --- a/repos/gems/src/app/fs_query/for_each_subdir_name.h +++ b/repos/gems/src/app/fs_query/for_each_subdir_name.h @@ -16,9 +16,7 @@ /* Genode includes */ #include <os/vfs.h> - -/* local includes */ -#include <sorted_for_each.h> +#include <util/dictionary.h> namespace Genode { @@ -31,43 +29,35 @@ template <typename FN> static void Genode::for_each_subdir_name(Allocator &alloc, Directory const &dir, FN const &fn) { - using Dirname = Directory::Entry::Name; + using Name = Directory::Entry::Name; - struct Name : Interface, private Dirname + struct Dirname : Dictionary<Dirname, Name>::Element { - using Dirname::string; - - Name(Dirname const &name) : Dirname(name) { } - - bool higher(Name const &other) const - { - return (strcmp(other.string(), string()) > 0); - } + Dirname(Dictionary<Dirname, Name> & dict, Name const & name) + : Dictionary<Dirname, Name>::Element(dict, name) + { } }; - /* obtain list of sub directory names */ - Registry<Registered<Name>> names { }; + /* obtain dictionary of sub directory names */ + Dictionary<Dirname, Name> names { }; dir.for_each_entry([&] (Directory::Entry const &entry) { if (entry.dir()) - new (alloc) Registered<Name>(names, entry.name()); }); + new (alloc) Dirname(names, entry.name()); }); - auto destroy_names = [&] () - { - names.for_each([&] (Registered<Name> &name) { - destroy(alloc, &name); }); - }; + auto destroy_element = [&] (Dirname &element) { + destroy(alloc, &element); }; - /* iterate over sorted list */ + /* iterate over dictionary */ try { - sorted_for_each(alloc, names, [&] (Name const &name) { - fn(name.string()); }); + names.for_each([&] (Dirname const &element) { + fn(element.name.string()); }); } catch (...) { - destroy_names(); + while (names.with_any_element(destroy_element)) { } throw; } - destroy_names(); + while (names.with_any_element(destroy_element)) { } } #endif /* _FOR_EACH_SUBDIR_NAME_H_ */ diff --git a/repos/gems/src/app/fs_query/main.cc b/repos/gems/src/app/fs_query/main.cc index 0d23332a93..2438c2484c 100644 --- a/repos/gems/src/app/fs_query/main.cc +++ b/repos/gems/src/app/fs_query/main.cc @@ -21,6 +21,7 @@ #include <os/vfs.h> /* local includes */ +#include <sorted_for_each.h> #include <for_each_subdir_name.h> namespace Fs_query { @@ -39,10 +40,9 @@ struct Fs_query::Watched_file /** * Support for 'sorted_for_each' */ - bool higher(Watched_file const &other) const - { - return (strcmp(other._name.string(), _name.string()) > 0); - } + using Name = File_content::Path; + + Name const &name() const { return _name; } Node_rwx const _rwx; diff --git a/repos/gems/src/app/fs_query/sorted_for_each.h b/repos/gems/src/app/fs_query/sorted_for_each.h index a4f4c5dd05..ce27eae757 100644 --- a/repos/gems/src/app/fs_query/sorted_for_each.h +++ b/repos/gems/src/app/fs_query/sorted_for_each.h @@ -16,6 +16,7 @@ #include <base/registry.h> #include <base/allocator.h> +#include <util/dictionary.h> namespace Genode { template <typename T, typename FN> @@ -26,55 +27,52 @@ namespace Genode { /** * Execute 'fn' for each registry element * - * The type T must be equipped with a method that defines the sort criterion: + * The type T must be equipped with a method name() and a type Name: * - * bool higher(T const &other) const + * const & Name name() const * - * It must implement a strict order over all registry elements. E.g., if the - * registry contains a set of names, no name must occur twice. The allocator - * passed as 'alloc' is used to for temporary allocations. + * The allocator passed as 'alloc' is used to for temporary allocations. */ template <typename T, typename FN> static inline void Genode::sorted_for_each(Allocator &alloc, Registry<T> const ®istry, FN const &fn) { - struct Sorted_item : Avl_node<Sorted_item> + using Name = T::Name; + struct SortedItem : Dictionary<SortedItem, Name>::Element { T const &element; - Sorted_item(T const &element) : element(element) { } - - bool higher(Sorted_item const *item) const - { - return item ? element.higher(item->element) : false; - } + SortedItem(Dictionary<SortedItem, Name> & dict, Name const & name, T const & element) + : Dictionary<SortedItem, Name>::Element(dict, name), + element(element) + { } }; - /* build temporary AVL tree of sorted elements */ - Avl_tree<Sorted_item> sorted { }; + /* build temporary Dictionary of sorted and unique elements */ + using Dict = Dictionary<SortedItem, Name>; + Dict sorted { }; registry.for_each([&] (T const &element) { - sorted.insert(new (alloc) Sorted_item(element)); }); + /* skip duplicates */ + if (sorted.exists(element.name())) return; - auto destroy_sorted = [&] () - { - while (Sorted_item *item = sorted.first()) { - sorted.remove(item); - destroy(alloc, item); - } - }; + new (alloc) SortedItem(sorted, element.name(), element); + }); + + auto destroy_element = [&] (SortedItem &item) { + destroy(alloc, &item); }; /* iterate over sorted elements, 'fn' may throw */ try { - sorted.for_each([&] (Sorted_item const &item) { + sorted.for_each([&] (SortedItem const &item) { fn(item.element); }); } catch (...) { - destroy_sorted(); + while (sorted.with_any_element(destroy_element)) { } throw; } - destroy_sorted(); + while (sorted.with_any_element(destroy_element)) { } } #endif /* _SORTED_FOR_EACH_H_ */ diff --git a/repos/gems/src/app/menu_view/button_widget.h b/repos/gems/src/app/menu_view/button_widget.h index 4d8f4bf6e8..016c1214ab 100644 --- a/repos/gems/src/app/menu_view/button_widget.h +++ b/repos/gems/src/app/menu_view/button_widget.h @@ -85,7 +85,7 @@ struct Menu_view::Button_widget : Widget, Animator::Item * or changing the selection state of a button, the transition * must be quick to provide a responsive feel. */ - enum { SLOW = 80, MEDIUM = 40, FAST = 3 }; + enum { SLOW = 40, MEDIUM = 20, FAST = 2 }; int steps = SLOW; if (_hovered && !new_hovered) steps = MEDIUM; if (!_hovered && new_hovered) steps = FAST; diff --git a/repos/gems/src/app/menu_view/cursor.h b/repos/gems/src/app/menu_view/cursor.h index 9b0c8b5dde..981a88232c 100644 --- a/repos/gems/src/app/menu_view/cursor.h +++ b/repos/gems/src/app/menu_view/cursor.h @@ -70,7 +70,7 @@ class Menu_view::Cursor : List_model<Cursor>::Element void _move_to(int position, Steps steps) { - _position.move_to(Rect::compound(Point(position, 0), Point()), steps); + _position.move_to(Rect { { position, 0 }, { 1, 1 } }, steps); } /* @@ -122,7 +122,7 @@ class Menu_view::Cursor : List_model<Cursor>::Element void update(Xml_node const &node) { - _move_to(_position_from_xml_node(node), Steps{12}); + _move_to(_position_from_xml_node(node), Steps{6}); } }; diff --git a/repos/gems/src/app/menu_view/dialog.h b/repos/gems/src/app/menu_view/dialog.h index 8e61fa020e..80cc7e0e78 100644 --- a/repos/gems/src/app/menu_view/dialog.h +++ b/repos/gems/src/app/menu_view/dialog.h @@ -47,9 +47,9 @@ struct Menu_view::Dialog : List_model<Dialog>::Element struct Action : Interface { - virtual void trigger_redraw() = 0; virtual void hover_changed() = 0; virtual void observed_seq_number(Input::Seq_number) = 0; + virtual Ticks now() = 0; }; Action &_action; @@ -72,6 +72,15 @@ struct Menu_view::Dialog : List_model<Dialog>::Element void _handle_input(); + Signal_handler<Dialog> _gui_sync_handler { + _env.ep(), *this, &Dialog::_handle_gui_sync }; + + void _handle_gui_sync(); + + bool _gui_sync_enabled = false; + + Ticks _previous_sync { }; + Constructible<Gui_buffer> _buffer { }; Gui::View_ref _view_ref { }; @@ -151,7 +160,7 @@ struct Menu_view::Dialog : List_model<Dialog>::Element _root_widget.gen_hover_model(xml, _hovered_position); } - void redraw() + void _redraw() { if (!_redraw_scheduled) return; @@ -182,7 +191,7 @@ struct Menu_view::Dialog : List_model<Dialog>::Element }); _buffer->flush_surface(); - _gui.framebuffer.refresh(0, 0, _buffer->size().w, _buffer->size().h); + _gui.framebuffer.refresh({ { 0, 0 }, _buffer->size() }); _update_view(Rect(_position, size)); _redraw_scheduled = false; @@ -190,7 +199,7 @@ struct Menu_view::Dialog : List_model<Dialog>::Element bool hovered() const { return _hovered; } - void animate() + void _animate() { bool const progress = _local_animator.active(); @@ -200,9 +209,14 @@ struct Menu_view::Dialog : List_model<Dialog>::Element _redraw_scheduled = true; } - bool animation_in_progress() const { return _local_animator.active(); } + void enforce_font_sytle_change() + { + _handle_dialog(); - bool redraw_scheduled() const { return _redraw_scheduled; } + /* fast-forward geometry animation */ + while (_local_animator.active()) + _animate(); + } /* * List_model @@ -214,10 +228,22 @@ struct Menu_view::Dialog : List_model<Dialog>::Element void update(Xml_node const &node) { + Point const orig_position = _position; + Area const orig_configured_size = _configured_size; + bool const orig_opaque = _opaque; + Color const orig_background_color = _background_color; + _position = Point::from_xml(node); _configured_size = Area ::from_xml(node); _opaque = node.attribute_value("opaque", false); _background_color = node.attribute_value("background", Color(127, 127, 127, 255)); + + bool const any_change = (orig_position != _position + || orig_configured_size != _configured_size + || orig_opaque != _opaque + || orig_background_color != _background_color); + if (any_change) + _dialog_handler.local_submit(); } }; @@ -237,7 +263,14 @@ void Menu_view::Dialog::_handle_dialog() _redraw_scheduled = true; _action.hover_changed(); - _action.trigger_redraw(); + + if (!_gui_sync_enabled) { + _previous_sync = _action.now(); + _gui.framebuffer.sync_sigh(_gui_sync_handler); + _gui_sync_enabled = true; + } + + _redraw(); } @@ -287,4 +320,25 @@ void Menu_view::Dialog::_handle_input() _action.hover_changed(); } + +void Menu_view::Dialog::_handle_gui_sync() +{ + Ticks const now = _action.now(); + + Ticks const passed_ticks { now.cs - _previous_sync.cs }; + + for (unsigned i = 0; i < passed_ticks.cs; i++) + _animate(); + + if (passed_ticks.cs) + _redraw(); + + /* deactivate sync signalling when idle */ + if (_gui_sync_enabled && !_local_animator.active()) { + _gui.framebuffer.sync_sigh(Signal_context_capability()); + _gui_sync_enabled = false; + } + _previous_sync = now; +} + #endif /* _DIALOG_H_ */ diff --git a/repos/gems/src/app/menu_view/label_widget.h b/repos/gems/src/app/menu_view/label_widget.h index b640ec5d01..817bdc00fc 100644 --- a/repos/gems/src/app/menu_view/label_widget.h +++ b/repos/gems/src/app/menu_view/label_widget.h @@ -89,7 +89,7 @@ struct Menu_view::Label_widget : Widget, Cursor::Glyph_position _hover = node.attribute_value("hover", false); _factory.styles.with_label_style(node, [&] (Label_style style) { - _color.fade_to(style.color, Animated_color::Steps{80}); }); + _color.fade_to(style.color, Animated_color::Steps{40}); }); if (node.has_attribute("text")) { _text = node.attribute_value("text", _text); diff --git a/repos/gems/src/app/menu_view/main.cc b/repos/gems/src/app/menu_view/main.cc index e220ad1cc8..dee982d66a 100644 --- a/repos/gems/src/app/menu_view/main.cc +++ b/repos/gems/src/app/menu_view/main.cc @@ -83,45 +83,14 @@ struct Menu_view::Main : Dialog::Action } _input_seq_number { }; - struct Frame { uint64_t count; }; - - /* - * Timer used for animating widgets - */ - struct Frame_timer : Timer::Connection - { - enum { PERIOD = 10 }; - - Frame curr_frame() const { return { elapsed_ms() / PERIOD }; } - - void schedule() { trigger_once((Genode::uint64_t)Frame_timer::PERIOD*1000); } - - Frame_timer(Env &env) : Timer::Connection(env) { } - - } _timer { _env }; - - void _handle_frame_timer(); + Timer::Connection _timer { _env }; /** * Dialog::Action */ - void trigger_redraw() override + Ticks now() override { - /* - * If we have not processed a period for at least one frame, perform the - * processing immediately. This way, we avoid latencies when the dialog - * model is updated sporadically. - */ - Frame const curr_frame = _timer.curr_frame(); - if (curr_frame.count != _last_frame.count) { - - if (curr_frame.count - _last_frame.count > 10) - _last_frame = curr_frame; - - _handle_frame_timer(); - } else { - _timer.schedule(); - } + return { .cs = _timer.curr_time().trunc_to_plain_ms().value / 10 }; } /** @@ -137,38 +106,16 @@ struct Menu_view::Main : Dialog::Action _input_seq_number.update(seq); } - Signal_handler<Main> _frame_timer_handler = { - _env.ep(), *this, &Main::_handle_frame_timer}; - Constructible<Genode::Expanding_reporter> _hover_reporter { }; void _update_hover_report(); - /** - * Frame of last call of 'handle_frame_timer' - */ - Frame _last_frame { }; - - /** - * Number of frames between two redraws - */ - static constexpr unsigned REDRAW_PERIOD = 2; - - /** - * Counter used for triggering redraws. Incremented in each frame-timer - * period, wraps at 'REDRAW_PERIOD'. The redraw is performed when the - * counter wraps. - */ - unsigned _frame_cnt = 0; - Main(Env &env, Vfs::Env &libc_vfs_env) : _env(env), _vfs_env(libc_vfs_env) { _config.sigh(_config_handler); _config_handler.local_submit(); /* apply initial configuration */ - - _timer.sigh(_frame_timer_handler); } }; @@ -239,57 +186,10 @@ void Menu_view::Main::_handle_config() /* re-assign font pointers in labels (needed due to font style change) */ if (!_styles.up_to_date()) { _dialogs.for_each([&] (Dialog &dialog) { - dialog._handle_dialog(); - - /* fast-forward geometry animation on font changes */ - while (dialog.animation_in_progress()) - dialog.animate(); - }); + dialog.enforce_font_sytle_change(); }); _styles.flush_outdated_styles(); } - trigger_redraw(); -} - - -void Menu_view::Main::_handle_frame_timer() -{ - _frame_cnt++; - - Frame const curr_frame = _timer.curr_frame(); - - unsigned const passed_frames = - max(unsigned(curr_frame.count - _last_frame.count), 4U); - - if (passed_frames > 0) - _dialogs.for_each([&] (Dialog &dialog) { - for (unsigned i = 0; i < passed_frames; i++) - dialog.animate(); }); - - bool any_redraw_scheduled = false; - _dialogs.for_each([&] (Dialog const &dialog) { - any_redraw_scheduled |= dialog.redraw_scheduled(); }); - - _last_frame = curr_frame; - - bool const redraw_skipped = any_redraw_scheduled && (_frame_cnt < REDRAW_PERIOD); - - if (!redraw_skipped) { - _frame_cnt = 0; - _dialogs.for_each([&] (Dialog &dialog) { - dialog.redraw(); }); - } - - bool any_animation_in_progress = false; - _dialogs.for_each([&] (Dialog const &dialog) { - any_animation_in_progress |= dialog.animation_in_progress(); }); - - /* - * Deactivate timer periods when idle, activate timer when an animation is - * in progress or a redraw is pending. - */ - if (any_animation_in_progress || redraw_skipped) - _timer.schedule(); } diff --git a/repos/gems/src/app/menu_view/styles/button/vconn/default.png b/repos/gems/src/app/menu_view/styles/button/vconn/default.png new file mode 100644 index 0000000000..0cc68605fa Binary files /dev/null and b/repos/gems/src/app/menu_view/styles/button/vconn/default.png differ diff --git a/repos/gems/src/app/menu_view/styles/button/vconn/hovered.png b/repos/gems/src/app/menu_view/styles/button/vconn/hovered.png new file mode 100644 index 0000000000..be207ad270 Binary files /dev/null and b/repos/gems/src/app/menu_view/styles/button/vconn/hovered.png differ diff --git a/repos/gems/src/app/menu_view/styles/button/vconn/hselected.png b/repos/gems/src/app/menu_view/styles/button/vconn/hselected.png new file mode 100644 index 0000000000..b55edb0672 Binary files /dev/null and b/repos/gems/src/app/menu_view/styles/button/vconn/hselected.png differ diff --git a/repos/gems/src/app/menu_view/styles/button/vconn/selected.png b/repos/gems/src/app/menu_view/styles/button/vconn/selected.png new file mode 100644 index 0000000000..ac09f5e328 Binary files /dev/null and b/repos/gems/src/app/menu_view/styles/button/vconn/selected.png differ diff --git a/repos/gems/src/app/menu_view/styles/button/vswap/default.png b/repos/gems/src/app/menu_view/styles/button/vswap/default.png new file mode 100644 index 0000000000..4139170a3a Binary files /dev/null and b/repos/gems/src/app/menu_view/styles/button/vswap/default.png differ diff --git a/repos/gems/src/app/menu_view/styles/button/vswap/hovered.png b/repos/gems/src/app/menu_view/styles/button/vswap/hovered.png new file mode 100644 index 0000000000..8f1a555a62 Binary files /dev/null and b/repos/gems/src/app/menu_view/styles/button/vswap/hovered.png differ diff --git a/repos/gems/src/app/menu_view/styles/button/vswap/hselected.png b/repos/gems/src/app/menu_view/styles/button/vswap/hselected.png new file mode 100644 index 0000000000..8fb1b960a8 Binary files /dev/null and b/repos/gems/src/app/menu_view/styles/button/vswap/hselected.png differ diff --git a/repos/gems/src/app/menu_view/styles/button/vswap/selected.png b/repos/gems/src/app/menu_view/styles/button/vswap/selected.png new file mode 100644 index 0000000000..68f49c25f0 Binary files /dev/null and b/repos/gems/src/app/menu_view/styles/button/vswap/selected.png differ diff --git a/repos/gems/src/app/menu_view/types.h b/repos/gems/src/app/menu_view/types.h index a2cf878a0f..10449caafe 100644 --- a/repos/gems/src/app/menu_view/types.h +++ b/repos/gems/src/app/menu_view/types.h @@ -36,6 +36,8 @@ namespace Menu_view { using Point = Surface_base::Point; using Area = Surface_base::Area; using Rect = Surface_base::Rect; + + struct Ticks { uint64_t cs; /* centi-seconds (10 ms) */ }; } #endif /* _TYPES_H_ */ diff --git a/repos/gems/src/app/menu_view/widget.h b/repos/gems/src/app/menu_view/widget.h index 2c2fa64a0d..9b5d01de77 100644 --- a/repos/gems/src/app/menu_view/widget.h +++ b/repos/gems/src/app/menu_view/widget.h @@ -110,7 +110,7 @@ class Menu_view::Widget : List_model<Widget>::Element return node.attribute_value("version", Version()); } - static Animated_rect::Steps motion_steps() { return { 60 }; }; + static Animated_rect::Steps motion_steps() { return { 30 }; }; protected: diff --git a/repos/gems/src/app/osci/main.cc b/repos/gems/src/app/osci/main.cc index 2a70ec9e9f..ccdd089209 100644 --- a/repos/gems/src/app/osci/main.cc +++ b/repos/gems/src/app/osci/main.cc @@ -159,7 +159,7 @@ struct Osci::Main _gui_buffer->flush_surface(); - _gui.framebuffer.refresh(0, 0, _size.w, _size.h); + _gui.framebuffer.refresh({ { 0, 0 }, _size }); } Main(Env &env) : _env(env) diff --git a/repos/gems/src/app/phone_manager/main.cc b/repos/gems/src/app/phone_manager/main.cc index 9e8f23da72..d95bb59d93 100644 --- a/repos/gems/src/app/phone_manager/main.cc +++ b/repos/gems/src/app/phone_manager/main.cc @@ -210,6 +210,8 @@ struct Sculpt::Main : Input_event_handler, .mmc = false, .modem = false, /* depends on presence of battery */ .nic = false, + + .fb_on_dedicated_cpu = false }; Drivers _drivers { _env, _child_states, *this, *this }; @@ -376,10 +378,11 @@ struct Sculpt::Main : Input_event_handler, */ bool ap_list_hovered() const override { - return _main_view.if_hovered([&] (Hovered_at const &at) { - return _network_widget.if_hovered(at, [&] (Hovered_at const &at) { - return _network_widget.hosted.if_hovered(at, [&] (Hovered_at const &at) { - return _network_widget.hosted.ap_list_hovered(at); }); }); }); + /* + * For now always report false so that scan-results + * will always be presented. + */ + return false; } /** @@ -650,6 +653,8 @@ struct Sculpt::Main : Input_event_handler, bool _leitzentrale_visible = false; + Fb_connectors::Name _hovered_display { }; + Color const _background_color { 62, 62, 67, 255 }; Affinity::Space _affinity_space { 1, 1 }; @@ -811,8 +816,8 @@ struct Sculpt::Main : Input_event_handler, Conditional_widget<Graph> _graph { Id { "graph" }, _runtime_state, _cached_runtime_config, _storage._storage_devices, - _storage._selected_target, _storage._ram_fs_state, - _popup.state, _deploy._children }; + _storage._selected_target, _storage._ram_fs_state, _fb_connectors, + _fb_config, _hovered_display, _popup.state, _deploy._children }; Conditional_widget<Network_widget> _network_widget { Conditional_widget<Network_widget>::Attr { .centered = true }, @@ -1994,6 +1999,30 @@ struct Sculpt::Main : Input_event_handler, } + /********************************** + ** Display driver configuration ** + **********************************/ + + Fb_connectors _fb_connectors { }; + + Fb_config _fb_config { }; + + /** + * Fb_driver::Action interface + */ + void fb_connectors_changed() override { } + + /** + * Fb_widget::Action interface + */ + void select_fb_mode (Fb_connectors::Name const &, + Fb_connectors::Connector::Mode::Id const &) override { } + void disable_fb_connector (Fb_connectors::Name const &) override { } + void toggle_fb_merge_discrete(Fb_connectors::Name const &) override { } + void swap_fb_connector (Fb_connectors::Name const &) override { } + void fb_brightness (Fb_connectors::Name const &, unsigned) override { } + + /******************* ** Runtime graph ** *******************/ @@ -2007,7 +2036,7 @@ struct Sculpt::Main : Input_event_handler, _drivers.update_soc(_soc); _gui.input.sigh(_input_handler); - _gui.mode_sigh(_gui_mode_handler); + _gui.info_sigh(_gui_mode_handler); _handle_gui_mode(); _system_config.with_manual_config([&] (Xml_node const &system) { @@ -2078,12 +2107,6 @@ void Sculpt::Main::_update_window_layout(Xml_node const &decorator_margins, return Area(win.attribute_value("width", 0U), win.attribute_value("height", 0U)); }; - Framebuffer::Mode const mode = _gui.mode(); - - /* suppress intermediate boot-time states before the framebuffer driver is up */ - if (mode.area.count() <= 1) - return; - _window_layout.generate([&] (Xml_generator &xml) { auto gen_window = [&] (Xml_node win, Rect rect) { @@ -2105,8 +2128,8 @@ void Sculpt::Main::_update_window_layout(Xml_node const &decorator_margins, Area const size = win_size(win); Point const pos = _touch_keyboard.visible - ? Point(0, int(mode.area.h) - int(size.h)) - : Point(0, int(mode.area.h)); + ? Point(0, int(_screen_size.h) - int(size.h)) + : Point(0, int(_screen_size.h)); gen_window(win, Rect(pos, size)); }); @@ -2122,16 +2145,19 @@ void Sculpt::Main::_update_window_layout(Xml_node const &decorator_margins, void Sculpt::Main::_handle_gui_mode() { - Framebuffer::Mode const mode = _gui.mode(); + auto const panorama = _gui.panorama(); - _screensaver.display_driver_ready(mode.area.count() > 1); + _screensaver.display_driver_ready(panorama.ok()); - if (mode.area.count() > 1) - _gui_mode_ready = true; - - _screen_size = mode.area; - _main_view.min_width = _screen_size.w; - _main_view.min_height = _screen_size.h; + panorama.with_result( + [&] (Gui::Rect const rect) { + _gui_mode_ready = true; + _screen_size = rect.area; + _main_view.min_width = _screen_size.w; + _main_view.min_height = _screen_size.h; + }, + [&] (Gui::Undefined) { } + ); generate_runtime_config(); _update_window_layout(); diff --git a/repos/gems/src/app/rom_osci/main.cc b/repos/gems/src/app/rom_osci/main.cc index 16c4d492e6..9d5ee4aeb4 100644 --- a/repos/gems/src/app/rom_osci/main.cc +++ b/repos/gems/src/app/rom_osci/main.cc @@ -305,7 +305,7 @@ struct Osci::Main channel.render(pixel, alpha, phase_lock); }); }); _gui_buffer->flush_surface(); - _gui.framebuffer.refresh(0, 0, _size.w, _size.h); + _gui.framebuffer.refresh({ { 0, 0 }, _size }); } Main(Env &env) : _env(env) diff --git a/repos/gems/src/app/sculpt_manager/deploy.h b/repos/gems/src/app/sculpt_manager/deploy.h index 2db79f9e49..b2aeed5432 100644 --- a/repos/gems/src/app/sculpt_manager/deploy.h +++ b/repos/gems/src/app/sculpt_manager/deploy.h @@ -65,6 +65,7 @@ struct Sculpt::Deploy _child_states, { .name = "depot_rom", .priority = Priority::STORAGE, .cpu_quota = 0, + .location = { }, .initial = { Ram_quota{24*1024*1024}, Cap_quota{200} }, .max = { Ram_quota{2*1024*1024*1024UL}, { } } } }; @@ -72,6 +73,7 @@ struct Sculpt::Deploy _child_states, { .name = "dynamic_depot_rom", .priority = Priority::STORAGE, .cpu_quota = 0, + .location = { }, .initial = { Ram_quota{8*1024*1024}, Cap_quota{200} }, .max = { Ram_quota{2*1024*1024*1024UL}, { } } } }; @@ -263,6 +265,9 @@ struct Sculpt::Deploy void restart() { + cached_depot_rom_state .trigger_restart(); + uncached_depot_rom_state.trigger_restart(); + /* ignore stale query results */ _depot_query.trigger_depot_query(); diff --git a/repos/gems/src/app/sculpt_manager/dialog/distant_runtime.h b/repos/gems/src/app/sculpt_manager/dialog/distant_runtime.h index 850c153e3e..f0063b9f2f 100644 --- a/repos/gems/src/app/sculpt_manager/dialog/distant_runtime.h +++ b/repos/gems/src/app/sculpt_manager/dialog/distant_runtime.h @@ -53,7 +53,7 @@ class Dialog::Distant_runtime : Noncopyable Start_name const _start_name { "runtime_view" }; Ram_quota const _initial_ram { 52*1024*1024 }; - Cap_quota const _initial_caps { 300 }; + Cap_quota const _initial_caps { 330 }; Ram_quota _ram = _initial_ram; Cap_quota _caps = _initial_caps; @@ -105,7 +105,7 @@ class Dialog::Distant_runtime : Noncopyable return false; if (child.has_sub_node("ram") && child.sub_node("ram").has_attribute("requested")) { - _ram.value = min(2*_ram.value, 32*1024*1024u); + _ram.value = min(2*_ram.value, 128*1024*1024u); result = true; } diff --git a/repos/gems/src/app/sculpt_manager/driver/fb.h b/repos/gems/src/app/sculpt_manager/driver/fb.h index bbc4d1f8c2..4962d7489c 100644 --- a/repos/gems/src/app/sculpt_manager/driver/fb.h +++ b/repos/gems/src/app/sculpt_manager/driver/fb.h @@ -14,24 +14,50 @@ #ifndef _DRIVER__FB_H_ #define _DRIVER__FB_H_ +#include <i2c_session/i2c_session.h> + namespace Sculpt { struct Fb_driver; } struct Sculpt::Fb_driver : private Noncopyable { + using Fb_name = String<16>; + + struct Action : Interface + { + virtual void fb_connectors_changed() = 0; + }; + + Env &_env; + Action &_action; + Constructible<Child_state> _intel_gpu { }, _intel_fb { }, _vesa_fb { }, _boot_fb { }, _soc_fb { }; + Constructible<Rom_handler<Fb_driver>> _connectors { }; + + void _handle_connectors(Xml_node const &) { _action.fb_connectors_changed(); } + + Fb_name _fb_name() const + { + return _intel_fb.constructed() ? "intel_fb" + : _vesa_fb .constructed() ? "vesa_fb" + : _boot_fb .constructed() ? "boot_fb" + : _soc_fb .constructed() ? "fb" + : ""; + } + + Fb_driver(Env &env, Action &action) : _env(env), _action(action) { } + void gen_start_nodes(Xml_generator &xml) const { auto gen_capture_route = [&] (Xml_generator &xml) { gen_service_node<Capture::Session>(xml, [&] { - xml.node("parent", [&] { - xml.attribute("label", "global"); }); }); + xml.node("parent", [] { }); }); }; auto start_node = [&] (auto const &driver, auto const &binary, auto const &fn) @@ -124,6 +150,8 @@ struct Sculpt::Fb_driver : private Noncopyable bool const use_vesa = !use_intel_fb && !suspending && board_info.detected.vga && !use_boot_fb; + Fb_name const orig_fb_name = _fb_name(); + _intel_gpu.conditional(use_intel_gpu, registry, "intel_gpu", Priority::MULTIMEDIA, Ram_quota { 32*1024*1024 }, Cap_quota { 1400 }); @@ -136,11 +164,16 @@ struct Sculpt::Fb_driver : private Noncopyable registry, "vesa_fb", Priority::MULTIMEDIA, Ram_quota { 8*1024*1024 }, Cap_quota { 110 }); + Affinity::Location const fb_affinity = + board_info.soc.fb_on_dedicated_cpu ? Affinity::Location { 1, 0, 1, 1 } + : Affinity::Location { }; + _soc_fb.conditional(board_info.soc.fb && board_info.options.display, registry, Child_state::Attr { .name = "fb", .priority = Priority::MULTIMEDIA, .cpu_quota = 20, + .location = fb_affinity, .initial = { Ram_quota { 16*1024*1024 }, Cap_quota { 250 } }, .max = { } } ); @@ -149,6 +182,12 @@ struct Sculpt::Fb_driver : private Noncopyable Boot_fb::with_mode(platform, [&] (Boot_fb::Mode mode) { _boot_fb.construct(registry, "boot_fb", Priority::MULTIMEDIA, mode.ram_quota(), Cap_quota { 100 }); }); + + if (orig_fb_name != _fb_name()) { + Session_label label { "report -> runtime/", _fb_name(), "/connectors" }; + _connectors.conditional((label.length() > 1), _env, label, + *this, &Fb_driver::_handle_connectors); + } } static bool suspend_supported(Board_info const &board_info) @@ -157,6 +196,12 @@ struct Sculpt::Fb_driver : private Noncopyable return board_info.detected.intel_gfx && !board_info.options.suppress.intel_gpu; } + + void with_connectors(auto const &fn) const + { + if (_connectors.constructed()) + _connectors->with_xml(fn); + } }; #endif /* _DRIVER__FB_H_ */ diff --git a/repos/gems/src/app/sculpt_manager/driver/touch.h b/repos/gems/src/app/sculpt_manager/driver/touch.h index 0fde42c103..1496adf103 100644 --- a/repos/gems/src/app/sculpt_manager/driver/touch.h +++ b/repos/gems/src/app/sculpt_manager/driver/touch.h @@ -51,6 +51,7 @@ struct Sculpt::Touch_driver : private Noncopyable .name = "touch", .priority = Priority::MULTIMEDIA, .cpu_quota = 10, + .location = { }, .initial = { Ram_quota { 10*1024*1024 }, Cap_quota { 250 } }, .max = { } } ); diff --git a/repos/gems/src/app/sculpt_manager/driver/wifi.h b/repos/gems/src/app/sculpt_manager/driver/wifi.h index b078cd604e..d6d3f68d6f 100644 --- a/repos/gems/src/app/sculpt_manager/driver/wifi.h +++ b/repos/gems/src/app/sculpt_manager/driver/wifi.h @@ -52,7 +52,7 @@ struct Sculpt::Wifi_driver : private Noncopyable }); xml.node("libc", [&] { - xml.attribute("stdout", "/dev/null"); + xml.attribute("stdout", "/dev/log"); xml.attribute("stderr", "/dev/null"); xml.attribute("rtc", "/dev/rtc"); }); @@ -97,7 +97,7 @@ struct Sculpt::Wifi_driver : private Noncopyable && !board_info.options.suspending; _wifi.conditional(use_wifi, registry, "wifi", Priority::DEFAULT, - Ram_quota { 16*1024*1024 }, Cap_quota { 250 }); + Ram_quota { 16*1024*1024 }, Cap_quota { 260 }); } }; diff --git a/repos/gems/src/app/sculpt_manager/drivers.cc b/repos/gems/src/app/sculpt_manager/drivers.cc index 58cd1e3b98..bf33f4e100 100644 --- a/repos/gems/src/app/sculpt_manager/drivers.cc +++ b/repos/gems/src/app/sculpt_manager/drivers.cc @@ -100,7 +100,7 @@ class Sculpt::Drivers::Instance : Noncopyable, Ps2_driver _ps2_driver { }; Touch_driver _touch_driver { }; - Fb_driver _fb_driver { }; + Fb_driver _fb_driver { _env, _action }; Usb_driver _usb_driver { _env, *this, *this }; Ahci_driver _ahci_driver { _env, *this }; Nvme_driver _nvme_driver { _env, *this }; @@ -155,7 +155,7 @@ class Sculpt::Drivers::Instance : Noncopyable, _nic_driver .gen_start_node (xml); } - void with(With_storage_devices::Callback const &fn) const + void with(With_storage_devices::Ft const &fn) const { _usb_driver.with_devices([&] (Xml_node const &usb_devices) { _ahci_driver.with_ports([&] (Xml_node const &ahci_ports) { @@ -167,8 +167,9 @@ class Sculpt::Drivers::Instance : Noncopyable, .mmc = mmc_devices }); }); }); }); }); } - void with(With_board_info::Callback const &fn) const { fn(_board_info); } - void with(With_platform_info::Callback const &fn) const { fn(_platform.xml()); } + void with(With_board_info::Ft const &fn) const { fn(_board_info); } + void with_platform_info(With_xml::Ft const &fn) const { fn(_platform.xml()); } + void with_fb_connectors(With_xml::Ft const &fn) const { _fb_driver.with_connectors(fn); } bool suspend_supported() const { @@ -202,9 +203,10 @@ Sculpt::Drivers::Drivers(Env &env, Children &children, Info const &info, Action _instance(_construct_instance(env, children, info, action)) { } -void Drivers::_with(With_storage_devices::Callback const &fn) const { _instance.with(fn); } -void Drivers::_with(With_board_info::Callback const &fn) const { _instance.with(fn); } -void Drivers::_with(With_platform_info::Callback const &fn) const { _instance.with(fn); } +void Drivers::_with(With_storage_devices::Ft const &fn) const { _instance.with(fn); } +void Drivers::_with(With_board_info::Ft const &fn) const { _instance.with(fn); } +void Drivers::_with_platform_info(With_xml::Ft const &fn) const { _instance.with_platform_info(fn); } +void Drivers::_with_fb_connectors(With_xml::Ft const &fn) const { _instance.with_fb_connectors(fn); } void Drivers::update_usb () { _instance.update_usb(); } void Drivers::update_soc (Board_info::Soc soc) { _instance.update_soc(soc); } diff --git a/repos/gems/src/app/sculpt_manager/drivers.h b/repos/gems/src/app/sculpt_manager/drivers.h index 09bea3fa25..6e99c96b91 100644 --- a/repos/gems/src/app/sculpt_manager/drivers.h +++ b/repos/gems/src/app/sculpt_manager/drivers.h @@ -16,8 +16,10 @@ /* local includes */ #include <xml.h> +#include <util/callable.h> #include <model/child_state.h> #include <model/board_info.h> +#include <driver/fb.h> namespace Sculpt { struct Drivers; } @@ -26,7 +28,7 @@ class Sculpt::Drivers : Noncopyable { public: - struct Action : Interface + struct Action : virtual Fb_driver::Action { virtual void handle_device_plug_unplug() = 0; }; @@ -51,13 +53,14 @@ class Sculpt::Drivers : Noncopyable static Instance &_construct_instance(auto &&...); - using With_storage_devices = With<Storage_devices const &>; - using With_board_info = With<Board_info const &>; - using With_platform_info = With<Xml_node const &>; + using With_storage_devices = Callable<void, Storage_devices const &>; + using With_board_info = Callable<void, Board_info const &>; + using With_xml = Callable<void, Xml_node const &>; - void _with(With_storage_devices::Callback const &) const; - void _with(With_board_info::Callback const &) const; - void _with(With_platform_info::Callback const &) const; + void _with(With_storage_devices::Ft const &) const; + void _with(With_board_info::Ft const &) const; + void _with_platform_info(With_xml::Ft const &) const; + void _with_fb_connectors(With_xml::Ft const &) const; public: @@ -69,9 +72,10 @@ class Sculpt::Drivers : Noncopyable void gen_start_nodes(Xml_generator &) const; - void with_storage_devices(auto const &fn) const { _with(With_storage_devices::Fn { fn }); } - void with_board_info (auto const &fn) const { _with(With_board_info::Fn { fn }); } - void with_platform_info (auto const &fn) const { _with(With_platform_info::Fn { fn }); } + void with_storage_devices(auto const &fn) const { _with(With_storage_devices::Fn { fn }); } + void with_board_info (auto const &fn) const { _with(With_board_info::Fn { fn }); } + void with_platform_info (auto const &fn) const { _with_platform_info(With_xml::Fn { fn }); } + void with_fb_connectors (auto const &fn) const { _with_fb_connectors(With_xml::Fn { fn }); } /* true if hardware is suspend/resume capable */ bool suspend_supported() const; diff --git a/repos/gems/src/app/sculpt_manager/graph.cc b/repos/gems/src/app/sculpt_manager/graph.cc index d90f52a24a..48cfaf540c 100644 --- a/repos/gems/src/app/sculpt_manager/graph.cc +++ b/repos/gems/src/app/sculpt_manager/graph.cc @@ -100,6 +100,9 @@ void Graph::_view_selected_node_content(Scope<Depgraph, Frame, Vbox> &s, if (name == "ram_fs") s.widget(_ram_fs_widget, _selected_target, _ram_fs_state); + if (name == "intel_fb") + s.widget(_fb_widget, _fb_connectors, _fb_config, _hovered_display); + String<100> const ram (Capacity{info.assigned_ram - info.avail_ram}, " / ", Capacity{info.assigned_ram}), @@ -257,6 +260,7 @@ void Graph::click(Clicked_at const &at, Action &action) }); _ram_fs_widget .propagate(at, _selected_target, action); + _fb_widget .propagate(at, _fb_connectors, action); _ahci_devices_widget.propagate(at, action); _nvme_devices_widget.propagate(at, action); _mmc_devices_widget .propagate(at, action); diff --git a/repos/gems/src/app/sculpt_manager/graph.h b/repos/gems/src/app/sculpt_manager/graph.h index d9a850e84a..5a71cea8a7 100644 --- a/repos/gems/src/app/sculpt_manager/graph.h +++ b/repos/gems/src/app/sculpt_manager/graph.h @@ -25,6 +25,7 @@ #include <types.h> #include <view/storage_widget.h> #include <view/ram_fs_widget.h> +#include <view/fb_widget.h> #include <model/capacity.h> #include <model/popup.h> #include <model/runtime_config.h> @@ -42,6 +43,9 @@ struct Sculpt::Graph : Widget<Depgraph> Storage_devices const &_storage_devices; Storage_target const &_selected_target; Ram_fs_state const &_ram_fs_state; + Fb_connectors const &_fb_connectors; + Fb_config const &_fb_config; + Fb_connectors::Name const &_hovered_display; Popup::State const &_popup_state; Depot_deploy::Children const &_deploy_children; @@ -50,6 +54,9 @@ struct Sculpt::Graph : Widget<Depgraph> Hosted<Depgraph, Frame, Vbox, Ram_fs_widget> _ram_fs_widget { Id { "ram_fs" } }; + Hosted<Depgraph, Frame, Vbox, Fb_widget> + _fb_widget { Id { "fb" } }; + Hosted<Depgraph, Frame, Vbox, Frame, Hbox, Deferred_action_button> _remove { Id { "Remove" } }, _restart { Id { "Restart" } }; @@ -81,18 +88,23 @@ struct Sculpt::Graph : Widget<Depgraph> Storage_devices const &storage_devices, Storage_target const &selected_target, Ram_fs_state const &ram_fs_state, + Fb_connectors const &fb_connectors, + Fb_config const &fb_config, + Fb_connectors::Name const &hovered_display, Popup::State const &popup_state, Depot_deploy::Children const &deploy_children) : _runtime_state(runtime_state), _runtime_config(runtime_config), _storage_devices(storage_devices), _selected_target(selected_target), - _ram_fs_state(ram_fs_state), _popup_state(popup_state), - _deploy_children(deploy_children) + _ram_fs_state(ram_fs_state), _fb_connectors(fb_connectors), + _fb_config(fb_config), _hovered_display(hovered_display), + _popup_state(popup_state), _deploy_children(deploy_children) { } void view(Scope<Depgraph> &) const; - struct Action : virtual Storage_device_widget::Action + struct Action : virtual Storage_device_widget::Action, + virtual Fb_widget::Action { virtual void remove_deployed_component(Start_name const &) = 0; virtual void restart_deployed_component(Start_name const &) = 0; diff --git a/repos/gems/src/app/sculpt_manager/gui.cc b/repos/gems/src/app/sculpt_manager/gui.cc index 0174dbb385..1ceb254509 100644 --- a/repos/gems/src/app/sculpt_manager/gui.cc +++ b/repos/gems/src/app/sculpt_manager/gui.cc @@ -49,7 +49,8 @@ static bool clack(Input::Event const &event) } -struct Gui::Session_component : Rpc_object<Gui::Session> +struct Gui::Session_component : Rpc_object<Gui::Session>, + private Input::Session_component::Action { Env &_env; @@ -63,7 +64,16 @@ struct Gui::Session_component : Rpc_object<Gui::Session> Input::Session_client _gui_input { _env.rm(), _gui_session.input() }; - Input::Session_component _input_component { _env, _env.ram() }; + Input::Session_component _input_component { + _env.ep(), _env.ram(), _env.rm(), *this }; + + /** + * Input::Session_component::Action interface + */ + void exclusive_input_requested(bool enabled) override + { + _gui_input.exclusive(enabled); + } Signal_handler<Session_component> _input_handler { _env.ep(), *this, &Session_component::_handle_input }; @@ -104,12 +114,9 @@ struct Gui::Session_component : Rpc_object<Gui::Session> _connection(env, session_label_from_args(args), Ram_quota { 36*1024 }, { }) { _gui_input.sigh(_input_handler); - _env.ep().manage(_input_component); _input_component.event_queue().enabled(true); } - ~Session_component() { _env.ep().dissolve(_input_component); } - void upgrade(Session::Resources const &resources) { _connection.upgrade(resources); @@ -145,14 +152,11 @@ struct Gui::Session_component : Rpc_object<Gui::Session> void execute() override { _gui_session.execute(); } - Framebuffer::Mode mode() override { - return _gui_session.mode(); } + Info_result info() override { + return _gui_session.info(); } - void mode_sigh(Signal_context_capability sigh) override { - _gui_session.mode_sigh(sigh); } - - Buffer_result buffer(Framebuffer::Mode mode, bool use_alpha) override { - return _gui_session.buffer(mode, use_alpha); } + Buffer_result buffer(Framebuffer::Mode mode) override { + return _gui_session.buffer(mode); } void focus(Capability<Gui::Session> session) override { _gui_session.focus(session); } diff --git a/repos/gems/src/app/sculpt_manager/main.cc b/repos/gems/src/app/sculpt_manager/main.cc index a205ac1260..3d2f0d25b5 100644 --- a/repos/gems/src/app/sculpt_manager/main.cc +++ b/repos/gems/src/app/sculpt_manager/main.cc @@ -40,6 +40,8 @@ #include <model/presets.h> #include <model/screensaver.h> #include <model/system_state.h> +#include <model/fb_config.h> +#include <model/panorama_config.h> #include <view/download_status_widget.h> #include <view/popup_dialog.h> #include <view/panel_dialog.h> @@ -88,6 +90,7 @@ struct Sculpt::Main : Input_event_handler, Build_info::from_xml(Attached_rom_dataspace(_env, "build_info").xml()); bool const _mnt_reform = (_build_info.board == "mnt_reform2"); + bool const _mnt_pocket = (_build_info.board == "mnt_pocket"); Registry<Child_state> _child_states { }; @@ -104,7 +107,10 @@ struct Sculpt::Main : Input_event_handler, Gui::Connection _gui { _env, "input" }; - bool _gui_mode_ready = false; /* becomes true once the graphics driver is up */ + Gui::Connection::Panorama_result _panorama = Gui::Undefined { }; + + /* becomes true once the graphics driver is up */ + bool _gui_mode_ready() const { return _panorama.ok(); }; Gui::Root _gui_root { _env, _heap, *this, _global_input_seq_number }; @@ -145,6 +151,18 @@ struct Sculpt::Main : Input_event_handler, void _handle_gui_mode(); + Rom_handler<Main> _leitzentrale_rom { + _env, "leitzentrale", *this, &Main::_handle_leitzentrale }; + + void _handle_leitzentrale(Xml_node const &leitzentrale) + { + bool const orig_leitzentrale_visibile = _leitzentrale_visible; + _leitzentrale_visible = leitzentrale.attribute_value("enabled", false); + + if (orig_leitzentrale_visibile != _leitzentrale_visible) + _handle_gui_mode(); + } + Rom_handler<Main> _config { _env, "config", *this, &Main::_handle_config }; void _handle_config(Xml_node const &config) @@ -276,13 +294,15 @@ struct Sculpt::Main : Input_event_handler, **********************/ Board_info::Soc _soc { - .fb = _mnt_reform, + .fb = _mnt_reform || _mnt_pocket, .touch = false, - .wifi = false, /* initialized via PCI */ - .usb = _mnt_reform, - .mmc = _mnt_reform, + .wifi = _mnt_pocket, /* initialized via PCI on Reform */ + .usb = _mnt_reform || _mnt_pocket, + .mmc = _mnt_reform || _mnt_pocket, .modem = false, - .nic = _mnt_reform, + .nic = _mnt_reform || _mnt_pocket, + + .fb_on_dedicated_cpu = _mnt_pocket }; Drivers _drivers { _env, _child_states, *this, *this }; @@ -290,10 +310,10 @@ struct Sculpt::Main : Input_event_handler, Drivers::Resumed _resumed = _drivers.resumed(); Board_info::Options _driver_options { - .display = _mnt_reform, + .display = _mnt_reform || _mnt_pocket, .usb_net = false, .nic = false, - .wifi = false, + .wifi = _mnt_pocket, .suppress {}, .suspending = false, }; @@ -733,7 +753,28 @@ struct Sculpt::Main : Input_event_handler, double _font_size_px = 14; - Area _screen_size { }; + Area _screen_size { }; + Point _screen_pos { }; + + bool _leitzentrale_visible = false; + + Rom_handler<Main> _nitpicker_hover_handler { + _env, "nitpicker_hover", *this, &Main::_handle_nitpicker_hover }; + + Expanding_reporter _gui_fb_config { _env, "config", "gui_fb_config" }; + + Constructible<Gui::Point> _pointer_pos { }; + + Fb_connectors::Name _hovered_display { }; + + void _handle_nitpicker_hover(Xml_node const &hover) + { + if (hover.has_attribute("xpos")) + _pointer_pos.construct(Gui::Point::from_xml(hover)); + + /* place leitzentrale at the display under the pointer */ + _handle_gui_mode(); + } Panel_dialog::Tab _selected_tab = Panel_dialog::Tab::COMPONENTS; @@ -907,6 +948,9 @@ struct Sculpt::Main : Input_event_handler, */ void handle_input_event(Input::Event const &ev) override { + ev.handle_absolute_motion([&] (int x, int y) { + _pointer_pos.construct(x, y); }); + Keyboard_focus_guard focus_guard { *this }; Dialog::Event::Seq_number const seq_number { _global_input_seq_number.value }; @@ -953,8 +997,10 @@ struct Sculpt::Main : Input_event_handler, ev.handle_wheel([&] (int, int y) { dy = y*32; }); - if (ev.key_press(Input::KEY_PAGEUP)) dy = int(_gui.mode().area.h / 3); - if (ev.key_press(Input::KEY_PAGEDOWN)) dy = -int(_gui.mode().area.h / 3); + int const vscroll_step = int(_screen_size.h) / 3; + + if (ev.key_press(Input::KEY_PAGEUP)) dy = vscroll_step; + if (ev.key_press(Input::KEY_PAGEDOWN)) dy = -vscroll_step; if (dy != 0) { scroll_ypos += dy; @@ -1442,7 +1488,7 @@ struct Sculpt::Main : Input_event_handler, Start_name const start_name("editor"); _file_browser_state.text_area.construct(_child_states, start_name, Priority::LEITZENTRALE, - Ram_quota{32*1024*1024}, Cap_quota{350}); + Ram_quota{80*1024*1024}, Cap_quota{350}); } } @@ -1555,18 +1601,6 @@ struct Sculpt::Main : Input_event_handler, _cached_runtime_config, _file_browser_state, *this }; - Managed_config<Main> _fb_config { - _env, "config", "fb", *this, &Main::_handle_fb_config }; - - void _handle_fb_config(Xml_node const &node) - { - _fb_config.generate([&] (Xml_generator &xml) { - xml.attribute("system", "yes"); - copy_attributes(xml, node); - node.for_each_sub_node([&] (Xml_node const &sub_node) { - copy_node(xml, sub_node, { 5 }); }); }); - } - void _update_window_layout(Xml_node const &, Xml_node const &); void _update_window_layout() @@ -1610,6 +1644,127 @@ struct Sculpt::Main : Input_event_handler, Signal_handler<Main> _wheel_handler { _env.ep(), *this, &Main::_update_window_layout }; + /********************************** + ** Display driver configuration ** + **********************************/ + + Managed_config<Main> _nitpicker_config { + _env, "config", "nitpicker", *this, &Main::_handle_nitpicker_config }; + + void _handle_nitpicker_config(Xml_node const &node) + { + _nitpicker_config.generate([&] (Xml_generator &xml) { + copy_attributes(xml, node); + node.for_each_sub_node([&] (Xml_node const &sub_node) { + if (sub_node.has_type("capture") && sub_node.num_sub_nodes() == 0) { + xml.node("capture", [&] { + + /* generate panorama of fb-driver sessions */ + Panorama_config(_fb_config).gen_policy_entries(xml); + + /* default policy for capture applications like screenshot */ + xml.node("default-policy", [&] { }); + }); + } else { + copy_node(xml, sub_node, { 5 }); + } + }); + }); + } + + Panorama_config _panorama_config { }; + + Fb_connectors _fb_connectors { }; + + Rom_handler<Main> _manual_fb_handler { _env, "config -> fb", *this, &Main::_handle_manual_fb }; + + Expanding_reporter _managed_fb_reporter { _env, "config", "fb_config"}; + + Fb_config _fb_config { }; + + void _generate_fb_config() + { + _managed_fb_reporter.generate([&] (Xml_generator &xml) { + _fb_config.generate_managed_fb(xml); }); + + /* update nitpicker config if the new fb config affects the panorama */ + Panorama_config const orig = _panorama_config; + _panorama_config = Panorama_config(_fb_config); + if (orig != Panorama_config(_fb_config)) + _nitpicker_config.trigger_update(); + } + + void _handle_manual_fb(Xml_node const &node) + { + _fb_config = { }; + _fb_config.import_manual_config(node); + _fb_config.apply_connectors(_fb_connectors); + + _generate_fb_config(); + } + + /** + * Fb_driver::Action interface + */ + void fb_connectors_changed() override + { + _drivers.with_fb_connectors([&] (Xml_node const &node) { + if (_fb_connectors.update(_heap, node).progress) { + _fb_config.apply_connectors(_fb_connectors); + _generate_fb_config(); + _handle_gui_mode(); + _graph_view.refresh(); + } + }); + } + + /** + * Fb_widget::Action interface + */ + void select_fb_mode(Fb_connectors::Name const &conn, + Fb_connectors::Connector::Mode::Id const &mode) override + { + _fb_config.select_fb_mode(conn, mode, _fb_connectors); + _generate_fb_config(); + } + + /** + * Fb_widget::Action interface + */ + void disable_fb_connector(Fb_connectors::Name const &conn) override + { + _fb_config.disable_connector(conn); + _generate_fb_config(); + } + + /** + * Fb_widget::Action interface + */ + void toggle_fb_merge_discrete(Fb_connectors::Name const &conn) override + { + _fb_config.toggle_merge_discrete(conn); + _generate_fb_config(); + } + + /** + * Fb_widget::Action interface + */ + void swap_fb_connector(Fb_connectors::Name const &conn) override + { + _fb_config.swap_connector(conn); + _generate_fb_config(); + } + + /** + * Fb_widget::Action interface + */ + void fb_brightness(Fb_connectors::Name const &conn, unsigned percent) override + { + _fb_config.brightness(conn, percent); + _generate_fb_config(); + } + + /******************* ** Runtime graph ** *******************/ @@ -1617,8 +1772,8 @@ struct Sculpt::Main : Input_event_handler, Popup _popup { }; Graph _graph { _runtime_state, _cached_runtime_config, _storage._storage_devices, - _storage._selected_target, _storage._ram_fs_state, - _popup.state, _deploy._children }; + _storage._selected_target, _storage._ram_fs_state, _fb_connectors, + _fb_config, _hovered_display, _popup.state, _deploy._children }; struct Graph_dialog : Dialog::Top_level_dialog { @@ -1645,11 +1800,19 @@ struct Sculpt::Main : Input_event_handler, Main(Env &env) : _env(env) { + /* + * Read static platform information + */ + _drivers.with_platform_info([&] (Xml_node const &platform) { + platform.with_optional_sub_node("affinity-space", [&] (Xml_node const &node) { + _affinity_space = Affinity::Space(node.attribute_value("width", 1U), + node.attribute_value("height", 1U)); }); }); + _drivers.update_soc(_soc); _gui.input.sigh(_input_handler); - _gui.mode_sigh(_gui_mode_handler); + _gui.info_sigh(_gui_mode_handler); _handle_gui_mode(); - _fb_config.trigger_update(); + _nitpicker_config.trigger_update(); /* * Generate initial configurations @@ -1659,14 +1822,6 @@ struct Sculpt::Main : Input_event_handler, _handle_storage_devices(); - /* - * Read static platform information - */ - _drivers.with_platform_info([&] (Xml_node const &platform) { - platform.with_optional_sub_node("affinity-space", [&] (Xml_node const &node) { - _affinity_space = Affinity::Space(node.attribute_value("width", 1U), - node.attribute_value("height", 1U)); }); }); - /* * Generate initial config/managed/deploy configuration */ @@ -1680,7 +1835,7 @@ void Sculpt::Main::_update_window_layout(Xml_node const &decorator_margins, Xml_node const &window_list) { /* skip window-layout handling (and decorator activity) while booting */ - if (!_gui_mode_ready) + if (!_gui_mode_ready()) return; struct Decorator_margins @@ -1726,18 +1881,16 @@ void Sculpt::Main::_update_window_layout(Xml_node const &decorator_margins, if (panel_height == 0) return; - Framebuffer::Mode const mode = _gui.mode(); - /* suppress intermediate boot-time states before the framebuffer driver is up */ - if (mode.area.count() <= 1) + if (!_screen_size.valid()) return; /* area reserved for the panel */ - Rect const panel = Rect(Point(0, 0), Area(mode.area.w, panel_height)); + Rect const panel = Rect(Point(0, 0), Area(_screen_size.w, panel_height)); /* available space on the right of the menu */ Rect avail = Rect::compound(Point(0, panel.h()), - Point(mode.area.w - 1, mode.area.h - 1)); + Point(_screen_size.w - 1, _screen_size.h - 1)); Point const log_offset = _log_visible ? Point(0, 0) @@ -1745,8 +1898,8 @@ void Sculpt::Main::_update_window_layout(Xml_node const &decorator_margins, Point const log_p1(avail.x2() - log_min_w - margins.right + 1 + log_offset.x, avail.y1() + margins.top); - Point const log_p2(mode.area.w - margins.right - 1 + log_offset.x, - mode.area.h - margins.bottom - 1); + Point const log_p2(_screen_size.w - margins.right - 1 + log_offset.x, + _screen_size.h - margins.bottom - 1); /* position of the inspect window */ Point const inspect_p1(avail.x1() + margins.left, avail.y1() + margins.top); @@ -1812,7 +1965,7 @@ void Sculpt::Main::_update_window_layout(Xml_node const &decorator_margins, Area const size = win_size(win); Point const pos = _network_visible ? Point(log_p1.x - size.w, avail.y1()) - : Point(mode.area.w, avail.y1()); + : Point(_screen_size.w, avail.y1()); gen_window(win, Rect(pos, size)); }); @@ -1918,7 +2071,7 @@ void Sculpt::Main::_update_window_layout(Xml_node const &decorator_margins, _with_window(window_list, logo_label, [&] (Xml_node const &win) { Area const size = win_size(win); - Point const pos(mode.area.w - size.w, mode.area.h - size.h); + Point const pos(_screen_size.w - size.w, _screen_size.h - size.h); gen_window(win, Rect(pos, size)); }); }); @@ -1945,18 +2098,65 @@ void Sculpt::Main::_update_window_layout(Xml_node const &decorator_margins, void Sculpt::Main::_handle_gui_mode() { - Framebuffer::Mode const mode = _gui.mode(); + _panorama = _gui.panorama(); - if (mode.area.count() > 1) - _gui_mode_ready = true; + /* place leitzentrale at pointed display */ + Rect const orig_screen_rect { _screen_pos, _screen_size }; + Fb_connectors::Name const orig_hovered_display = _hovered_display; + { + Rect rect { }; - _update_window_layout(); + _gui.with_info([&] (Xml_node const &info) { + rect = Rect::from_xml(info); /* entire panorama */ + + if (!_pointer_pos.constructed()) + return; + + Gui::Point const at = *_pointer_pos; + + info.for_each_sub_node("capture", [&] (Xml_node const &capture) { + Rect const display = Rect::from_xml(capture); + if (display.contains(at)) { + rect = display; + Session_label label { capture.attribute_value("name", String<64>()) }; + _hovered_display = label.last_element(); + } + }); + }); + + _screen_pos = rect.at; + _screen_size = rect.area; + } + + bool const screen_changed = (orig_screen_rect != Rect { _screen_pos, _screen_size }) + || (orig_hovered_display != _hovered_display); + + if (screen_changed) { + _gui_fb_config.generate([&] (Xml_generator &xml) { + xml.attribute("xpos", _screen_pos.x); + xml.attribute("ypos", _screen_pos.y); + xml.attribute("width", _screen_size.w); + xml.attribute("height", _screen_size.h); + }); + + _panel_dialog.min_width = _screen_size.w; + unsigned const menu_width = max((unsigned)(_font_size_px*21.0), 320u); + _diag_dialog.min_width = menu_width; + _network_dialog.min_width = menu_width; + + _panel_dialog.refresh(); + _network_dialog.refresh(); + _diag_dialog.refresh(); + _update_window_layout(); + } _settings.manual_fonts_config = _fonts_config.try_generate_manually_managed(); if (!_settings.manual_fonts_config) { - _font_size_px = (double)mode.area.h / 60.0; + double const orig_font_size_px = _font_size_px; + + _font_size_px = (double)_screen_size.h / 60.0; if (_settings.font_size == Settings::Font_size::SMALL) _font_size_px *= 0.85; if (_settings.font_size == Settings::Font_size::LARGE) _font_size_px *= 1.35; @@ -1967,58 +2167,53 @@ void Sculpt::Main::_handle_gui_mode() */ _font_size_px = max(_font_size_px, _min_font_size_px); - _fonts_config.generate([&] (Xml_generator &xml) { - xml.attribute("copy", true); - xml.attribute("paste", true); - xml.node("vfs", [&] { - gen_named_node(xml, "rom", "Vera.ttf"); - gen_named_node(xml, "rom", "VeraMono.ttf"); - gen_named_node(xml, "dir", "fonts", [&] { + if (orig_font_size_px != _font_size_px) { + _fonts_config.generate([&] (Xml_generator &xml) { + xml.attribute("copy", true); + xml.attribute("paste", true); + xml.node("vfs", [&] { + gen_named_node(xml, "rom", "Vera.ttf"); + gen_named_node(xml, "rom", "VeraMono.ttf"); + gen_named_node(xml, "dir", "fonts", [&] { - auto gen_ttf_dir = [&] (char const *dir_name, - char const *ttf_path, double size_px) { + auto gen_ttf_dir = [&] (char const *dir_name, + char const *ttf_path, double size_px) { - gen_named_node(xml, "dir", dir_name, [&] { - gen_named_node(xml, "ttf", "regular", [&] { - xml.attribute("path", ttf_path); - xml.attribute("size_px", size_px); - xml.attribute("cache", "256K"); + gen_named_node(xml, "dir", dir_name, [&] { + gen_named_node(xml, "ttf", "regular", [&] { + xml.attribute("path", ttf_path); + xml.attribute("size_px", size_px); + xml.attribute("cache", "256K"); + }); }); - }); - }; + }; - gen_ttf_dir("title", "/Vera.ttf", _font_size_px*1.25); - gen_ttf_dir("text", "/Vera.ttf", _font_size_px); - gen_ttf_dir("annotation", "/Vera.ttf", _font_size_px*0.8); - gen_ttf_dir("monospace", "/VeraMono.ttf", _font_size_px); - }); - }); - xml.node("default-policy", [&] { xml.attribute("root", "/fonts"); }); - - auto gen_color = [&] (unsigned index, Color color) { - xml.node("palette", [&] { - xml.node("color", [&] { - xml.attribute("index", index); - xml.attribute("value", String<16>(color)); + gen_ttf_dir("title", "/Vera.ttf", _font_size_px*1.25); + gen_ttf_dir("text", "/Vera.ttf", _font_size_px); + gen_ttf_dir("annotation", "/Vera.ttf", _font_size_px*0.8); + gen_ttf_dir("monospace", "/VeraMono.ttf", _font_size_px); }); }); - }; + xml.node("default-policy", [&] { xml.attribute("root", "/fonts"); }); - Color const background = Color::rgb(0x1c, 0x22, 0x32); + auto gen_color = [&] (unsigned index, Color color) { + xml.node("palette", [&] { + xml.node("color", [&] { + xml.attribute("index", index); + xml.attribute("value", String<16>(color)); + }); + }); + }; - gen_color(0, background); - gen_color(8, background); - }); + Color const background = Color::rgb(0x1c, 0x22, 0x32); + + gen_color(0, background); + gen_color(8, background); + }); + /* propagate fonts config of runtime view */ + generate_runtime_config(); + } } - - _screen_size = mode.area; - _panel_dialog.min_width = _screen_size.w; - unsigned const menu_width = max((unsigned)(_font_size_px*21.0), 320u); - _diag_dialog.min_width = menu_width; - _network_dialog.min_width = menu_width; - - /* font size may has changed, propagate fonts config of runtime view */ - generate_runtime_config(); } diff --git a/repos/gems/src/app/sculpt_manager/model/board_info.h b/repos/gems/src/app/sculpt_manager/model/board_info.h index 9e838015e5..3b4fadb643 100644 --- a/repos/gems/src/app/sculpt_manager/model/board_info.h +++ b/repos/gems/src/app/sculpt_manager/model/board_info.h @@ -95,11 +95,14 @@ struct Sculpt::Board_info { bool fb, touch, wifi, usb, mmc, modem, nic; + bool fb_on_dedicated_cpu; + bool operator != (Soc const &other) const { return (fb != other.fb) || (touch != other.touch) || (wifi != other.wifi) || (usb != other.usb) - || (mmc != other.mmc) || (modem != other.modem); + || (mmc != other.mmc) || (modem != other.modem) + || (fb_on_dedicated_cpu != other.fb_on_dedicated_cpu); } } soc; diff --git a/repos/gems/src/app/sculpt_manager/model/child_state.h b/repos/gems/src/app/sculpt_manager/model/child_state.h index b4a613c1d2..d9985981c6 100644 --- a/repos/gems/src/app/sculpt_manager/model/child_state.h +++ b/repos/gems/src/app/sculpt_manager/model/child_state.h @@ -36,6 +36,8 @@ struct Sculpt::Child_state : Noncopyable Priority priority; unsigned cpu_quota; + Affinity::Location location; + struct Initial { Ram_quota ram; Cap_quota caps; } initial; struct Max { Ram_quota ram; Cap_quota caps; } max; @@ -64,6 +66,11 @@ struct Sculpt::Child_state : Noncopyable Version _version { 0 }; + static bool _location_valid(Attr const attr) + { + return attr.location.width() != 0 && attr.location.height() != 0; + } + public: Child_state(Registry<Child_state> ®istry, Attr const attr) @@ -75,6 +82,7 @@ struct Sculpt::Child_state : Noncopyable Child_state(registry, { .name = name, .priority = priority, .cpu_quota = 0, + .location = { }, .initial = { initial_ram, initial_caps }, .max = { } }) { } @@ -108,6 +116,14 @@ struct Sculpt::Child_state : Noncopyable if (_attr.cpu_quota) gen_named_node(xml, "resource", "CPU", [&] { xml.attribute("quantum", _attr.cpu_quota); }); + + if (_location_valid(_attr)) + xml.node("affinity", [&] { + xml.attribute("xpos", _attr.location.xpos()); + xml.attribute("ypos", _attr.location.ypos()); + xml.attribute("width", _attr.location.width()); + xml.attribute("height", _attr.location.height()); + }); } /** diff --git a/repos/gems/src/app/sculpt_manager/model/fb_config.h b/repos/gems/src/app/sculpt_manager/model/fb_config.h new file mode 100644 index 0000000000..2d2f346e06 --- /dev/null +++ b/repos/gems/src/app/sculpt_manager/model/fb_config.h @@ -0,0 +1,416 @@ +/* + * \brief Model for the framebuffer driver configuration + * \author Norman Feske + * \date 2024-10-23 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _MODEL__FB_CONFIG_H_ +#define _MODEL__FB_CONFIG_H_ + +#include <model/fb_connectors.h> + +namespace Sculpt { struct Fb_config; }; + + +struct Sculpt::Fb_config +{ + struct Entry + { + using Name = Fb_connectors::Name; + using Mode_id = Fb_connectors::Connector::Mode::Id; + using Mode_attr = Fb_connectors::Connector::Mode::Attr; + using Brightness = Fb_connectors::Brightness; + + bool defined; + bool present; /* false if imported from config but yet unused */ + Name name; + Mode_id mode_id; + Mode_attr mode_attr; + Brightness brightness; + + static Entry from_connector(Fb_connectors::Connector const &connector) + { + Mode_attr mode_attr { }; + Mode_id mode_id { }; + connector.with_used_mode([&] (Fb_connectors::Connector::Mode const &mode) { + mode_attr = mode.attr; + mode_id = mode.id; }); + + return { .defined = true, + .present = true, + .name = connector.name, + .mode_id = mode_id, + .mode_attr = mode_attr, + .brightness = connector.brightness }; + } + + static Entry from_manual_xml(Xml_node const &node) + { + return { .defined = true, + .present = false, + .name = node.attribute_value("name", Name()), + .mode_id = node.attribute_value("mode", Mode_id()), + .mode_attr = Mode_attr::from_xml(node), + .brightness = Brightness::from_xml(node) }; + } + + void generate(Xml_generator &xml) const + { + if (!defined) + return; + + xml.node("connector", [&] { + xml.attribute("name", name); + if (mode_attr.px.valid()) { + xml.attribute("width", mode_attr.px.w); + xml.attribute("height", mode_attr.px.h); + if (mode_attr.hz) + xml.attribute("hz", mode_attr.hz); + if (brightness.defined) + xml.attribute("brightness", brightness.percent); + if (mode_id.length() > 1) + xml.attribute("mode", mode_id); + } else { + xml.attribute("enabled", "no"); + } + }); + } + + bool smaller_than(Entry const &other) const + { + return mode_attr.px.count() < other.mode_attr.px.count(); + } + }; + + static constexpr unsigned MAX_ENTRIES = 16; + Entry _entries[MAX_ENTRIES]; + + struct Manual_attr + { + Area max_px; /* upper bound of framebuffer allocation */ + Area px; /* for vesa_fb */ + + static Manual_attr from_xml(Xml_node const &node) + { + return { .max_px = { .w = node.attribute_value("max_width", 0u), + .h = node.attribute_value("max_height", 0u) }, + .px = Area::from_xml(node) }; + } + + void generate(Xml_generator &xml) const + { + if (max_px.w) xml.attribute("max_width", max_px.w); + if (max_px.h) xml.attribute("max_height", max_px.h); + if (px.w) xml.attribute("width", px.w); + if (px.h) xml.attribute("height", px.h); + } + }; + + Manual_attr _manual_attr { }; + + unsigned _num_merged = 0; + + bool _known(Fb_connectors::Connector const &connector) + { + for (Entry const &entry : _entries) + if (entry.name == connector.name) + return true; + return false; + } + + void _with_known(Fb_connectors::Connector const &connector, auto const &fn) + { + for (Entry &entry : _entries) + if (entry.name == connector.name) + fn(entry); + } + + void _insert_at(unsigned at, Entry const &entry) + { + if (at >= MAX_ENTRIES) { + warning("maximum number of ", MAX_ENTRIES, " fb config entries exeeded"); + return; + } + + for (unsigned i = MAX_ENTRIES - 1; i > at; i--) + _entries[i] = _entries[i - 1]; + + _entries[at] = entry; + } + + /* + * A new merged connector such that the smallest mode stays in front + */ + void _add_unknown_merged(Entry const &new_entry) + { + unsigned at = 0; + for (; at < _num_merged && _entries[at].smaller_than(new_entry); at++); + + _insert_at(at, new_entry); + + if (_num_merged < MAX_ENTRIES) + _num_merged++; + } + + void _add_unknown_discrete(Entry const &new_entry) + { + unsigned at = 0; + for (; at < MAX_ENTRIES && _entries[at].defined; at++); + + _insert_at(at, new_entry); + } + + void import_manual_config(Xml_node const &config) + { + _manual_attr = Manual_attr::from_xml(config); + + unsigned count = 0; + + auto add_connectors = [&] (Xml_node const &node) + { + node.for_each_sub_node("connector", [&] (Xml_node const &node) { + Entry const e = Entry::from_manual_xml(node); + if (!_known(e.name) && count < MAX_ENTRIES) { + _entries[count] = e; + count++; + } + }); + }; + + /* import merged nodes */ + config.with_optional_sub_node("merge", [&] (Xml_node const &merge) { + add_connectors(merge); }); + + _num_merged = count; + + /* import discrete nodes */ + add_connectors(config); + + /* handle case that manual config contains solely discrete items */ + if (count && !_num_merged) + _num_merged = 1; + } + + void apply_connectors(Fb_connectors const &connectors) + { + /* apply information for connectors known from the manual config */ + connectors.for_each([&] (Fb_connectors::Connector const &conn) { + _with_known(conn.name, [&] (Entry &e) { + + if (e.present) /* apply config only once */ + return; + + if (!e.mode_attr.px.valid()) { /* switched off by config */ + e.mode_id = { }; + e.mode_attr = { }; + e.present = true; + return; + } + + conn.with_matching_mode(e.mode_id, e.mode_attr, + [&] (Fb_connectors::Connector::Mode const &mode) { + e.mode_id = mode.id; + e.mode_attr = mode.attr; + e.present = true; }); + }); + }); + + /* detect unplugging */ + for (Entry &entry : _entries) { + bool connected = false; + connectors.with_connector(entry.name, [&] (auto &) { connected = true; }); + if (!connected) + entry.present = false; + } + + connectors._merged.for_each([&] (Fb_connectors::Connector const &conn) { + if (!_known(conn.name)) + _add_unknown_merged(Entry::from_connector(conn)); }); + + connectors._discrete.for_each([&] (Fb_connectors::Connector const &conn) { + if (!_known(conn.name)) + _add_unknown_discrete(Entry::from_connector(conn)); }); + } + + void _with_entry(Entry::Name const &name, auto const &fn) + { + for (Entry &entry : _entries) + if (entry.name == name) + fn(entry); + } + + void select_fb_mode(Fb_connectors::Name const &conn, + Fb_connectors::Connector::Mode::Id const &mode_id, + Fb_connectors const &connectors) + { + connectors.with_mode_attr(conn, mode_id, [&] (Entry::Mode_attr const &attr) { + _with_entry(conn, [&] (Entry &entry) { + entry.mode_attr = attr; + entry.mode_id = mode_id; }); }); + } + + void disable_connector(Fb_connectors::Name const &conn) + { + _with_entry(conn, [&] (Entry &entry) { + entry.mode_attr = { }; }); + } + + void brightness(Fb_connectors::Name const &conn, unsigned percent) + { + _with_entry(conn, [&] (Entry &entry) { + entry.brightness.percent = percent; }); + } + + void _with_idx(Fb_connectors::Name const &conn, auto const &fn) const + { + for (unsigned i = 0; i < MAX_ENTRIES; i++) + if (_entries[i].name == conn && _entries[i].defined) { + fn(i); + return; + } + } + + void _swap_entries(unsigned i, unsigned j) + { + Entry tmp = _entries[i]; + _entries[i] = _entries[j]; + _entries[j] = tmp; + } + + /** + * Swap connector with next present predecessor + */ + void swap_connector(Fb_connectors::Name const &conn) + { + _with_idx(conn, [&] (unsigned const conn_idx) { + + if (conn_idx < 1) /* first entry cannot have a predecessor */ + return; + + /* search present predecessor */ + unsigned prev_idx = conn_idx - 1; + while (prev_idx > 0 && !_entries[prev_idx].present) + prev_idx--; + + _swap_entries(conn_idx, prev_idx); + }); + } + + void toggle_merge_discrete(Fb_connectors::Name const &conn) + { + _with_idx(conn, [&] (unsigned const idx) { + + if (idx < _num_merged) { + + /* + * Turn merged entry into discrete entry. + * + * There may be (non-present) merge entries following idx. + * Bubble up the entry so that it becomes the last merge + * entry before turning it into the first discrete entry by + * decreasing '_num_merged'. + */ + if (_num_merged > 0) { + for (unsigned i = idx; i < _num_merged - 1; i++) + _swap_entries(i, i + 1); + _num_merged--; + } + } else { + + /* + * Turn discrete entry into merged entry + */ + if (_num_merged < MAX_ENTRIES) { + for (unsigned i = idx; i > _num_merged; i--) + _swap_entries(i, i - 1); + _num_merged++; + } + } + }); + } + + struct Merge_info { Entry::Name name; Area px; }; + + void with_merge_info(auto const &fn) const + { + /* merged screen size and name corresponds to first enabled connector */ + for (unsigned i = 0; i < _num_merged; i++) { + if (_entries[i].present && _entries[i].mode_attr.px.valid()) { + fn({ .name = _entries[i].name, + .px = _entries[i].mode_attr.px }); + return; + } + } + + /* if all merged connectors are switched off, use name of first present one */ + for (unsigned i = 0; i < _num_merged; i++) { + if (_entries[i].present) { + fn({ .name = _entries[i].name, .px = { }}); + return; + } + } + }; + + void _gen_merge_node(Xml_generator &xml) const + { + with_merge_info([&] (Merge_info const &info) { + xml.node("merge", [&] { + xml.attribute("width", info.px.w); + xml.attribute("height", info.px.h); + xml.attribute("name", info.name); + + for (unsigned i = 0; i < _num_merged; i++) + _entries[i].generate(xml); + }); + }); + } + + void generate_managed_fb(Xml_generator &xml) const + { + _manual_attr.generate(xml); + + xml.attribute("system", "yes"); /* for screen blanking on suspend */ + + xml.node("report", [&] { xml.attribute("connectors", "yes"); }); + + _gen_merge_node(xml); + + /* nodes for discrete connectors */ + for (unsigned i = _num_merged; i < MAX_ENTRIES; i++) + _entries[i].generate(xml); + } + + void for_each_present_connector(Fb_connectors const &connectors, auto const &fn) const + { + for (Entry const &entry : _entries) + if (entry.defined && entry.present) + connectors.with_connector(entry.name, fn); + } + + void for_each_discrete_entry(auto const &fn) const + { + for (unsigned i = _num_merged; i < MAX_ENTRIES; i++) { + Entry const &entry = _entries[i]; + if (entry.defined && entry.present) + fn(entry); + } + } + + unsigned num_present_merged() const + { + unsigned count = 0; + for (unsigned i = 0; i < _num_merged; i++) + if (_entries[i].defined && _entries[i].present) + count++; + return count; + } +}; + +#endif /* _MODEL__FB_CONFIG_H_ */ diff --git a/repos/gems/src/app/sculpt_manager/model/fb_connectors.h b/repos/gems/src/app/sculpt_manager/model/fb_connectors.h new file mode 100644 index 0000000000..596214ad07 --- /dev/null +++ b/repos/gems/src/app/sculpt_manager/model/fb_connectors.h @@ -0,0 +1,279 @@ +/* + * \brief Representation of connectors reported by the framebuffer driver + * \author Norman Feske + * \date 2024-10-23 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _MODEL__FB_CONNECTORS_H_ +#define _MODEL__FB_CONNECTORS_H_ + +#include <types.h> + +namespace Sculpt { struct Fb_connectors; }; + + +struct Sculpt::Fb_connectors : private Noncopyable +{ + using Area = Gui::Area; + using Name = String<16>; + + struct Connector; + using Connectors = List_model<Connector>; + + struct Brightness + { + bool defined; + unsigned percent; + + bool operator != (Brightness const &other) const + { + return defined != other.defined || percent != other.percent; + } + + static Brightness from_xml(Xml_node const &node) + { + return { .defined = node.has_attribute("brightness"), + .percent = node.attribute_value("brightness", 0u) }; + } + }; + + struct Connector : Connectors::Element + { + Name const name; + Area mm { }; + Brightness brightness { }; + + struct Mode; + using Modes = List_model<Mode>; + + Modes _modes { }; + + struct Mode : Modes::Element + { + using Id = String<16>; + + Id const id; + + struct Attr + { + Name name; + Area px; + Area mm; + bool used; + unsigned hz; + + bool operator != (Attr const &other) const + { + return name != other.name + || px != other.px + || mm != other.mm + || used != other.used + || hz != other.hz; + } + + static Attr from_xml(Xml_node const &node) + { + return { + .name = node.attribute_value("name", Name()), + .px = { .w = node.attribute_value("width", 0u), + .h = node.attribute_value("height", 0u) }, + .mm = { .w = node.attribute_value("width_mm", 0u), + .h = node.attribute_value("height_mm", 0u) }, + .used = node.attribute_value("used", false), + .hz = node.attribute_value("hz", 0u) + }; + } + }; + + Attr attr { }; + + Mode(Id id) : id(id) { }; + + static Id id_from_xml(Xml_node const &node) + { + return node.attribute_value("id", Mode::Id()); + } + + bool matches(Xml_node const &node) const + { + return id_from_xml(node) == id; + } + + static bool type_matches(Xml_node const &node) + { + return node.has_type("mode"); + } + + bool has_resolution(Area px) const { return attr.px == px; } + bool has_hz (unsigned hz) const { return attr.hz == hz; } + }; + + Connector(Name const &name) : name(name) { } + + void _with_mode(auto const &match_fn, auto const &fn) const + { + bool found = false; + _modes.for_each([&] (Mode const &mode) { + if (!found && match_fn(mode.attr)) { + fn(mode); + found = true; } }); + } + + void with_used_mode(auto const &fn) const + { + _with_mode([&] (Mode::Attr const &attr) { return attr.used; }, fn); + } + + void with_matching_mode(Mode::Id const &preferred_id, + Mode::Attr const &attr, auto const &fn) const + { + auto matches_resolution_and_id = [&] (Mode const &mode) + { + return mode.has_resolution(attr.px) && (mode.id == preferred_id); + }; + + auto matches_resolution_and_hz = [&] (Mode const &mode) + { + return mode.has_resolution(attr.px) && mode.has_hz(attr.hz); + }; + + auto matches_resolution = [&] (Mode const &mode) + { + return mode.has_resolution(attr.px); + }; + + bool matched = false; + auto with_match_once = [&] (auto const &matches_fn, auto const &fn) + { + if (!matched) + _modes.for_each([&] (Mode const &mode) { + if (matches_fn(mode)) { + fn(mode); + matched = true; } }); + }; + + with_match_once(matches_resolution_and_id, fn); + with_match_once(matches_resolution_and_hz, fn); + with_match_once(matches_resolution, fn); + + if (!matched) + with_used_mode([&] (Mode const &used) { + fn(used); + matched = true; }); + } + + bool update(Allocator &alloc, Xml_node const &node) + { + Area const orig_mm = mm; + Brightness const orig_brightness = brightness; + + mm.w = node.attribute_value("width_mm", 0u); + mm.h = node.attribute_value("height_mm", 0u); + brightness = Brightness::from_xml(node); + + bool progress = (orig_mm != mm || orig_brightness != brightness); + + _modes.update_from_xml(node, + [&] (Xml_node const &node) -> Mode & { + progress = true; + return *new (alloc) Mode(Mode::id_from_xml(node)); + }, + [&] (Mode &mode) { + progress = true; + destroy(alloc, &mode); + }, + [&] (Mode &mode, Xml_node const &node) { + Mode::Attr const orig_attr = mode.attr; + mode.attr = Mode::Attr::from_xml(node); + progress |= (orig_attr != mode.attr); + } + ); + + return progress; + } + + bool matches(Xml_node const &node) const + { + return node.attribute_value("name", Name()) == name; + } + + static bool type_matches(Xml_node const &node) + { + return node.has_type("connector") + && node.attribute_value("connected", false) + && node.has_sub_node("mode"); + } + }; + + Connectors _merged { }; + Connectors _discrete { }; + + [[nodiscard]] Progress update(Allocator &alloc, Xml_node const &connectors) + { + bool progress = false; + + auto update = [&] (Connectors &model, Xml_node const &node) + { + model.update_from_xml(node, + [&] (Xml_node const &node) -> Connector & { + progress = true; + return *new (alloc) Connector(node.attribute_value("name", Name())); + }, + [&] (Connector &conn) { + progress = true; + conn.update(alloc, Xml_node("<empty/>")); + destroy(alloc, &conn); + }, + [&] (Connector &conn, Xml_node const &node) { + progress |= conn.update(alloc, node); + }); + }; + + update(_discrete, connectors); + + connectors.with_sub_node("merge", + [&] (Xml_node const &merge) { update(_merged, merge); }, + [&] { update(_merged, Xml_node("<merge/>")); }); + + return { progress }; + } + + static unsigned _count(Connectors const &connectors) + { + unsigned count = 0; + connectors.for_each([&] (Connector const &) { count++; }); + return count; + } + + unsigned num_merged() const { return _count(_merged); } + + void for_each(auto const &fn) const + { + _merged .for_each(fn); + _discrete.for_each(fn); + } + + void with_connector(Name const &conn_name, auto const &fn) const + { + for_each([&] (Connector const &connector) { + if (connector.name == conn_name) + fn(connector); }); + } + + void with_mode_attr(Name const &conn_name, Connector::Mode::Id const &id, auto const &fn) const + { + with_connector(conn_name, [&] (Connector const &connector) { + connector._modes.for_each([&] (Connector::Mode const &mode) { + if (mode.id == id) + fn(mode.attr); }); }); + } +}; + +#endif /* _MODEL__FB_CONNECTORS_H_ */ diff --git a/repos/gems/src/app/sculpt_manager/model/panorama_config.h b/repos/gems/src/app/sculpt_manager/model/panorama_config.h new file mode 100644 index 0000000000..36aa10ed47 --- /dev/null +++ b/repos/gems/src/app/sculpt_manager/model/panorama_config.h @@ -0,0 +1,100 @@ +/* + * \brief Representation of nitpicker's <capture> configuration + * \author Norman Feske + * \date 2024-10-25 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _MODEL__PANORAMA_CONFIG_H_ +#define _MODEL__PANORAMA_CONFIG_H_ + +#include <types.h> +#include <model/fb_config.h> + +namespace Sculpt { struct Panorama_config; }; + + +struct Sculpt::Panorama_config +{ + struct Entry + { + using Name = Fb_config::Entry::Name; + + Name name; + Rect rect; + + bool operator != (Entry const &other) const + { + return (name != other.name) || (rect != other.rect); + } + + void gen_policy(Xml_generator &xml) const + { + xml.node("policy", [&] { + xml.attribute("label_suffix", name); + xml.attribute("xpos", rect.x1()); + xml.attribute("ypos", rect.y1()); + xml.attribute("width", rect.w()); + xml.attribute("height", rect.h()); + }); + } + }; + + static constexpr unsigned MAX_ENTRIES = 16; + + Entry _entries[MAX_ENTRIES] { }; + + unsigned _num_entries = 0; + + Panorama_config() { }; + + Panorama_config(Fb_config const &fb_config) + { + int xpos = 0; + + auto append = [&] (auto const &name, auto const area) + { + if (_num_entries == MAX_ENTRIES) + return; + + _entries[_num_entries] = Entry { + .name = name, + .rect = { .at = { .x = xpos, .y = 0 }, .area = area } }; + + _num_entries++; + xpos += area.w; + }; + + fb_config.with_merge_info([&] (Fb_config::Merge_info const &info) { + append(info.name, info.px); }); + + fb_config.for_each_discrete_entry([&] (Fb_config::Entry const &entry) { + append(entry.name, entry.mode_attr.px); }); + } + + void gen_policy_entries(Xml_generator &xml) const + { + for (unsigned i = 0; i < _num_entries; i++) + _entries[i].gen_policy(xml); + } + + bool operator != (Panorama_config const &other) const + { + if (other._num_entries != _num_entries) + return true; + + for (unsigned i = 0; i < _num_entries; i++) + if (other._entries[i] != _entries[i]) + return true; + + return false; + } +}; + +#endif /* _MODEL__PANORAMA_CONFIG_H_ */ diff --git a/repos/gems/src/app/sculpt_manager/model/ram_fs_state.h b/repos/gems/src/app/sculpt_manager/model/ram_fs_state.h index 97312fbf2b..0046868239 100644 --- a/repos/gems/src/app/sculpt_manager/model/ram_fs_state.h +++ b/repos/gems/src/app/sculpt_manager/model/ram_fs_state.h @@ -37,6 +37,7 @@ struct Sculpt::Ram_fs_state : Child_state, File_system Child_state(registry, { .name = name, .priority = Priority::LEITZENTRALE, .cpu_quota = 0, + .location = { }, .initial = { Ram_quota{1024*1024}, Cap_quota{300} }, .max = { Ram_quota{2*1024*1024*1024UL}, { } } }), File_system(File_system::UNKNOWN) diff --git a/repos/gems/src/app/sculpt_manager/network.h b/repos/gems/src/app/sculpt_manager/network.h index 4647ef233a..20690639c1 100644 --- a/repos/gems/src/app/sculpt_manager/network.h +++ b/repos/gems/src/app/sculpt_manager/network.h @@ -141,12 +141,11 @@ struct Sculpt::Network : Noncopyable _wlan_config.generate([&] (Xml_generator &xml) { - xml.attribute("connected_scan_interval", 0U); xml.attribute("scan_interval", 10U); xml.attribute("update_quality_interval", 30U); - xml.attribute("verbose_state", false); - xml.attribute("verbose", false); + xml.attribute("verbose", false); + xml.attribute("log_level", "error"); xml.node("network", [&]() { xml.attribute("ssid", ap.ssid); @@ -172,19 +171,11 @@ struct Sculpt::Network : Noncopyable _wlan_config.generate([&] (Xml_generator &xml) { - xml.attribute("connected_scan_interval", 0U); xml.attribute("scan_interval", 10U); xml.attribute("update_quality_interval", 30U); - xml.attribute("verbose_state", false); - xml.attribute("verbose", false); - - xml.node("network", [&]() { - /* generate attributes to ease subsequent manual tweaking */ - xml.attribute("ssid", ""); - xml.attribute("protection", "NONE"); - xml.attribute("passphrase", ""); - }); + xml.attribute("verbose", false); + xml.attribute("log_level", "error"); }); _runtime_config_generator.generate_runtime_config(); diff --git a/repos/gems/src/app/sculpt_manager/runtime/inspect_view.cc b/repos/gems/src/app/sculpt_manager/runtime/inspect_view.cc index a8a3e46cee..7f1fe24ed1 100644 --- a/repos/gems/src/app/sculpt_manager/runtime/inspect_view.cc +++ b/repos/gems/src/app/sculpt_manager/runtime/inspect_view.cc @@ -28,7 +28,7 @@ static void for_each_inspected_storage_target(Storage_devices const &devices, au static void gen_terminal_start(Xml_generator &xml) { gen_common_start_content(xml, "terminal", - Cap_quota{110}, Ram_quota{36*1024*1024}, + Cap_quota{140}, Ram_quota{36*1024*1024}, Priority::NESTED_MAX); gen_provides<Terminal::Session>(xml); diff --git a/repos/gems/src/app/sculpt_manager/types.h b/repos/gems/src/app/sculpt_manager/types.h index 44defc155b..4d238abe19 100644 --- a/repos/gems/src/app/sculpt_manager/types.h +++ b/repos/gems/src/app/sculpt_manager/types.h @@ -69,26 +69,6 @@ namespace Sculpt { */ struct Verify { bool value; }; - /** - * Utility for passing lambda arguments to non-template functions - */ - template <typename... ARGS> - struct With - { - struct Callback : Interface - { - virtual void operator () (ARGS &&...) const = 0; - }; - - template <typename FN> - struct Fn : Callback - { - FN const &_fn; - Fn(FN const &fn) : _fn(fn) { }; - void operator () (ARGS &&... args) const override { _fn(args...); } - }; - }; - struct Progress { bool progress; }; } diff --git a/repos/gems/src/app/sculpt_manager/view/fb_widget.h b/repos/gems/src/app/sculpt_manager/view/fb_widget.h new file mode 100644 index 0000000000..cf957533e3 --- /dev/null +++ b/repos/gems/src/app/sculpt_manager/view/fb_widget.h @@ -0,0 +1,202 @@ +/* + * \brief Framebuffer settings + * \author Norman Feske + * \date 2024-10-23 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _VIEW__FB_WIDGET_H_ +#define _VIEW__FB_WIDGET_H_ + +#include <view/dialog.h> +#include <model/fb_config.h> + +namespace Sculpt { struct Fb_widget; } + +struct Sculpt::Fb_widget : Widget<Vbox> +{ + using Connector = Fb_connectors::Connector; + using Mode = Connector::Mode; + using Hosted_choice = Hosted<Vbox, Choice<Mode::Id>>; + using Mode_radio = Hosted<Radio_select_button<Mode::Id>>; + + struct Action : Interface + { + virtual void select_fb_mode(Fb_connectors::Name const &, Mode::Id const &) = 0; + virtual void disable_fb_connector(Fb_connectors::Name const &) = 0; + virtual void toggle_fb_merge_discrete(Fb_connectors::Name const &) = 0; + virtual void swap_fb_connector(Fb_connectors::Name const &) = 0; + virtual void fb_brightness(Fb_connectors::Name const &, unsigned) = 0; + }; + + Fb_connectors::Name _selected_connector { }; + + struct Bar : Widget<Right_floating_hbox> + { + void view(Scope<Right_floating_hbox> &s, unsigned const percent) const + { + for (unsigned i = 0; i < 10; i++) { + s.sub_scope<Button>(Id { i }, [&] (Scope<Right_floating_hbox, Button> &s) { + + if (s.hovered()) s.attribute("hovered", "yes"); + + if (i*10 <= percent) + s.attribute("selected", "yes"); + else + s.attribute("style", "unimportant"); + + s.sub_scope<Float>([&] (auto &) { }); + }); + } + } + + void click(Clicked_at const &at, auto const &fn) + { + Id const id = at.matching_id<Right_floating_hbox, Button>(); + unsigned value = 0; + if (!ascii_to(id.value.string(), value)) + return; + + unsigned const percent = max(10u, min(100u, value*10 + 9)); + fn(percent); + } + }; + + using Hosted_brightness = Hosted<Bar>; + + void view(Scope<Vbox> &s, Fb_connectors const &connectors, Fb_config const &config, + Fb_connectors::Name const &hovered_display) const + { + auto view_connector = [&] (Connector const &conn) + { + Hosted_choice choice { Id { conn.name }, conn.name }; + + Mode::Id selected_mode { "off" }; + conn._modes.for_each([&] (Mode const &mode) { + if (mode.attr.used) + selected_mode = mode.id; }); + + s.widget(choice, + Hosted_choice::Attr { + .left_ex = 12, .right_ex = 28, + .unfolded = _selected_connector, + .selected_item = selected_mode + }, + [&] (Hosted_choice::Sub_scope &s) { + + if (conn.brightness.defined) { + Hosted_brightness brightness { Id { "brightness" } }; + s.widget(brightness, conn.brightness.percent); + } + + conn._modes.for_each([&] (Mode const &mode) { + String<32> text { mode.attr.name }; + if (mode.attr.hz) + text = { text, " (", mode.attr.hz, " Hz)" }; + + s.widget(Mode_radio { Id { mode.id }, mode.id }, + selected_mode, text); + }); + if (conn.name != hovered_display) + s.widget(Mode_radio { Id { "off" }, "off" }, selected_mode, "off"); + }); + }; + + unsigned const num_merged = config.num_present_merged(); + + auto view_controls = [&] (Scope<Vbox> &s, unsigned const count, Id const &id) + { + if (count <= 1) + return; + + s.sub_scope<Float>([&] (Scope<Vbox, Float> &s) { + s.sub_scope<Hbox>(id, [&] (Scope<Vbox, Float, Hbox> &s) { + + /* + * Restrict merge/unmerge toggle to last merged and first + * discrete connector. + */ + bool const toggle_allowed = (count == num_merged || count == num_merged + 1); + Id const equal_id { toggle_allowed ? "equal" : "_equal" }; + + s.sub_scope<Float>(equal_id, + [&] (Scope<Vbox, Float, Hbox, Float> &s) { + s.sub_scope<Button>([&] (Scope<Vbox, Float, Hbox, Float, Button> &s) { + s.attribute("style", "vconn"); + if (count <= num_merged) + s.attribute("selected", "yes"); + if (toggle_allowed) { + if (s.hovered() && !s.dragged()) + s.attribute("hovered", "yes"); + } + s.sub_node("hbox", [&] { }); + }); + }); + s.sub_scope<Float>(Id { "swap" }, [&] (Scope<Vbox, Float, Hbox, Float> &s) { + s.sub_scope<Button>([&] (Scope<Vbox, Float, Hbox, Float, Button> &s) { + s.attribute("style", "vswap"); + if (s.hovered() && !s.dragged()) + s.attribute("hovered", "yes"); + if (s.hovered() && s.dragged()) + s.attribute("selected", "yes"); + s.sub_node("hbox", [&] { }); + }); + }); + }); + }); + }; + + unsigned count = 0; + + config.for_each_present_connector(connectors, [&] (Connector const &conn) { + count++; + view_controls(s, count, Id { conn.name }); + view_connector(conn); + }); + } + + void click(Clicked_at const &at, Fb_connectors const &connectors, Action &action) + { + auto click_connector = [&] (Connector const &conn) + { + Hosted_choice choice { Id { conn.name }, conn.name }; + + choice.propagate(at, _selected_connector, + [&] { _selected_connector = { }; }, + [&] (Clicked_at const &at) { + Id const id = at.matching_id<Mode_radio>(); + if (id.value == "brightness") { + Hosted_brightness brightness { Id { "brightness" } }; + brightness.propagate(at, [&] (unsigned percent) { + action.fb_brightness(conn.name, percent); }); + } else if (id.value == "off") + action.disable_fb_connector(conn.name); + else if (id.valid()) + action.select_fb_mode(conn.name, id); + }); + }; + + connectors._merged.for_each([&] (Connector const &conn) { + click_connector(conn); }); + + connectors._discrete.for_each([&] (Connector const &conn) { + click_connector(conn); }); + + /* operation buttons */ + { + Id const conn = at.matching_id<Vbox, Float, Hbox>(); + Id const op = at.matching_id<Vbox, Float, Hbox, Float>(); + + if (op.value == "equal") action.toggle_fb_merge_discrete(conn.value); + if (op.value == "swap") action.swap_fb_connector(conn.value); + } + } +}; + +#endif /* _VIEW__FB_WIDGET_H_ */ diff --git a/repos/gems/src/app/themed_decorator/main.cc b/repos/gems/src/app/themed_decorator/main.cc index 5361aa819f..edf44d3bca 100644 --- a/repos/gems/src/app/themed_decorator/main.cc +++ b/repos/gems/src/app/themed_decorator/main.cc @@ -17,6 +17,7 @@ #include <base/heap.h> #include <base/attached_rom_dataspace.h> #include <os/reporter.h> +#include <timer_session/connection.h> /* decorator includes */ #include <decorator/window_stack.h> @@ -36,6 +37,18 @@ struct Decorator::Main : Window_factory_base { Env &_env; + Timer::Connection _timer { _env }; + + /* + * Time base for animations, which are computed in steps of 10 ms + */ + struct Ticks { uint64_t cs; /* centi-seconds (10 ms) */ }; + + Ticks _now() + { + return { .cs = _timer.curr_time().trunc_to_plain_ms().value / 10 }; + } + Window_stack _window_stack = { *this }; /** @@ -77,19 +90,7 @@ struct Decorator::Main : Window_factory_base Reporter _decorator_margins_reporter = { _env, "decorator_margins" }; - /** - * Process the update every 'frame_period' GUI sync signals. The - * 'frame_cnt' holds the counter of the GUI sync signals. - * - * A lower 'frame_period' value makes the decorations more responsive - * but it also puts more load on the system. - * - * If the GUI sync signal fires every 10 milliseconds, a - * 'frame_period' of 2 results in an update rate of 1000/20 = 50 frames per - * second. - */ - unsigned _frame_cnt = 0; - unsigned _frame_period = 2; + Ticks _previous_sync { }; /** * Install handler for responding to GUI sync events @@ -99,9 +100,17 @@ struct Decorator::Main : Window_factory_base Signal_handler<Main> _gui_sync_handler = { _env.ep(), *this, &Main::_handle_gui_sync }; - void _trigger_sync_handling() + bool _gui_sync_enabled = false; + + void _trigger_gui_sync() { - _gui.framebuffer.sync_sigh(_gui_sync_handler); + Ticks const now = _now(); + bool const idle = now.cs - _previous_sync.cs > 3; + + if (!_gui_sync_enabled || idle) { + _previous_sync = now; + _gui_sync_handler.local_submit(); + } } Attached_rom_dataspace _config { _env, "config" }; @@ -141,7 +150,7 @@ struct Decorator::Main : Window_factory_base Genode::log("pointer information unavailable"); } - _trigger_sync_handling(); + _trigger_gui_sync(); _hover_reporter.enabled(true); @@ -252,16 +261,15 @@ void Decorator::Main::_handle_window_layout_update() _window_layout_update_needed = true; - _trigger_sync_handling(); + _trigger_gui_sync(); } void Decorator::Main::_handle_gui_sync() { - if (_frame_cnt++ < _frame_period) - return; + Ticks const now = _now(); - _frame_cnt = 0; + Ticks const passed_ticks { now.cs - _previous_sync.cs }; bool model_updated = false; @@ -286,25 +294,30 @@ void Decorator::Main::_handle_gui_sync() bool const windows_animated = _window_stack.schedule_animated_windows(); - /* - * To make the perceived animation speed independent from the setting of - * 'frame_period', we update the animation as often as the GUI sync signal - * occurs. - */ - for (unsigned i = 0; i < _frame_period; i++) + for (unsigned i = 0; i < passed_ticks.cs; i++) _animator.animate(); - if (!model_updated && !windows_animated) - return; - - _window_stack.update_gui_views(); - _gui.execute(); + if (model_updated || windows_animated) { + _window_stack.update_gui_views(); + _gui.execute(); + } /* - * Disable sync handling when becoming idle + * Enable/disable periodic sync depending on animation state */ - if (!_animator.active()) - _gui.framebuffer.sync_sigh(Signal_context_capability()); + if (_gui_sync_enabled) { + if (!_animator.active()) { + _gui.framebuffer.sync_sigh(Signal_context_capability()); + _gui_sync_enabled = false; + } + } else { + if (_animator.active()) { + _gui.framebuffer.sync_sigh(_gui_sync_handler); + _gui_sync_enabled = true; + } + } + + _previous_sync = now; } diff --git a/repos/gems/src/app/themed_decorator/window.h b/repos/gems/src/app/themed_decorator/window.h index 3c35413546..7abdf8fb02 100644 --- a/repos/gems/src/app/themed_decorator/window.h +++ b/repos/gems/src/app/themed_decorator/window.h @@ -286,8 +286,6 @@ class Decorator::Window : public Window_base, public Animator::Item }); buffer.flush_surface(); - - buffer.gui.framebuffer.refresh(0, 0, buffer.size().w, buffer.size().h); } void _repaint_decorations() @@ -300,17 +298,15 @@ class Decorator::Window : public Window_base, public Animator::Item void _reallocate_gui_buffers() { - bool const use_alpha = true; - Area const size_top_bottom = _visible_top_bottom_area(geometry().area); if (size_top_bottom.w > _size_top_bottom.w || size_top_bottom.h > _size_top_bottom.h || !_buffer_top_bottom.constructed()) { - _gui_top_bottom.buffer(Framebuffer::Mode { .area = { size_top_bottom.w, - size_top_bottom.h } }, - use_alpha); + _gui_top_bottom.buffer({ .area = { size_top_bottom.w, + size_top_bottom.h }, + .alpha = true }); _buffer_top_bottom.construct(_gui_top_bottom, size_top_bottom, _env.ram(), _env.rm()); @@ -324,9 +320,9 @@ class Decorator::Window : public Window_base, public Animator::Item || size_left_right.h > _size_left_right.h || !_buffer_left_right.constructed()) { - _gui_left_right.buffer(Framebuffer::Mode { .area = { size_left_right.w, - size_left_right.h } }, - use_alpha); + _gui_left_right.buffer({ .area = { size_left_right.w, + size_left_right.h }, + .alpha = true }); _buffer_left_right.construct(_gui_left_right, size_left_right, _env.ram(), _env.rm()); diff --git a/repos/gems/src/app/window_layouter/action.h b/repos/gems/src/app/window_layouter/action.h index 45890aa426..995274b6ac 100644 --- a/repos/gems/src/app/window_layouter/action.h +++ b/repos/gems/src/app/window_layouter/action.h @@ -49,6 +49,7 @@ class Window_layouter::Action PREV_TAB, TOOGLE_OVERLAY, SCREEN, + RELEASE_GRAB, }; private: @@ -64,6 +65,7 @@ class Window_layouter::Action if (string == "raise_window") return RAISE_WINDOW; if (string == "toggle_fullscreen") return TOGGLE_FULLSCREEN; if (string == "screen") return SCREEN; + if (string == "release_grab") return RELEASE_GRAB; Genode::warning("cannot convert \"", string, "\" to action type"); return NONE; diff --git a/repos/gems/src/app/window_layouter/main.cc b/repos/gems/src/app/window_layouter/main.cc index b6ac16d19e..123428445f 100644 --- a/repos/gems/src/app/window_layouter/main.cc +++ b/repos/gems/src/app/window_layouter/main.cc @@ -196,6 +196,12 @@ struct Window_layouter::Main : Operations, _gen_focus(); } + void release_grab() override + { + /* wm revokes exclusive input on each focus update */ + _gen_focus(); + } + void toggle_fullscreen(Window_id id) override { /* make sure that the specified window is the front-most one */ @@ -325,9 +331,9 @@ struct Window_layouter::Main : Operations, void _handle_mode_change() { /* determine maximized window geometry */ - Framebuffer::Mode const mode = _gui.mode(); - - _screen_size = mode.area; + _screen_size = _gui.panorama().convert<Gui::Area>( + [&] (Gui::Rect rect) { return rect.area; }, + [&] (Gui::Undefined) { return Gui::Area { 1, 1 }; }); _update_window_layout(); } @@ -373,7 +379,7 @@ struct Window_layouter::Main : Operations, */ Main(Env &env) : _env(env) { - _gui.mode_sigh(_mode_change_handler); + _gui.info_sigh(_mode_change_handler); _handle_mode_change(); _drop_timer.sigh(_drop_timer_handler); diff --git a/repos/gems/src/app/window_layouter/operations.h b/repos/gems/src/app/window_layouter/operations.h index 4ed9922d13..5cf7da46cc 100644 --- a/repos/gems/src/app/window_layouter/operations.h +++ b/repos/gems/src/app/window_layouter/operations.h @@ -28,6 +28,7 @@ struct Window_layouter::Operations : Interface virtual void close(Window_id) = 0; virtual void toggle_fullscreen(Window_id) = 0; virtual void focus(Window_id) = 0; + virtual void release_grab() = 0; virtual void to_front(Window_id) = 0; virtual void drag(Window_id, Window::Element, Point clicked, Point curr) = 0; virtual void finalize_drag(Window_id, Window::Element, Point clicked, Point final) = 0; diff --git a/repos/gems/src/app/window_layouter/user_state.h b/repos/gems/src/app/window_layouter/user_state.h index 255b17dca8..edb2d8cf8e 100644 --- a/repos/gems/src/app/window_layouter/user_state.h +++ b/repos/gems/src/app/window_layouter/user_state.h @@ -332,6 +332,10 @@ void Window_layouter::User_state::_handle_event(Input::Event const &e, _operations.screen(action.target_name()); return; + case Action::RELEASE_GRAB: + _operations.release_grab(); + return; + default: warning("action ", (int)action.type(), " unhanded"); } diff --git a/repos/gems/src/lib/dialog/sandboxed_runtime.cc b/repos/gems/src/lib/dialog/sandboxed_runtime.cc index ff460a3ad8..d8e204ae14 100644 --- a/repos/gems/src/lib/dialog/sandboxed_runtime.cc +++ b/repos/gems/src/lib/dialog/sandboxed_runtime.cc @@ -66,7 +66,14 @@ struct Sandboxed_runtime::Gui_session : Session_object<Gui::Session> Input::Session_client _gui_input { _env.rm(), _gui_session.input() }; - Input::Session_component _input_component { _env, _env.ram() }; + struct Input_action : Input::Session_component::Action + { + void exclusive_input_requested(bool) override { }; + + } _input_action { }; + + Input::Session_component _input_component { + _env.ep(), _env.ram(), _env.rm(), _input_action }; Signal_handler<Gui_session> _input_handler { _env.ep(), *this, &Gui_session::_handle_input }; @@ -109,12 +116,9 @@ struct Sandboxed_runtime::Gui_session : Session_object<Gui::Session> _connection(env, _label, Ram_quota { 36*1024 }, { }) { _gui_input.sigh(_input_handler); - _env.ep().manage(_input_component); _input_component.event_queue().enabled(true); } - ~Gui_session() { _env.ep().dissolve(_input_component); } - void upgrade(Session::Resources const &resources) { _connection.upgrade(resources); @@ -150,14 +154,11 @@ struct Sandboxed_runtime::Gui_session : Session_object<Gui::Session> void execute() override { _gui_session.execute(); } - Framebuffer::Mode mode() override { - return _gui_session.mode(); } + Info_result info() override { + return _gui_session.info(); } - void mode_sigh(Signal_context_capability sigh) override { - _gui_session.mode_sigh(sigh); } - - Buffer_result buffer(Framebuffer::Mode mode, bool use_alpha) override { - return _gui_session.buffer(mode, use_alpha); } + Buffer_result buffer(Framebuffer::Mode mode) override { + return _gui_session.buffer(mode); } void focus(Capability<Gui::Session> session) override { _gui_session.focus(session); } diff --git a/repos/gems/src/server/cpu_sampler/cpu_session_component.cc b/repos/gems/src/server/cpu_sampler/cpu_session_component.cc index 091628b762..d3e78f0c03 100644 --- a/repos/gems/src/server/cpu_sampler/cpu_session_component.cc +++ b/repos/gems/src/server/cpu_sampler/cpu_session_component.cc @@ -30,22 +30,30 @@ Cpu_sampler::Cpu_session_component::create_thread(Pd_session_capability pd, { Cpu_thread_component *cpu_thread = new (_md_alloc) Cpu_thread_component(*this, _env, - _md_alloc, - pd, - name, - affinity, - weight, - utcb, - name.string(), - _next_thread_id); + _md_alloc, + pd, + name, + affinity, + weight, + utcb, + name.string(), + _next_thread_id); - _thread_list.insert(new (_md_alloc) Thread_element(cpu_thread)); + return cpu_thread->result().convert<Create_thread_result>( + [&] (Thread_capability) { + _thread_list.insert(new (_md_alloc) Thread_element(cpu_thread)); - _thread_list_change_handler.thread_list_changed(); + _thread_list_change_handler.thread_list_changed(); - _next_thread_id++; + _next_thread_id++; - return cpu_thread->cap(); + return cpu_thread->cap(); + }, + [&] (Create_thread_error e) { + destroy(_md_alloc, cpu_thread); + return e; + } + ); } diff --git a/repos/gems/src/server/cpu_sampler/cpu_thread_component.cc b/repos/gems/src/server/cpu_sampler/cpu_thread_component.cc index 08091ab6c3..109d686d69 100644 --- a/repos/gems/src/server/cpu_sampler/cpu_thread_component.cc +++ b/repos/gems/src/server/cpu_sampler/cpu_thread_component.cc @@ -36,15 +36,14 @@ Cpu_sampler::Cpu_thread_component::Cpu_thread_component( _cpu_session_component(cpu_session_component), _env(env), _md_alloc(md_alloc), _parent_cpu_thread( _cpu_session_component.parent_cpu_session() - .create_thread(pd, name, affinity, weight, utcb) - .convert<Thread_capability>( - [&] (Thread_capability cap) { return cap; }, - [&] (auto) { - error("failed to create CPU thread"); - return Thread_capability(); })), + .create_thread(pd, name, affinity, weight, utcb)), _label(_cpu_session_component.session_label().string(), " -> ", thread_name), _log_session_label("samples -> ", _label, ".", thread_id) { + _parent_cpu_thread.with_result( + [&] (Thread_capability cap) { _parent_cpu_client.construct(cap); }, + [&] (Cpu_session::Create_thread_error) { }); + _cpu_session_component.thread_ep().manage(this); } @@ -72,13 +71,13 @@ void Cpu_sampler::Cpu_thread_component::take_sample() unsigned loop_cnt = 0; for (; loop_cnt < MAX_LOOP_CNT; loop_cnt++) { - _parent_cpu_thread.pause(); + _parent_cpu_client->pause(); - Thread_state const thread_state = _parent_cpu_thread.state(); + Thread_state const thread_state = _parent_cpu_client->state(); if (thread_state.state == Thread_state::State::VALID) _sample_buf[_sample_buf_index++] = thread_state.cpu.ip; - _parent_cpu_thread.resume(); + _parent_cpu_client->resume(); if (_sample_buf_index == SAMPLE_BUF_SIZE) flush(); @@ -122,75 +121,75 @@ void Cpu_sampler::Cpu_thread_component::flush() Dataspace_capability Cpu_sampler::Cpu_thread_component::utcb() { - return _parent_cpu_thread.utcb(); + return _parent_cpu_client->utcb(); } void Cpu_sampler::Cpu_thread_component::start(addr_t ip, addr_t sp) { - _parent_cpu_thread.start(ip, sp); + _parent_cpu_client->start(ip, sp); _started = true; } void Cpu_sampler::Cpu_thread_component::pause() { - _parent_cpu_thread.pause(); + _parent_cpu_client->pause(); } void Cpu_sampler::Cpu_thread_component::resume() { - _parent_cpu_thread.resume(); + _parent_cpu_client->resume(); } void Cpu_sampler::Cpu_thread_component::single_step(bool enable) { - _parent_cpu_thread.single_step(enable); + _parent_cpu_client->single_step(enable); } Thread_state Cpu_sampler::Cpu_thread_component::state() { - return _parent_cpu_thread.state(); + return _parent_cpu_client->state(); } void Cpu_sampler::Cpu_thread_component::state(Thread_state const &state) { - _parent_cpu_thread.state(state); + _parent_cpu_client->state(state); } void Cpu_sampler::Cpu_thread_component::exception_sigh(Signal_context_capability sigh_cap) { - _parent_cpu_thread.exception_sigh(sigh_cap); + _parent_cpu_client->exception_sigh(sigh_cap); } void Cpu_sampler::Cpu_thread_component::affinity(Affinity::Location location) { - _parent_cpu_thread.affinity(location); + _parent_cpu_client->affinity(location); } unsigned Cpu_sampler::Cpu_thread_component::trace_control_index() { - return _parent_cpu_thread.trace_control_index(); + return _parent_cpu_client->trace_control_index(); } Dataspace_capability Cpu_sampler::Cpu_thread_component::trace_buffer() { - return _parent_cpu_thread.trace_buffer(); + return _parent_cpu_client->trace_buffer(); } Dataspace_capability Cpu_sampler::Cpu_thread_component::trace_policy() { - return _parent_cpu_thread.trace_policy(); + return _parent_cpu_client->trace_policy(); } diff --git a/repos/gems/src/server/cpu_sampler/cpu_thread_component.h b/repos/gems/src/server/cpu_sampler/cpu_thread_component.h index 873bef97c6..70115ceb23 100644 --- a/repos/gems/src/server/cpu_sampler/cpu_thread_component.h +++ b/repos/gems/src/server/cpu_sampler/cpu_thread_component.h @@ -39,7 +39,8 @@ class Cpu_sampler::Cpu_thread_component : public Rpc_object<Cpu_thread> Allocator &_md_alloc; - Cpu_thread_client _parent_cpu_thread; + Cpu_session::Create_thread_result _parent_cpu_thread; + Constructible<Cpu_thread_client> _parent_cpu_client; bool _started = false; @@ -68,7 +69,9 @@ class Cpu_sampler::Cpu_thread_component : public Rpc_object<Cpu_thread> Cpu_session_component const *cpu_session_component() const { return &_cpu_session_component; } - Thread_capability parent_thread() { return _parent_cpu_thread.rpc_cap(); } + Cpu_session::Create_thread_result result() { return _parent_cpu_thread; } + + Thread_capability parent_thread() { return _parent_cpu_client->rpc_cap(); } Session_label &label() { return _label; } void take_sample(); diff --git a/repos/gems/src/server/gui_fader/main.cc b/repos/gems/src/server/gui_fader/main.cc index e6225e2df7..1d713f8034 100644 --- a/repos/gems/src/server/gui_fader/main.cc +++ b/repos/gems/src/server/gui_fader/main.cc @@ -23,6 +23,7 @@ #include <os/static_root.h> #include <util/reconstructible.h> #include <nitpicker_gfx/texture_painter.h> +#include <blit/painter.h> #include <util/lazy_value.h> #include <timer_session/connection.h> @@ -42,6 +43,7 @@ namespace Gui_fader { using Rect = Genode::Surface_base::Rect; using Genode::size_t; + using Genode::uint8_t; using Genode::Xml_node; using Genode::Dataspace_capability; using Genode::Attached_ram_dataspace; @@ -64,9 +66,9 @@ class Gui_fader::Src_buffer using Pixel = Pixel_rgb888; - bool const _use_alpha; Attached_ram_dataspace _ds; Texture<Pixel> _texture; + bool _warned_once = false; static size_t _needed_bytes(Area size) { @@ -74,25 +76,40 @@ class Gui_fader::Src_buffer return size.count() * (1 + 1 + sizeof(Pixel)); } + void _with_pixel_surface(auto const &fn) + { + Surface<Pixel_rgb888> pixel { _ds.local_addr<Pixel_rgb888>(), _texture.size() }; + fn(pixel); + } + public: - /** - * Constructor - */ - Src_buffer(Genode::Env &env, Area size, bool use_alpha) + Src_buffer(Genode::Env &env, Framebuffer::Mode mode) : - _use_alpha(use_alpha), - _ds(env.ram(), env.rm(), _needed_bytes(size)), + _ds(env.ram(), env.rm(), _needed_bytes(mode.area)), _texture(_ds.local_addr<Pixel>(), - _ds.local_addr<unsigned char>() + size.count()*sizeof(Pixel), - size) + mode.alpha ? _ds.local_addr<uint8_t>() + mode.area.count()*sizeof(Pixel) + : nullptr, + mode.area) { } Dataspace_capability dataspace() { return _ds.cap(); } Texture<Pixel> const &texture() const { return _texture; } - bool use_alpha() const { return _use_alpha; } + bool use_alpha() const { return _texture.alpha(); } + + void blit(Rect from, Point to) + { + if (_texture.alpha() && !_warned_once) { + Genode::warning("Framebuffer::Session::blit does not support alpha blending"); + _warned_once = true; + } + + _with_pixel_surface([&] (Surface<Pixel_rgb888> &surface) { + surface.clip({ to, from.area }); + Blit_painter::paint(surface, _texture, to - from.p1()); }); + } }; @@ -142,7 +159,6 @@ class Gui_fader::Framebuffer_session_component Constructible<Dst_buffer> _dst_buffer { }; - Lazy_value<int> _fade { }; public: @@ -207,7 +223,7 @@ class Gui_fader::Framebuffer_session_component transfer_src_to_dst_alpha(rect); - _gui.framebuffer.refresh(rect.x1(), rect.y1(), rect.w(), rect.h()); + _gui.framebuffer.refresh(rect); /* keep animating as long as the destination value is not reached */ return _fade != _fade.dst(); @@ -238,18 +254,44 @@ class Gui_fader::Framebuffer_session_component _gui.framebuffer.mode_sigh(sigh); } - void refresh(int x, int y, int w, int h) override + void refresh(Rect rect) override { - transfer_src_to_dst_pixel(Rect(Point(x, y), Area(w, h))); - transfer_src_to_dst_alpha(Rect(Point(x, y), Area(w, h))); + transfer_src_to_dst_pixel(rect); + transfer_src_to_dst_alpha(rect); - _gui.framebuffer.refresh(x, y, w, h); + _gui.framebuffer.refresh(rect); + } + + Blit_result blit(Framebuffer::Blit_batch const &batch) override + { + Framebuffer::Mode const mode { .area = _src_buffer.texture().size(), + .alpha = false }; + for (Framebuffer::Transfer const &transfer : batch.transfer) { + if (transfer.valid(mode)) { + _src_buffer.blit(transfer.from, transfer.to); + Rect const to_rect { transfer.to, transfer.from.area }; + refresh(to_rect); + } + } + return Blit_result::OK; + } + + void panning(Point pos) override + { + Rect const rect { { }, _src_buffer.texture().size() }; + + transfer_src_to_dst_pixel(rect); + transfer_src_to_dst_alpha(rect); + + _gui.framebuffer.panning(pos); } void sync_sigh(Genode::Signal_context_capability sigh) override { _gui.framebuffer.sync_sigh(sigh); } + + void sync_source(Genode::Session_label const &) override { } }; @@ -264,7 +306,8 @@ class Gui_fader::Gui_session_component Genode::Env &_env; - Reconstructible<Src_buffer> _src_buffer { _env, Area(1, 1), false }; + Reconstructible<Src_buffer> _src_buffer { + _env, Framebuffer::Mode { .area = { 1, 1 }, .alpha = false } }; Gui::Connection _gui { _env }; @@ -412,25 +455,15 @@ class Gui_fader::Gui_session_component return _gui.execute(); } - Framebuffer::Mode mode() override + Info_result info() override { return _gui.info_rom_cap(); } + + Buffer_result buffer(Framebuffer::Mode mode) override { - return _gui.mode(); - } + _src_buffer.construct(_env, mode); - void mode_sigh(Genode::Signal_context_capability sigh) override - { - _gui.mode_sigh(sigh); - } + _gui.buffer({ .area = mode.area, .alpha = true }); - Buffer_result buffer(Framebuffer::Mode mode, bool use_alpha) override - { - Area const size = mode.area; - - _src_buffer.construct(_env, size, use_alpha); - - _gui.buffer(mode, true); - - _fb_session.dst_buffer(_gui.framebuffer.dataspace(), size); + _fb_session.dst_buffer(_gui.framebuffer.dataspace(), mode.area); return Buffer_result::OK; } diff --git a/repos/gems/src/server/terminal/main.cc b/repos/gems/src/server/terminal/main.cc index f81db3a24b..c6ff2a1217 100644 --- a/repos/gems/src/server/terminal/main.cc +++ b/repos/gems/src/server/terminal/main.cc @@ -100,9 +100,33 @@ struct Terminal::Main : Character_consumer Signal_handler<Main> _config_handler { _env.ep(), *this, &Main::_handle_config }; + Gui::Area _initial_mode { }; + + Gui::Rect _gui_window_rect() + { + return _gui.window().convert<Gui::Rect>( + [&] (Gui::Rect rect) { return rect; }, + [&] (Gui::Undefined) { + Gui::Area const area = + _initial_mode.valid() ? _initial_mode + : Gui::Area { 1, 1 }; + return Gui::Rect { { }, area }; + }); + } + void _handle_mode_change() { - _fb_mode = _gui.mode(); + Rect const orig_win_rect = _win_rect; + + _win_rect = _gui_window_rect(); + + /* shrink view before shrinking the buffer to prevent tiling artifacts */ + Rect const intersection = Rect::intersect(orig_win_rect, _win_rect); + if (intersection != orig_win_rect) { + _gui.enqueue<Gui::Session::Command::Geometry>(_view, intersection); + _gui.execute(); + } + _handle_config(); } @@ -114,7 +138,7 @@ struct Terminal::Main : Character_consumer Constructible<Attached_dataspace> _fb_ds { }; - Framebuffer::Mode _fb_mode { }; + Gui::Rect _win_rect { }; Gui::View_id _view { }; @@ -143,7 +167,7 @@ struct Terminal::Main : Character_consumer bool _flush_scheduled = false; - Framebuffer::Mode _flushed_fb_mode { }; + Gui::Rect _flushed_win_rect { }; void _handle_flush() { @@ -151,22 +175,22 @@ struct Terminal::Main : Character_consumer if (_text_screen_surface.constructed() && _fb_ds.constructed()) { - Surface<PT> surface(_fb_ds->local_addr<PT>(), _fb_mode.area); + Surface<PT> surface(_fb_ds->local_addr<PT>(), _win_rect.area); Rect const dirty = _text_screen_surface->redraw(surface); - _gui.framebuffer.refresh(dirty.x1(), dirty.y1(), dirty.w(), dirty.h()); + _gui.framebuffer.refresh(dirty); } /* update view geometry after mode change */ - if (_fb_mode.area != _flushed_fb_mode.area) { + if (_win_rect != _flushed_win_rect) { using Command = Gui::Session::Command; - _gui.enqueue<Command::Geometry>(_view, Rect(Point(0, 0), _fb_mode.area)); + _gui.enqueue<Command::Geometry>(_view, _win_rect); _gui.enqueue<Command::Front>(_view); _gui.execute(); - _flushed_fb_mode = _fb_mode; + _flushed_win_rect = _win_rect; } } @@ -215,16 +239,16 @@ struct Terminal::Main : Character_consumer _config.sigh(_config_handler); _gui.input.sigh(_input_handler); - _gui.mode_sigh(_mode_change_handler); - - _fb_mode = _gui.mode(); + _gui.info_sigh(_mode_change_handler); /* apply initial size from config, if provided */ _config.xml().with_optional_sub_node("initial", [&] (Xml_node const &initial) { - _fb_mode.area = Area(initial.attribute_value("width", _fb_mode.area.w), - initial.attribute_value("height", _fb_mode.area.h)); + _initial_mode = { initial.attribute_value("width", _win_rect.w()), + initial.attribute_value("height", _win_rect.h()) }; }); + _win_rect = _gui_window_rect(); + _handle_config(); /* announce service at our parent */ @@ -243,7 +267,8 @@ void Terminal::Main::_handle_config() _font.destruct(); - _root_dir.apply_config(config.sub_node("vfs")); + config.with_optional_sub_node("vfs", [&] (Xml_node const &vfs_config) { + _root_dir.apply_config(vfs_config); }); Cached_font::Limit const cache_limit { config.attribute_value("cache", Number_of_bytes(256*1024)) }; @@ -259,9 +284,9 @@ void Terminal::Main::_handle_config() /* * Adapt terminal to font or framebuffer mode changes */ - _gui.buffer(_fb_mode, false); + _gui.buffer({ .area = _win_rect.area, .alpha = false }); - if (_fb_mode.area.count() > 0) + if (_win_rect.valid()) _fb_ds.construct(_env.rm(), _gui.framebuffer.dataspace()); /* @@ -276,7 +301,7 @@ void Terminal::Main::_handle_config() */ try { - Text_screen_surface<PT>::Geometry const new_geometry(_font->font(), _fb_mode.area); + Text_screen_surface<PT>::Geometry const new_geometry(_font->font(), _win_rect.area); bool const reconstruct = !_text_screen_surface.constructed() || _text_screen_surface->size() != new_geometry.size(); @@ -307,7 +332,7 @@ void Terminal::Main::_handle_config() : Position(); _text_screen_surface.construct(_heap, _font->font(), - _color_palette, _fb_mode.area); + _color_palette, _win_rect.area); if (snapshot.constructed()) _text_screen_surface->import(*snapshot); @@ -339,6 +364,9 @@ void Terminal::Main::_handle_config() void Terminal::Main::_handle_input() { + if (!_text_screen_surface.constructed()) + return; + _gui.input.for_each_event([&] (Input::Event const &event) { event.handle_absolute_motion([&] (int x, int y) { @@ -460,7 +488,7 @@ void Terminal::Main::_handle_input() void Terminal::Main::_report_clipboard_selection() { - if (!_clipboard_reporter.constructed()) + if (!_text_screen_surface.constructed() || !_clipboard_reporter.constructed()) return; _clipboard_reporter->generate([&] (Xml_generator &xml) { diff --git a/repos/gems/src/server/wm/decorator_gui.h b/repos/gems/src/server/wm/decorator_gui.h index 394b289392..067606c2dc 100644 --- a/repos/gems/src/server/wm/decorator_gui.h +++ b/repos/gems/src/server/wm/decorator_gui.h @@ -21,25 +21,14 @@ #include <input/component.h> /* local includes */ +#include <types.h> #include <window_registry.h> #include <pointer.h> #include <real_gui.h> -namespace Wm { class Main; - using Genode::size_t; - using Genode::Allocator; - using Genode::Arg_string; - using Genode::Object_pool; - using Genode::Attached_dataspace; - using Genode::Attached_ram_dataspace; - using Genode::Signal_handler; - using Genode::Reporter; - using Genode::Interface; -} - - namespace Wm { + class Main; struct Decorator_gui_session; struct Decorator_content_callback; struct Decorator_content_registry; @@ -58,8 +47,9 @@ struct Wm::Decorator_content_callback : Interface }; -struct Wm::Decorator_gui_session : Genode::Rpc_object<Gui::Session>, - private List<Decorator_gui_session>::Element +struct Wm::Decorator_gui_session : Session_object<Gui::Session>, + private List<Decorator_gui_session>::Element, + private Upgradeable { friend class List<Decorator_gui_session>; using List<Decorator_gui_session>::Element::next; @@ -80,17 +70,19 @@ struct Wm::Decorator_gui_session : Genode::Rpc_object<Gui::Session>, Gui::View_ids _content_view_ids { }; - Genode::Env &_env; + Env &_env; - Genode::Heap _heap { _env.ram(), _env.rm() }; + Constrained_ram_allocator _ram { _env.ram(), _ram_quota_guard(), _cap_quota_guard() }; - Genode::Ram_allocator &_ram; + Sliced_heap _session_alloc { _ram, _env.rm() }; - Real_gui _gui { _env, "decorator" }; + Slab<Content_view_ref, 4000> _content_view_ref_alloc { _session_alloc }; - Input::Session_client _input_session { _env.rm(), _gui.session.input() }; + Real_gui _real_gui { _env, "decorator" }; - Genode::Signal_context_capability _mode_sigh { }; + Input::Session_client _input_session { _env.rm(), _real_gui.session.input() }; + + Signal_context_capability _mode_sigh { }; Attached_ram_dataspace _client_command_ds { _ram, _env.rm(), sizeof(Command_buffer) }; @@ -102,48 +94,52 @@ struct Wm::Decorator_gui_session : Genode::Rpc_object<Gui::Session>, Decorator_content_callback &_content_callback; - Allocator &_md_alloc; + struct Dummy_input_action : Input::Session_component::Action + { + void exclusive_input_requested(bool) override { }; + + } _input_action { }; /* Gui::Connection requires a valid input session */ - Input::Session_component _dummy_input_component { _env, _env.ram() }; - Input::Session_capability _dummy_input_component_cap = - _env.ep().manage(_dummy_input_component); + Input::Session_component _dummy_input_component { + _env.ep(), _env.ram(), _env.rm(), _input_action }; Signal_handler<Decorator_gui_session> _input_handler { _env.ep(), *this, &Decorator_gui_session::_handle_input }; - Window_registry::Id _win_id_from_title(Gui::Title const &title) + void _with_win_id_from_title(Gui::Title const &title, auto const &fn) { unsigned value = 0; - Genode::ascii_to(title.string(), value); - return { value }; + if (ascii_to(title.string(), value)) + fn(Window_registry::Id { value }); } - /** - * Constructor - * - * \param ep entrypoint used for dispatching signals - */ - Decorator_gui_session(Genode::Env &env, - Genode::Ram_allocator &ram, - Allocator &md_alloc, - Pointer::Tracker &pointer_tracker, - Input::Session_component &window_layouter_input, + Decorator_gui_session(Env &env, + Resources const &resources, + Label const &label, + Diag const &diag, + Pointer::Tracker &pointer_tracker, + Input::Session_component &window_layouter_input, Decorator_content_callback &content_callback) : + Session_object<Gui::Session>(env.ep(), resources, label, diag), _env(env), - _ram(ram), _pointer_state(pointer_tracker), _window_layouter_input(window_layouter_input), - _content_callback(content_callback), - _md_alloc(md_alloc) + _content_callback(content_callback) { _input_session.sigh(_input_handler); } ~Decorator_gui_session() { - _env.ep().dissolve(_dummy_input_component); + while (_content_view_ids.apply_any<Content_view_ref>([&] (Content_view_ref &view_ref) { + destroy(_content_view_ref_alloc, &view_ref); })); + } + + void upgrade_local_or_remote(Resources const &resources) + { + _upgrade_local_or_remote(resources, *this, _real_gui); } void _handle_input() @@ -171,7 +167,7 @@ struct Wm::Decorator_gui_session : Genode::Rpc_object<Gui::Session>, [&] { }); /* forward command */ - _gui.enqueue(cmd); + _real_gui.enqueue(cmd); return; case Command::OFFSET: @@ -182,7 +178,7 @@ struct Wm::Decorator_gui_session : Genode::Rpc_object<Gui::Session>, */ _content_view_ids.apply<Content_view_ref const>(cmd.geometry.view, [&] (Content_view_ref const &) { }, - [&] { _gui.enqueue(cmd); }); + [&] { _real_gui.enqueue(cmd); }); return; case Command::FRONT: @@ -190,28 +186,24 @@ struct Wm::Decorator_gui_session : Genode::Rpc_object<Gui::Session>, case Command::FRONT_OF: case Command::BEHIND_OF: + _real_gui.enqueue(cmd); _content_view_ids.apply<Content_view_ref const>(cmd.front.view, [&] (Content_view_ref const &view_ref) { + _real_gui.execute(); _content_callback.update_content_child_views(view_ref.win_id); }, [&] { }); - _gui.enqueue(cmd); return; case Command::TITLE: case Command::BACKGROUND: case Command::NOP: - _gui.enqueue(cmd); + _real_gui.enqueue(cmd); return; } } - void upgrade(const char *args) - { - _gui.connection.upgrade(Genode::session_resources_from_args(args)); - } - Pointer::Position last_observed_pointer_pos() const { return _pointer_state.last_observed_pos(); @@ -224,7 +216,7 @@ struct Wm::Decorator_gui_session : Genode::Rpc_object<Gui::Session>, Framebuffer::Session_capability framebuffer() override { - return _gui.session.framebuffer(); + return _real_gui.session.framebuffer(); } Input::Session_capability input() override @@ -233,7 +225,12 @@ struct Wm::Decorator_gui_session : Genode::Rpc_object<Gui::Session>, * Deny input to the decorator. User input referring to the * window decorations is routed to the window manager. */ - return _dummy_input_component_cap; + return _dummy_input_component.cap(); + } + + Info_result info() override + { + return _real_gui.session.info(); } View_result view(View_id id, View_attr const &attr) override @@ -243,33 +240,38 @@ struct Wm::Decorator_gui_session : Genode::Rpc_object<Gui::Session>, * as view title. For such views, we import the view from the * corresponding GUI cient instead of creating a new view. */ - Window_registry::Id const win_id = _win_id_from_title(attr.title); - if (win_id.valid()) { + bool out_of_ram = false, out_of_caps = false, associated = false; + _with_win_id_from_title(attr.title, [&] (Window_registry::Id win_id) { try { - Content_view_ref &view_ref_ptr = *new (_heap) + Content_view_ref &view_ref_ptr = *new (_content_view_ref_alloc) Content_view_ref(Window_registry::Id(win_id), _content_view_ids, id); View_capability view_cap = _content_callback.content_view(win_id); - Associate_result result = _gui.session.associate(id, view_cap); + Associate_result result = _real_gui.session.associate(id, view_cap); if (result != Associate_result::OK) - destroy(_heap, &view_ref_ptr); + destroy(_content_view_ref_alloc, &view_ref_ptr); switch (result) { - case Associate_result::OUT_OF_RAM: return View_result::OUT_OF_RAM; - case Associate_result::OUT_OF_CAPS: return View_result::OUT_OF_CAPS; - case Associate_result::OK: return View_result::OK; + case Associate_result::OUT_OF_RAM: out_of_ram = true; break; + case Associate_result::OUT_OF_CAPS: out_of_caps = true; break; + case Associate_result::OK: associated = true; break; case Associate_result::INVALID: break; /* fall back to regular view */ }; } - catch (Genode::Out_of_ram) { return View_result::OUT_OF_RAM; } - catch (Genode::Out_of_caps) { return View_result::OUT_OF_CAPS; } - } - return _gui.session.view(id, attr); + catch (Out_of_ram) { _starved_for_ram = out_of_ram = true; } + catch (Out_of_caps) { _starved_for_caps = out_of_caps = true; } + }); + + if (out_of_ram) return View_result::OUT_OF_RAM; + if (out_of_caps) return View_result::OUT_OF_CAPS; + if (associated) return View_result::OK; + + return _real_gui.session.view(id, attr); } Child_view_result child_view(View_id id, View_id parent, View_attr const &attr) override { - return _gui.session.child_view(id, parent, attr); + return _real_gui.session.child_view(id, parent, attr); } void destroy_view(View_id view) override @@ -283,36 +285,36 @@ struct Wm::Decorator_gui_session : Genode::Rpc_object<Gui::Session>, _content_callback.hide_content_child_views(view_ref.win_id); Gui::Rect rect(Gui::Point(0, 0), Gui::Area(0, 0)); - _gui.enqueue<Gui::Session::Command::Geometry>(view, rect); - _gui.execute(); + _real_gui.enqueue<Gui::Session::Command::Geometry>(view, rect); + _real_gui.execute(); - destroy(_heap, &view_ref); + destroy(_content_view_ref_alloc, &view_ref); }, [&] { }); - _gui.session.destroy_view(view); + _real_gui.session.destroy_view(view); } Associate_result associate(View_id id, View_capability view_cap) override { - return _gui.session.associate(id, view_cap); + return _real_gui.session.associate(id, view_cap); } View_capability_result view_capability(View_id view) override { - return _gui.session.view_capability(view); + return _real_gui.session.view_capability(view); } void release_view_id(View_id view) override { _content_view_ids.apply<Content_view_ref>(view, - [&] (Content_view_ref &view_ref) { destroy(_heap, &view_ref); }, + [&] (Content_view_ref &view_ref) { destroy(_content_view_ref_alloc, &view_ref); }, [&] { }); - _gui.session.release_view_id(view); + _real_gui.session.release_view_id(view); } - Genode::Dataspace_capability command_dataspace() override + Dataspace_capability command_dataspace() override { return _client_command_ds.cap(); } @@ -322,30 +324,15 @@ struct Wm::Decorator_gui_session : Genode::Rpc_object<Gui::Session>, for (unsigned i = 0; i < _client_command_buffer.num(); i++) _execute_command(_client_command_buffer.get(i)); - _gui.execute(); + _real_gui.execute(); } - Framebuffer::Mode mode() override + Buffer_result buffer(Framebuffer::Mode mode) override { - return _gui.session.mode(); + return _real_gui.session.buffer(mode); } - void mode_sigh(Genode::Signal_context_capability sigh) override - { - /* - * Remember signal-context capability to keep NOVA from revoking - * transitive delegations of the capability. - */ - _mode_sigh = sigh; - _gui.session.mode_sigh(sigh); - } - - Buffer_result buffer(Framebuffer::Mode mode, bool use_alpha) override - { - return _gui.session.buffer(mode, use_alpha); - } - - void focus(Genode::Capability<Gui::Session>) override { } + void focus(Capability<Gui::Session>) override { } }; #endif /* _DECORATOR_GUI_H_ */ diff --git a/repos/gems/src/server/wm/direct_gui.h b/repos/gems/src/server/wm/direct_gui.h index d1080a126b..76b0f134f8 100644 --- a/repos/gems/src/server/wm/direct_gui.h +++ b/repos/gems/src/server/wm/direct_gui.h @@ -21,16 +21,14 @@ namespace Wm { class Direct_gui_session; } -class Wm::Direct_gui_session : public Genode::Rpc_object<Gui::Session> +class Wm::Direct_gui_session : public Session_object<Gui::Session> { private: - Genode::Env &_env; + Env &_env; - Genode::Session_label _label; - - Genode::Connection<Gui::Session> _connection { - _env, _label, Genode::Ram_quota { 36*1024 }, /* Args */ { } }; + Connection<Gui::Session> _connection { + _env, _label, Ram_quota { 36*1024 }, /* Args */ { } }; Gui::Session_client _session { _connection.cap() }; @@ -39,12 +37,10 @@ class Wm::Direct_gui_session : public Genode::Rpc_object<Gui::Session> public: - /** - * Constructor - */ - Direct_gui_session(Genode::Env &env, Genode::Session_label const &label) + Direct_gui_session(Env &env, auto &&... args) : - _env(env), _label(label) + Session_object<Gui::Session>(env.ep(), args...), + _env(env) { } void upgrade(char const *args) @@ -98,7 +94,7 @@ class Wm::Direct_gui_session : public Genode::Rpc_object<Gui::Session> _session.release_view_id(view); } - Genode::Dataspace_capability command_dataspace() override + Dataspace_capability command_dataspace() override { return _session.command_dataspace(); } @@ -108,22 +104,17 @@ class Wm::Direct_gui_session : public Genode::Rpc_object<Gui::Session> _session.execute(); } - Framebuffer::Mode mode() override + Info_result info() override { - return _session.mode(); + return _session.info(); } - void mode_sigh(Genode::Signal_context_capability sigh) override + Buffer_result buffer(Framebuffer::Mode mode) override { - _session.mode_sigh(sigh); + return _session.buffer(mode); } - Buffer_result buffer(Framebuffer::Mode mode, bool use_alpha) override - { - return _session.buffer(mode, use_alpha); - } - - void focus(Genode::Capability<Gui::Session> session) override + void focus(Capability<Gui::Session> session) override { _session.focus(session); } diff --git a/repos/gems/src/server/wm/gui.h b/repos/gems/src/server/wm/gui.h index 3379749ae4..8819828f89 100644 --- a/repos/gems/src/server/wm/gui.h +++ b/repos/gems/src/server/wm/gui.h @@ -15,17 +15,11 @@ #define _GUI_H_ /* Genode includes */ -#include <util/list.h> -#include <base/tslab.h> -#include <os/surface.h> -#include <base/attached_ram_dataspace.h> -#include <os/session_policy.h> -#include <os/reporter.h> -#include <os/session_policy.h> #include <root/component.h> #include <gui_session/connection.h> #include <input_session/capability.h> #include <input/component.h> +#include <os/dynamic_rom_session.h> /* local includes */ #include <window_registry.h> @@ -33,26 +27,6 @@ #include <layouter_gui.h> #include <direct_gui.h> - -namespace Wm { - - using Genode::Rpc_object; - using Genode::List; - using Genode::Allocator; - using Genode::Affinity; - using Genode::static_cap_cast; - using Genode::Signal_handler; - using Genode::Weak_ptr; - using Genode::Locked_ptr; - using Genode::Tslab; - using Genode::Attached_ram_dataspace; - using Genode::Signal_context_capability; - using Genode::Signal_transmitter; - using Genode::Reporter; - using Genode::Capability; - using Genode::Interface; -} - namespace Wm { namespace Gui { using namespace ::Gui; @@ -65,10 +39,6 @@ namespace Wm { namespace Gui { class Session_control_fn; class Session_component; class Root; - - using Rect = Genode::Surface_base::Rect; - using Point = Genode::Surface_base::Point; - using Session_label = Genode::Session_label; } } @@ -97,13 +67,12 @@ struct Wm::Gui::Input_origin_changed_handler : Interface }; -class Wm::Gui::View : private Genode::Weak_object<View>, - public Genode::Rpc_object< ::Gui::View> +class Wm::Gui::View : private Weak_object<View>, public Rpc_object< ::Gui::View> { private: - friend class Genode::Weak_ptr<View>; - friend class Genode::Locked_ptr<View>; + friend class Weak_ptr<View>; + friend class Locked_ptr<View>; protected: @@ -121,6 +90,7 @@ class Wm::Gui::View : private Genode::Weak_object<View>, Weak_ptr<View> _neighbor_ptr { }; bool _neighbor_behind { }; bool _has_alpha; + bool _layouted = false; void _with_temporary_view_id(View_capability cap, auto const &fn) { @@ -141,12 +111,11 @@ class Wm::Gui::View : private Genode::Weak_object<View>, }; View(Real_gui &real_gui, - View_id const &real_view_id, Session_label const &session_label, bool has_alpha) : _session_label(session_label), _real_gui(real_gui), - _real_view(_real_view_ref, _real_gui.view_ids, real_view_id), + _real_view(_real_view_ref, _real_gui.view_ids), _has_alpha(has_alpha) { } @@ -197,8 +166,8 @@ class Wm::Gui::View : private Genode::Weak_object<View>, _real_gui.session.destroy_view(_real_view.id()); } - using Genode::Weak_object<View>::weak_ptr; - using Genode::Weak_object<View>::lock_for_destruction; + using Weak_object<View>::weak_ptr; + using Weak_object<View>::lock_for_destruction; Point virtual_position() const { return _geometry.at; } @@ -241,16 +210,22 @@ class Wm::Gui::View : private Genode::Weak_object<View>, } bool has_alpha() const { return _has_alpha; } + + bool layouted() const { return _layouted; } }; class Wm::Gui::Top_level_view : public View, private List<Top_level_view>::Element { + public: + + using View_result = Gui::Session::View_result; + private: friend class List<Top_level_view>; - Window_registry::Id _win_id { }; + Window_registry::Create_result _win_id = Window_registry::Create_error::IDS_EXHAUSTED; Window_registry &_window_registry; @@ -268,37 +243,46 @@ class Wm::Gui::Top_level_view : public View, private List<Top_level_view>::Eleme Session_label const _session_label; + View_result _init_real_view() + { + return _real_gui.session.view(_real_view.id(), { .title = _title, + .rect = { }, + .front = false }); + } + + View_result const _real_view_result = _init_real_view(); + using Command = Gui::Session::Command; + void _with_optional_win_id(auto const &fn) const + { + _win_id.with_result([&] (Window_registry::Id id) { fn(id); }, + [&] (Window_registry::Create_error) { }); + } + public: Top_level_view(Real_gui &real_gui, - View_id view_id, bool has_alpha, Window_registry &window_registry, Input_origin_changed_handler &input_origin_changed_handler) : - View(real_gui, view_id, real_gui.label, has_alpha), + View(real_gui, real_gui.label, has_alpha), _window_registry(window_registry), _input_origin_changed_handler(input_origin_changed_handler), _session_label(real_gui.label) - { - /* - * Create and configure physical GUI view. - */ - _real_gui.session.view(_real_view.id(), { .title = _title, - .rect = { }, - .front = false }); - } + { } ~Top_level_view() { - if (_win_id.valid()) - _window_registry.destroy(_win_id); + _with_optional_win_id([&] (Window_registry::Id id) { + _window_registry.destroy(id); }); View::lock_for_destruction(); } + View_result real_view_result() const { return _real_view_result; } + using List<Top_level_view>::Element::next; void _propagate_view_geometry() override { } @@ -310,16 +294,20 @@ class Wm::Gui::Top_level_view : public View, private List<Top_level_view>::Eleme * defer the creation of the window ID until the time when the * initial geometry is known. */ - if (!_win_id.valid()) { - _win_id = _window_registry.create(); - _window_registry.title(_win_id, _window_title); - _window_registry.label(_win_id, _session_label); - _window_registry.has_alpha(_win_id, View::has_alpha()); - _window_registry.resizeable(_win_id, _resizeable); + if (!_win_id.ok()) { + _win_id = _window_registry.create({ + .title = _window_title, + .label = _session_label, + .area = geometry.area, + .alpha = { View::has_alpha() }, + .hidden = { }, + .resizeable = { _resizeable } + }); + } else { + _with_optional_win_id([&] (Window_registry::Id id) { + _window_registry.area(id, geometry.area); }); } - _window_registry.size(_win_id, geometry.area); - View::geometry(geometry); } @@ -331,11 +319,17 @@ class Wm::Gui::Top_level_view : public View, private List<Top_level_view>::Eleme _window_title = title; - if (_win_id.valid()) - _window_registry.title(_win_id, _window_title); + _with_optional_win_id([&] (Window_registry::Id id) { + _window_registry.title(id, _window_title); }); } - bool has_win_id(Window_registry::Id id) const { return id == _win_id; } + bool has_win_id(Window_registry::Id id) const + { + bool result = false; + _with_optional_win_id([&] (Window_registry::Id this_id) { + result = (this_id == id); }); + return result; + } bool belongs_to_win_id(Window_registry::Id id) const override { @@ -353,26 +347,36 @@ class Wm::Gui::Top_level_view : public View, private List<Top_level_view>::Eleme _content_geometry = rect; + _layouted = true; + if (position_changed) _input_origin_changed_handler.input_origin_changed(); } View_capability content_view() { return real_view_cap(); } - void hidden(bool hidden) { _window_registry.hidden(_win_id, hidden); } + void hidden(bool hidden) + { + _with_optional_win_id([&] (Window_registry::Id id) { + _window_registry.hidden(id, hidden); }); + } void resizeable(bool resizeable) { _resizeable = resizeable; - if (_win_id.valid()) - _window_registry.resizeable(_win_id, resizeable); + _with_optional_win_id([&] (Window_registry::Id id) { + _window_registry.resizeable(id, resizeable); }); } }; class Wm::Gui::Child_view : public View, private List<Child_view>::Element { + public: + + using View_result = Gui::Session::Child_view_result; + private: friend class List<Child_view>; @@ -381,23 +385,24 @@ class Wm::Gui::Child_view : public View, private List<Child_view>::Element bool _visible = false; + View_result _real_view_result = try_to_init_real_view(); + public: Child_view(Real_gui &real_gui, - View_id real_gui_id, bool has_alpha, Weak_ptr<View> parent) : - View(real_gui, real_gui_id, real_gui.label, has_alpha), _parent(parent) - { - try_to_init_real_view(); - } + View(real_gui, real_gui.label, has_alpha), _parent(parent) + { } ~Child_view() { View::lock_for_destruction(); } + View_result real_view_result() const { return _real_view_result; } + using List<Child_view>::Element::next; void _propagate_view_geometry() override @@ -410,7 +415,14 @@ class Wm::Gui::Child_view : public View, private List<Child_view>::Element _neighbor_ptr = neighbor_ptr; _neighbor_behind = behind; - _apply_view_config(); + auto parent_position_known = [&] + { + Locked_ptr<View> parent(_parent); + return parent.valid() && parent->layouted(); + }; + + if (parent_position_known()) + _apply_view_config(); } bool belongs_to_win_id(Window_registry::Id id) const override @@ -428,11 +440,15 @@ class Wm::Gui::Child_view : public View, private List<Child_view>::Element return Point(); } - void try_to_init_real_view() + View_result try_to_init_real_view() { + using Child_view_result = Gui::Session::Child_view_result; + + Child_view_result result = Child_view_result::INVALID; + Locked_ptr<View> parent(_parent); if (!parent.valid()) - return; + return result; _with_temporary_view_id(parent->real_view_cap(), [&] (View_id parent_id) { @@ -443,22 +459,24 @@ class Wm::Gui::Child_view : public View, private List<Child_view>::Element .rect = _geometry, .front = false }; - switch (_real_gui.session.child_view(_real_view.id(), parent_id, attr)) { - case Gui::Session::Child_view_result::OUT_OF_RAM: - case Gui::Session::Child_view_result::OUT_OF_CAPS: - case Gui::Session::Child_view_result::INVALID: + result = _real_gui.session.child_view(_real_view.id(), parent_id, attr); + + if (result != Child_view_result::OK) { warning("unable to create child view"); return; - case Gui::Session::Child_view_result::OK: - break; - }; + } + _visible = true; }); - if (_neighbor_ptr == _parent) - _unsynchronized_apply_view_config(parent); - else - _apply_view_config(); + if (parent->layouted()) { + if (_neighbor_ptr == _parent) + _unsynchronized_apply_view_config(parent); + else + _apply_view_config(); + } + + return result; } void update_child_stacking() @@ -474,10 +492,20 @@ class Wm::Gui::Child_view : public View, private List<Child_view>::Element }; -class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, +class Wm::Gui::Session_component : public Session_object<Gui::Session>, private List<Session_component>::Element, - private Input_origin_changed_handler + private Input_origin_changed_handler, + private Upgradeable, + private Dynamic_rom_session::Xml_producer, + private Input::Session_component::Action { + public: + + struct Action : Interface + { + virtual void gen_screen_area_info(Xml_generator &) const = 0; + }; + private: friend class List<Session_component>; @@ -513,30 +541,90 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, } }; - Genode::Env &_env; + Env &_env; + Action &_action; - Session_label _session_label; - Genode::Ram_allocator &_ram; - Real_gui _real_gui { _env, _session_label }; + Constrained_ram_allocator _ram { + _env.ram(), _ram_quota_guard(), _cap_quota_guard() }; + + Sliced_heap _session_alloc { _ram, _env.rm() }; + Real_gui _real_gui { _env, _label }; Window_registry &_window_registry; - Tslab<Top_level_view, 8000> _top_level_view_alloc; - Tslab<Child_view, 7000> _child_view_alloc; - Tslab<View_ref, 4000> _view_ref_alloc; + Slab<Top_level_view, 8000> _top_level_view_alloc { _session_alloc }; + Slab<Child_view, 7000> _child_view_alloc { _session_alloc }; + Slab<View_ref, 4000> _view_ref_alloc { _session_alloc }; List<Top_level_view> _top_level_views { }; List<Child_view> _child_views { }; View_ids _view_ids { }; - Input::Session_component _input_session { _env, _ram }; - Input::Session_capability _input_session_cap; - Click_handler &_click_handler; - Signal_context_capability _mode_sigh { }; - Area _requested_size { }; - bool _resize_requested = false; - bool _has_alpha = false; - Pointer::State _pointer_state; - Point const _initial_pointer_pos { -1, -1 }; - Point _pointer_pos = _initial_pointer_pos; - Point _virtual_pointer_pos { }; - unsigned _key_cnt = 0; + + Input::Session_component _input_session { + _env.ep(), _ram, _env.rm(), *this }; + + bool _exclusive_input_requested = false, + _exclusive_input_granted = false; + + /* used for hiding the click-to-grab event from the client */ + bool _consume_one_btn_left_release = false; + + /** + * Input::Session_component::Action interface + */ + void exclusive_input_requested(bool const requested) override + { + if (requested == _exclusive_input_requested) + return; + + /* + * Allow immediate changes when + * + * 1. Exclusive input is already granted by the user having clicked + * into the window, or + * 2. The client yields the exclusivity, or + * 3. Transient exclusive input is requested while a button is held. + * In this case, exclusive input will be revoked as soon as the + * last button/key is released. + */ + if (_exclusive_input_granted || _key_cnt || !requested) + _gui_input.exclusive(requested); + + _exclusive_input_requested = requested; + } + + Click_handler &_click_handler; + + struct Info_rom_session : Dynamic_rom_session + { + Session_component &_session; + + Info_rom_session(Session_component &session, auto &&... args) + : Dynamic_rom_session(args...), _session(session) { } + + void sigh(Signal_context_capability sigh) override + { + Dynamic_rom_session::sigh(sigh); + + /* + * We consider a window as resizable if the client shows interest + * in mode-change notifications. + */ + _session._resizeable = sigh.valid(); + for (Top_level_view *v = _session._top_level_views.first(); v; v = v->next()) + v->resizeable(_session._resizeable); + } + }; + + Constructible<Info_rom_session> _info_rom { }; + + bool _resizeable = false; + Area _requested_size { }; + bool _resize_requested = false; + bool _close_requested = false; + bool _has_alpha = false; + Pointer::State _pointer_state; + Point const _initial_pointer_pos { -1, -1 }; + Point _pointer_pos = _initial_pointer_pos; + Point _virtual_pointer_pos { }; + unsigned _key_cnt = 0; auto _with_view(View_id id, auto const &fn, auto const &missing_fn) -> decltype(missing_fn()) @@ -568,9 +656,6 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, Signal_handler<Session_component> _input_handler { _env.ep(), *this, &Session_component::_handle_input }; - Signal_handler<Session_component> _mode_handler { - _env.ep(), *this, &Session_component::_handle_mode_change }; - Point _input_origin() const { if (Top_level_view const *v = _top_level_views.first()) @@ -675,20 +760,78 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, if (propagate_to_pointer_state) _pointer_state.apply_event(ev); + /* + * Handle pointer grabbing/ungrabbing + */ + + /* revoke transient exclusive input (while clicked) */ + if (ev.release() && _key_cnt == 0) + if (_exclusive_input_requested && !_exclusive_input_granted) + _gui_input.exclusive(false); + + /* grant exclusive input when clicking into window */ + if (ev.key_press(Input::BTN_LEFT) && _key_cnt == 1) { + if (_exclusive_input_requested && !_exclusive_input_granted) { + _gui_input.exclusive(true); + _exclusive_input_granted = true; + _consume_one_btn_left_release = true; + continue; + } + } + if (ev.key_release(Input::BTN_LEFT)) { + if (_consume_one_btn_left_release) { + _consume_one_btn_left_release = false; + continue; + } + } + /* submit event to the client */ _input_session.submit(_translate_event(ev, input_origin)); } } } - void _handle_mode_change() + /** + * Dynamic_rom_session::Xml_producer interface + */ + void produce_xml(Xml_generator &xml) override { - /* - * Inform a viewless client about the upstream - * mode change. - */ - if (_mode_sigh.valid() && !_top_level_views.first()) - Signal_transmitter(_mode_sigh).submit(); + _action.gen_screen_area_info(xml); + + if (_close_requested) { + xml.node("capture", [&] { xml.attribute("closed", "yes"); }); + return; + } + + auto virtual_capture_area = [&] + { + /* + * While resizing the window, return requested window size as + * mode + */ + if (_resize_requested) + return _requested_size; + + /* + * If the first top-level view has a defined size, use it + * as the size of the virtualized GUI session. + */ + if (Top_level_view const *v = _top_level_views.first()) + if (v->size().valid()) + return v->size(); + + return Area { }; + }; + + auto gen_attr = [&] (Area const area) + { + if (area.valid()) { + xml.attribute("width", area.w); + xml.attribute("height", area.h); + } + }; + + xml.node("capture", [&] { gen_attr(virtual_capture_area()); }); } /** @@ -704,18 +847,26 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, _input_session.submit(Input::Absolute_motion { pos.x, pos.y }); } + void _dissolve_view_from_ep(View &view) + { + if (view.cap().valid()) { + _env.ep().dissolve(view); + replenish(Cap_quota { 1 }); + } + } + void _destroy_top_level_view(Top_level_view &view) { _top_level_views.remove(&view); - _env.ep().dissolve(view); - Genode::destroy(&_top_level_view_alloc, &view); + _dissolve_view_from_ep(view); + destroy(&_top_level_view_alloc, &view); } void _destroy_child_view(Child_view &view) { _child_views.remove(&view); - _env.ep().dissolve(view); - Genode::destroy(&_child_view_alloc, &view); + _dissolve_view_from_ep(view); + destroy(&_child_view_alloc, &view); } void _execute_command(Command const &command) @@ -764,8 +915,8 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, char sanitized_title[args.title.capacity()]; - Genode::copy_cstring(sanitized_title, command.title.title.string(), - sizeof(sanitized_title)); + copy_cstring(sanitized_title, command.title.title.string(), + sizeof(sanitized_title)); for (char *c = sanitized_title; *c; c++) if (*c == '"') @@ -785,32 +936,23 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, public: - /** - * Constructor - * - * \param ep entrypoint used for managing the views - */ - Session_component(Genode::Env &env, - Genode::Ram_allocator &ram, - Window_registry &window_registry, - Allocator &session_alloc, - Session_label const &session_label, - Pointer::Tracker &pointer_tracker, - Click_handler &click_handler) + Session_component(Env &env, + Action &action, + Resources const &resources, + Label const &label, + Diag const diag, + Window_registry &window_registry, + Pointer::Tracker &pointer_tracker, + Click_handler &click_handler) : - _env(env), - _session_label(session_label), - _ram(ram), + Session_object<Gui::Session>(env.ep(), resources, label, diag), + Xml_producer("panorama"), + _env(env), _action(action), _window_registry(window_registry), - _top_level_view_alloc(&session_alloc), - _child_view_alloc(&session_alloc), - _view_ref_alloc(&session_alloc), - _input_session_cap(env.ep().manage(_input_session)), _click_handler(click_handler), _pointer_state(pointer_tracker) { _gui_input.sigh(_input_handler); - _real_gui.session.mode_sigh(_mode_handler); _input_session.event_queue().enabled(true); } @@ -824,15 +966,13 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, while (Child_view *view = _child_views.first()) _destroy_child_view(*view); - - _env.ep().dissolve(_input_session); } using List<Session_component>::Element::next; - void upgrade(char const *args) + void upgrade_local_or_remote(Resources const &resources) { - _real_gui.connection.upgrade(Genode::session_resources_from_args(args)); + _upgrade_local_or_remote(resources, *this, _real_gui); } void try_to_init_real_child_views() @@ -869,13 +1009,13 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, View_capability content_view(Window_registry::Id id) { for (Top_level_view *v = _top_level_views.first(); v; v = v->next()) - if (v->has_win_id(id.value)) + if (v->has_win_id(id)) return v->content_view(); return View_capability(); } - bool has_win_id(unsigned id) const + bool has_win_id(Window_registry::Id id) const { for (Top_level_view const *v = _top_level_views.first(); v; v = v->next()) if (v->has_win_id(id)) @@ -884,8 +1024,6 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, return false; } - Session_label session_label() const { return _session_label; } - bool matches_session_label(char const *selector) const { using namespace Genode; @@ -896,7 +1034,7 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, * * The code snippet originates from nitpicker's 'gui_session.h'. */ - String<Session_label::capacity() + 4> const label(_session_label, " ->"); + String<Session_label::capacity() + 4> const label(_label, " ->"); return strcmp(label.string(), selector, strlen(selector)) == 0; } @@ -905,9 +1043,12 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, _requested_size = size; _resize_requested = true; + if (_requested_size.count() == 0) + _close_requested = true; + /* notify client */ - if (_mode_sigh.valid()) - Signal_transmitter(_mode_sigh).submit(); + if (_info_rom.constructed()) + _info_rom->trigger_update(); } void hidden(bool hidden) @@ -926,6 +1067,20 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, */ Capability<Session> session() { return _real_gui.connection.cap(); } + void propagate_mode_change() + { + if (_info_rom.constructed()) + _info_rom->trigger_update(); + } + + void revoke_exclusive_input() + { + if (_exclusive_input_granted) { + _gui_input.exclusive(false); + _exclusive_input_granted = false; + } + } + /*************************** ** GUI session interface ** @@ -938,39 +1093,64 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, Input::Session_capability input() override { - return _input_session_cap; + return _input_session.cap(); } template <typename VIEW> - View_result _create_view_with_id(auto &dealloc, View_id id, View_attr const &attr, auto const &create_fn) + VIEW::View_result _create_view_with_id(auto &dealloc, View_id id, View_attr const &attr, auto const &create_fn) { + using Result = VIEW::View_result; + + /* precondition for obtaining 'real_view_cap' */ + if (!try_withdraw(Cap_quota { 1 })) { + _starved_for_caps = true; + return Result::OUT_OF_CAPS; + } + release_view_id(id); - View_result error { }; + Result error { }; VIEW *view_ptr = nullptr; try { view_ptr = &create_fn(); } - catch (Out_of_ram) { error = View_result::OUT_OF_RAM; } - catch (Out_of_caps) { error = View_result::OUT_OF_CAPS; } + catch (Out_of_ram) { + _starved_for_ram = true; + error = Result::OUT_OF_RAM; + } + catch (Out_of_caps) { + _starved_for_caps = true; + error = Result::OUT_OF_CAPS; + } if (!view_ptr) return error; + /* _real_gui view creation may return OUT_OF_RAM or OUT_OF_CAPS */ + if (view_ptr->real_view_result() != Result::OK) { + error = view_ptr->real_view_result(); + destroy(dealloc, view_ptr); + return error; + } + View_ref *view_ref_ptr = nullptr; try { view_ref_ptr = new (_view_ref_alloc) View_ref(view_ptr->weak_ptr(), _view_ids, id); } - catch (Out_of_ram) { error = View_result::OUT_OF_RAM; } - catch (Out_of_caps) { error = View_result::OUT_OF_CAPS; } + catch (Out_of_ram) { + _starved_for_ram = true; + error = Result::OUT_OF_RAM; + } + catch (Out_of_caps) { + _starved_for_caps = true; + error = Result::OUT_OF_CAPS; + } if (!view_ref_ptr) { destroy(dealloc, view_ptr); return error; } - _env.ep().manage(*view_ptr); - /* apply initial view attributes */ _execute_command(Command::Title { id, attr.title }); _execute_command(Command::Geometry { id, attr.rect }); @@ -979,7 +1159,7 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, _window_registry.flush(); } - return View_result::OK; + return Result::OK; } View_result view(View_id id, View_attr const &attr) override @@ -990,13 +1170,13 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, _create_view_with_id<Top_level_view>(_top_level_view_alloc, id, attr, [&] () -> Top_level_view & { view_ptr = new (_top_level_view_alloc) - Top_level_view(_real_gui, id, _has_alpha, + Top_level_view(_real_gui, _has_alpha, _window_registry, *this); return *view_ptr; }); if (result == View_result::OK && view_ptr) { - view_ptr->resizeable(_mode_sigh.valid()); + view_ptr->resizeable(_resizeable); _top_level_views.insert(view_ptr); } return result; @@ -1009,24 +1189,18 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, Child_view *view_ptr = nullptr; - View_result const result = + Child_view_result const result = _create_view_with_id<Child_view>(_child_view_alloc, id, attr, [&] () -> Child_view & { view_ptr = new (_child_view_alloc) - Child_view(_real_gui, id, _has_alpha, parent.weak_ptr()); + Child_view(_real_gui, _has_alpha, parent.weak_ptr()); return *view_ptr; }); - switch (result) { - case View_result::OUT_OF_RAM: return Child_view_result::OUT_OF_RAM; - case View_result::OUT_OF_CAPS: return Child_view_result::OUT_OF_CAPS; - case View_result::OK: break; - } - - if (view_ptr) + if (result == Child_view_result::OK && view_ptr) _child_views.insert(view_ptr); - return Child_view_result::OK; + return result; }, [&] () -> Child_view_result { return Child_view_result::INVALID; }); } @@ -1038,11 +1212,13 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, for (Child_view *v = _child_views.first(); v; v = v->next()) if (&view == v) { _destroy_child_view(*v); + replenish(Cap_quota { 1 }); return; } for (Top_level_view *v = _top_level_views.first(); v; v = v->next()) if (&view == v) { _destroy_top_level_view(*v); + replenish(Cap_quota { 1 }); return; } }, @@ -1064,16 +1240,32 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, new (_view_ref_alloc) View_ref(view_ptr->weak_ptr(), _view_ids, id); return Associate_result::OK; } - catch (Out_of_ram) { return Associate_result::OUT_OF_RAM; } - catch (Out_of_caps) { return Associate_result::OUT_OF_CAPS; } + catch (Out_of_ram) { + _starved_for_ram = true; + return Associate_result::OUT_OF_RAM; + } + catch (Out_of_caps) { + _starved_for_caps = true; + return Associate_result::OUT_OF_CAPS; + } }); } View_capability_result view_capability(View_id id) override { return _with_view(id, - [&] (View &view) { return view.cap(); }, - [&] /* view does not exist */ { return View_capability(); }); + [&] (View &view) -> View_capability_result + { + if (!view.cap().valid()) { + if (!try_withdraw(Cap_quota { 1 })) { + _starved_for_caps = true; + return View_capability_error::OUT_OF_CAPS; + } + _env.ep().manage(view); + } + return view.cap(); + }, + [&] () -> View_capability_result { return View_capability(); }); } void release_view_id(View_id id) override @@ -1083,7 +1275,7 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, [&] { }); } - Genode::Dataspace_capability command_dataspace() override + Dataspace_capability command_dataspace() override { return _command_ds.cap(); } @@ -1097,46 +1289,38 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, _window_registry.flush(); } - Framebuffer::Mode mode() override + Info_result info() override { - Framebuffer::Mode const real_mode = _real_gui.session.mode(); + if (!_info_rom.constructed()) { + Cap_quota const needed_caps { 2 }; + if (!_cap_quota_guard().have_avail(needed_caps)) { + _starved_for_caps = true; + return Info_error::OUT_OF_CAPS; + } - /* - * While resizing the window, return requested window size as - * mode - */ - if (_resize_requested) - return Framebuffer::Mode { .area = _requested_size }; + Ram_quota const needed_ram { 8*1024 }; + if (!_ram_quota_guard().have_avail(needed_ram)) { + _starved_for_ram = true; + return Info_error::OUT_OF_RAM; + } - /* - * If the first top-level view has a defined size, use it - * as the size of the virtualized GUI session. - */ - if (Top_level_view const *v = _top_level_views.first()) - if (v->size().valid()) - return Framebuffer::Mode { .area = v->size() }; + try { + Dynamic_rom_session::Content_producer &rom_producer = *this; + _info_rom.construct(*this, _env.ep(), _ram, _env.rm(), rom_producer); + _info_rom->dataspace(); /* eagerly consume RAM and caps */ + } + catch (Out_of_ram) { _starved_for_ram = true; } + catch (Out_of_caps) { _starved_for_caps = true; } - /* - * If top-level view has yet been defined, return the real mode. - */ - return real_mode; + if (_starved_for_ram || _starved_for_caps) { + if (_starved_for_ram) return Info_error::OUT_OF_RAM; + if (_starved_for_caps) return Info_error::OUT_OF_CAPS; + } + } + return _info_rom->cap(); } - void mode_sigh(Genode::Signal_context_capability sigh) override - { - _mode_sigh = sigh; - - /* - * We consider a window as resizable if the client shows interest - * in mode-change notifications. - */ - bool const resizeable = _mode_sigh.valid(); - - for (Top_level_view *v = _top_level_views.first(); v; v = v->next()) - v->resizeable(resizeable); - } - - Buffer_result buffer(Framebuffer::Mode mode, bool has_alpha) override + Buffer_result buffer(Framebuffer::Mode mode) override { /* * We must not perform the 'buffer' operation on the connection @@ -1147,20 +1331,21 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, * wrapped GUI session. Otherwise, we would perform session * upgrades initiated by the wm client's buffer operation twice. */ - _has_alpha = has_alpha; + _has_alpha = mode.alpha; - Buffer_result const result = _real_gui.session.buffer(mode, has_alpha); + Buffer_result const result = _real_gui.session.buffer(mode); _window_registry.flush(); return result; } - void focus(Genode::Capability<Gui::Session>) override { } + void focus(Capability<Gui::Session>) override { } }; -class Wm::Gui::Root : public Genode::Rpc_object<Genode::Typed_root<Gui::Session> >, - public Decorator_content_callback +class Wm::Gui::Root : public Rpc_object<Typed_root<Gui::Session> >, + public Decorator_content_callback, + private Input::Session_component::Action { private: @@ -1170,27 +1355,27 @@ class Wm::Gui::Root : public Genode::Rpc_object<Genode::Typed_root<Gui::Session> Root(Root const &); Root &operator = (Root const &); - Genode::Env &_env; + Env &_env; - Genode::Attached_rom_dataspace _config { _env, "config" }; + Session_component::Action &_action; - Allocator &_md_alloc; + Attached_rom_dataspace _config { _env, "config" }; - Genode::Ram_allocator &_ram; + Sliced_heap _sliced_heap { _env.ram(), _env.rm() }; enum { STACK_SIZE = 1024*sizeof(long) }; Pointer::Tracker &_pointer_tracker; - Reporter &_focus_request_reporter; - - unsigned _focus_request_cnt = 0; - Window_registry &_window_registry; - Input::Session_component _window_layouter_input { _env, _env.ram() }; + Input::Session_component _window_layouter_input { + _env.ep(), _env.ram(), _env.rm(), *this }; - Input::Session_capability _window_layouter_input_cap { _env.ep().manage(_window_layouter_input) }; + /** + * Input::Session_component::Action interface + */ + void exclusive_input_requested(bool) override { } /* handler that forwards clicks into unfocused windows to the layouter */ struct Click_handler : Gui::Click_handler @@ -1232,16 +1417,13 @@ class Wm::Gui::Root : public Genode::Rpc_object<Genode::Typed_root<Gui::Session> /** * Constructor */ - Root(Genode::Env &env, - Window_registry &window_registry, Allocator &md_alloc, - Genode::Ram_allocator &ram, - Pointer::Tracker &pointer_tracker, Reporter &focus_request_reporter, - Gui::Connection &focus_gui_session) + Root(Env &env, Session_component::Action &action, + Window_registry &window_registry, + Pointer::Tracker &pointer_tracker, + Gui::Connection &focus_gui_session) : - _env(env), - _md_alloc(md_alloc), _ram(ram), + _env(env), _action(action), _pointer_tracker(pointer_tracker), - _focus_request_reporter(focus_request_reporter), _window_registry(window_registry), _focus_gui_session(focus_gui_session) { @@ -1273,11 +1455,16 @@ class Wm::Gui::Root : public Genode::Rpc_object<Genode::Typed_root<Gui::Session> ** Root interface ** ********************/ + static_assert(Gui::Session::CAP_QUOTA == 9); + Genode::Session_capability session(Session_args const &args, Affinity const &) override { - Genode::Session_label const session_label = - Genode::label_from_args(args.string()); + using Session = Genode::Session; + + Session::Label label = label_from_args(args.string()); + Session::Resources resources = session_resources_from_args(args.string()); + Session::Diag diag = session_diag_from_args(args.string()); enum Role { ROLE_DECORATOR, ROLE_LAYOUTER, ROLE_REGULAR, ROLE_DIRECT }; Role role = ROLE_REGULAR; @@ -1286,8 +1473,7 @@ class Wm::Gui::Root : public Genode::Rpc_object<Genode::Typed_root<Gui::Session> * Determine session policy */ try { - Genode::Xml_node policy = - Genode::Session_policy(session_label, _config.xml()); + Xml_node policy = Session_policy(label, _config.xml()); auto const value = policy.attribute_value("role", String<16>()); @@ -1297,44 +1483,76 @@ class Wm::Gui::Root : public Genode::Rpc_object<Genode::Typed_root<Gui::Session> } catch (...) { } + if (role == ROLE_REGULAR || role == ROLE_DECORATOR) { + + size_t const needed_ram = Real_gui::RAM_QUOTA + + sizeof(Session_component) + + _sliced_heap.overhead(sizeof(Session_component)) + + 8*1024; + + if (resources.ram_quota.value < needed_ram) + throw Insufficient_ram_quota(); + resources.ram_quota.value -= needed_ram; + + static constexpr unsigned needed_caps = + 1 + /* Sliced_heap alloc of Session_component */ + 1 + /* Session_component RPC cap */ + 9 + /* Wrapped nitpicker GUI session (_real_gui) */ + 1 + /* Input_session RPC cap (_input_session) */ + 1 + /* Input_session events dataspace (_input_session) */ + 1 + /* Command buffer (_command_buffer) */ + 1 + /* Input signal handler (_input_handler) */ + 1; /* Content-view capability */ + + if (resources.cap_quota.value < needed_caps) + throw Insufficient_cap_quota(); + /* preserve caps for content_view and command buffer ds */ + resources.cap_quota.value -= needed_caps - 2; + } + switch (role) { case ROLE_REGULAR: - { - auto session = new (_md_alloc) - Session_component(_env, _ram, _window_registry, - _md_alloc, session_label, + try { + Session_component &session = *new (_sliced_heap) + Session_component(_env, _action, resources, label, diag, + _window_registry, _pointer_tracker, _click_handler); - _sessions.insert(session); - return _env.ep().manage(*session); + _sessions.insert(&session); + return session.cap(); } + catch (Out_of_ram) { throw Insufficient_ram_quota(); } + catch (Out_of_caps) { throw Insufficient_cap_quota(); } case ROLE_DECORATOR: - { - auto session = new (_md_alloc) - Decorator_gui_session(_env, _ram, _md_alloc, + try { + Decorator_gui_session &session = *new (_sliced_heap) + Decorator_gui_session(_env, resources, label, diag, _pointer_tracker, _window_layouter_input, *this); - _decorator_sessions.insert(session); - return _env.ep().manage(*session); + _decorator_sessions.insert(&session); + return session.cap(); } + catch (Out_of_ram) { throw Insufficient_ram_quota(); } + catch (Out_of_caps) { throw Insufficient_cap_quota(); } case ROLE_LAYOUTER: { - _layouter_session = new (_md_alloc) - Layouter_gui_session(_env, _window_layouter_input_cap); + _layouter_session = new (_sliced_heap) + Layouter_gui_session(_env, resources, label, diag, + _window_layouter_input.cap()); - return _env.ep().manage(*_layouter_session); + return _layouter_session->cap(); } case ROLE_DIRECT: { - Direct_gui_session *session = new (_md_alloc) - Direct_gui_session(_env, session_label); + Direct_gui_session &session = *new (_sliced_heap) + Direct_gui_session(_env, resources, label, diag); - return _env.ep().manage(*session); + return session.cap(); } } @@ -1347,7 +1565,7 @@ class Wm::Gui::Root : public Genode::Rpc_object<Genode::Typed_root<Gui::Session> auto lambda = [&] (Rpc_object_base *session) { if (!session) { - Genode::warning("session lookup failed"); + warning("session lookup failed"); return; } @@ -1355,13 +1573,13 @@ class Wm::Gui::Root : public Genode::Rpc_object<Genode::Typed_root<Gui::Session> dynamic_cast<Session_component *>(session); if (regular_session) - regular_session->upgrade(args.string()); + regular_session->upgrade_local_or_remote(session_resources_from_args(args.string())); Decorator_gui_session *decorator_session = dynamic_cast<Decorator_gui_session *>(session); if (decorator_session) - decorator_session->upgrade(args.string()); + decorator_session->upgrade_local_or_remote(session_resources_from_args(args.string())); Direct_gui_session *direct_session = dynamic_cast<Direct_gui_session *>(session); @@ -1374,54 +1592,46 @@ class Wm::Gui::Root : public Genode::Rpc_object<Genode::Typed_root<Gui::Session> void close(Genode::Session_capability session_cap) override { - Genode::Rpc_entrypoint &ep = _env.ep().rpc_ep(); + Rpc_entrypoint &ep = _env.ep().rpc_ep(); Session_component *regular_session = ep.apply(session_cap, [this] (Session_component *session) { - if (session) { + if (session) _sessions.remove(session); - _env.ep().dissolve(*session); - } return session; }); if (regular_session) { - Genode::destroy(_md_alloc, regular_session); + destroy(_sliced_heap, regular_session); return; } Direct_gui_session *direct_session = ep.apply(session_cap, [this] (Direct_gui_session *session) { - if (session) { - _env.ep().dissolve(*session); - } return session; }); if (direct_session) { - Genode::destroy(_md_alloc, direct_session); + destroy(_sliced_heap, direct_session); return; } Decorator_gui_session *decorator_session = ep.apply(session_cap, [this] (Decorator_gui_session *session) { - if (session) { + if (session) _decorator_sessions.remove(session); - _env.ep().dissolve(*session); - } return session; }); if (decorator_session) { - Genode::destroy(_md_alloc, decorator_session); + destroy(_sliced_heap, decorator_session); return; } auto layouter_lambda = [this] (Layouter_gui_session *session) { - this->_env.ep().dissolve(*_layouter_session); _layouter_session = nullptr; return session; }; if (ep.apply(session_cap, layouter_lambda) == _layouter_session) { - Genode::destroy(_md_alloc, _layouter_session); + destroy(_sliced_heap, _layouter_session); return; } } @@ -1444,8 +1654,8 @@ class Wm::Gui::Root : public Genode::Rpc_object<Genode::Typed_root<Gui::Session> * calling 's->content_view'. */ for (Session_component *s = _sessions.first(); s; s = s->next()) - if (s->has_win_id(id.value)) - return s->content_view(id.value); + if (s->has_win_id(id)) + return s->content_view(id); return View_capability(); } @@ -1486,21 +1696,33 @@ class Wm::Gui::Root : public Genode::Rpc_object<Genode::Typed_root<Gui::Session> s->content_geometry(id, rect); } - Capability<Gui::Session> lookup_gui_session(unsigned win_id) + void with_gui_session(Window_registry::Id id, auto const &fn) { for (Session_component *s = _sessions.first(); s; s = s->next()) - if (s->has_win_id(win_id)) - return s->session(); - - return { }; + if (s->has_win_id(id)) { + fn(s->session()); + return; + } } - void request_resize(unsigned win_id, Area size) + void request_resize(Window_registry::Id win_id, Area size) { for (Session_component *s = _sessions.first(); s; s = s->next()) if (s->has_win_id(win_id)) return s->request_resize(size); } + + void propagate_mode_change() + { + for (Session_component *s = _sessions.first(); s; s = s->next()) + s->propagate_mode_change(); + } + + void revoke_exclusive_input() + { + for (Session_component *s = _sessions.first(); s; s = s->next()) + s->revoke_exclusive_input(); + } }; #endif /* _GUI_H_ */ diff --git a/repos/gems/src/server/wm/layouter_gui.h b/repos/gems/src/server/wm/layouter_gui.h index 4878a56a23..4bfc231c25 100644 --- a/repos/gems/src/server/wm/layouter_gui.h +++ b/repos/gems/src/server/wm/layouter_gui.h @@ -24,11 +24,8 @@ namespace Wm { } -struct Wm::Layouter_gui_session : Genode::Rpc_object<Gui::Session> +struct Wm::Layouter_gui_session : Session_object<Gui::Session> { - using View_capability = Gui::View_capability; - using View_id = Gui::View_id; - Input::Session_capability _input_session_cap; /* @@ -36,13 +33,15 @@ struct Wm::Layouter_gui_session : Genode::Rpc_object<Gui::Session> */ Gui::Connection _mode_sigh_gui; - Genode::Signal_context_capability _mode_sigh { }; - Attached_ram_dataspace _command_ds; - Layouter_gui_session(Genode::Env &env, + Layouter_gui_session(Env &env, + Resources const &resources, + Label const &label, + Diag const &diag, Input::Session_capability input_session_cap) : + Session_object<Gui::Session>(env.ep(), resources, label, diag), _input_session_cap(input_session_cap), _mode_sigh_gui(env), _command_ds(env.ram(), env.rm(), 4096) { } @@ -62,53 +61,45 @@ struct Wm::Layouter_gui_session : Genode::Rpc_object<Gui::Session> return _input_session_cap; } - View_result view(View_id, View_attr const &) override + Info_result info() override + { + return _mode_sigh_gui.info_rom_cap(); + } + + View_result view(Gui::View_id, View_attr const &) override { return View_result::OK; } - Child_view_result child_view(View_id, View_id, View_attr const &) override + Child_view_result child_view(Gui::View_id, Gui::View_id, View_attr const &) override { return Child_view_result::OK; } - void destroy_view(View_id) override { } + void destroy_view(Gui::View_id) override { } - Associate_result associate(View_id, View_capability) override + Associate_result associate(Gui::View_id, Gui::View_capability) override { return Associate_result::OK; } - View_capability_result view_capability(View_id) override + View_capability_result view_capability(Gui::View_id) override { - return View_capability(); + return Gui::View_capability(); } - void release_view_id(View_id) override { } + void release_view_id(Gui::View_id) override { } - Genode::Dataspace_capability command_dataspace() override + Dataspace_capability command_dataspace() override { return _command_ds.cap(); } void execute() override { } - Framebuffer::Mode mode() override { return _mode_sigh_gui.mode(); } + Buffer_result buffer(Framebuffer::Mode) override { return Buffer_result::OK; } - void mode_sigh(Genode::Signal_context_capability sigh) override - { - /* - * Remember signal-context capability to keep NOVA from revoking - * transitive delegations of the capability. - */ - _mode_sigh = sigh; - - _mode_sigh_gui.mode_sigh(sigh); - } - - Buffer_result buffer(Framebuffer::Mode, bool) override { return Buffer_result::OK; } - - void focus(Genode::Capability<Gui::Session>) override { } + void focus(Capability<Gui::Session>) override { } }; #endif /* _LAYOUTER_GUI_H_ */ diff --git a/repos/gems/src/server/wm/main.cc b/repos/gems/src/server/wm/main.cc index 82d0fdbd49..88f9bc62fc 100644 --- a/repos/gems/src/server/wm/main.cc +++ b/repos/gems/src/server/wm/main.cc @@ -15,109 +15,105 @@ #include <gui_session/client.h> #include <framebuffer_session/client.h> #include <base/component.h> -#include <base/attached_rom_dataspace.h> -#include <base/heap.h> -#include <util/reconstructible.h> -#include <util/xml_node.h> /* local includes */ #include <gui.h> #include <report_forwarder.h> #include <rom_forwarder.h> -namespace Wm { - - class Main; - - using Genode::size_t; - using Genode::Rom_session_client; - using Genode::Rom_connection; - using Genode::Xml_node; - using Genode::Attached_rom_dataspace; -} +namespace Wm { class Main; } -struct Wm::Main : Pointer::Tracker +struct Wm::Main : Pointer::Tracker, Gui::Session_component::Action { - Genode::Env &env; + Env &_env; - Genode::Heap heap { env.ram(), env.rm() }; + Heap _heap { _env.ram(), _env.rm() }; /* currently focused window, reported by the layouter */ - Attached_rom_dataspace focus_rom { env, "focus" }; + Attached_rom_dataspace _focus_rom { _env, "focus" }; /* resize requests, issued by the layouter */ - Attached_rom_dataspace resize_request_rom { env, "resize_request" }; + Attached_rom_dataspace _resize_request_rom { _env, "resize_request" }; /* pointer position to be consumed by the layouter */ - Reporter pointer_reporter = { env, "pointer" }; + Expanding_reporter _pointer_reporter { _env, "pointer", "pointer" }; /* list of present windows, to be consumed by the layouter */ - Reporter window_list_reporter = { env, "window_list" }; + Expanding_reporter _window_list_reporter { _env, "window_list", "window_list" }; - /* request to the layouter to set the focus */ - Reporter focus_request_reporter = { env, "focus_request" }; + Window_registry _window_registry { _heap, _window_list_reporter }; - Window_registry window_registry { heap, window_list_reporter }; + Gui::Connection _focus_gui_session { _env }; - Gui::Connection focus_gui_session { env }; + Gui::Area _screen_area { }; - Gui::Root gui_root { env, window_registry, heap, env.ram(), - *this, focus_request_reporter, - focus_gui_session }; + Signal_handler<Main> _mode_handler { + _env.ep(), *this, &Main::_handle_mode }; - void handle_focus_update() + void _handle_mode() { - focus_rom.update(); - - focus_rom.xml().with_optional_sub_node("window", [&] (Xml_node const &window) { - - unsigned const win_id = window.attribute_value("id", 0u); - - if (win_id) { - try { - Gui::Session_capability session_cap = - gui_root.lookup_gui_session(win_id); - - focus_gui_session.focus(session_cap); - } catch (...) { } - } - }); + _focus_gui_session.with_info([&] (Xml_node const &info) { + _screen_area = Area::from_xml(info); }); + _gui_root.propagate_mode_change(); } - Genode::Signal_handler<Main> focus_handler = { - env.ep(), *this, &Main::handle_focus_update }; - - void handle_resize_request_update() + /** + * Gui::Session_component::Action interface + */ + void gen_screen_area_info(Xml_generator &xml) const override { - resize_request_rom.update(); - - resize_request_rom.xml().for_each_sub_node("window", [&] (Xml_node window) { - - unsigned const - win_id = window.attribute_value("id", 0U), - width = window.attribute_value("width", 0U), - height = window.attribute_value("height", 0U); - - gui_root.request_resize(win_id, Area(width, height)); - }); + xml.attribute("width", _screen_area.w); + xml.attribute("height", _screen_area.h); } - Genode::Signal_handler<Main> resize_request_handler = - { env.ep(), *this, &Main::handle_resize_request_update }; + Gui::Root _gui_root { _env, *this, _window_registry, *this, _focus_gui_session }; - Report_forwarder _report_forwarder { env, heap }; - Rom_forwarder _rom_forwarder { env, heap }; + static void _with_win_id_from_xml(Xml_node const &window, auto const &fn) + { + if (window.has_attribute("id")) + fn(Window_registry::Id { window.attribute_value("id", 0u) }); + } - Genode::Signal_handler<Main> _update_pointer_report_handler = - { env.ep(), *this, &Main::_handle_update_pointer_report }; + void _handle_focus_update() + { + _gui_root.revoke_exclusive_input(); + _focus_rom.update(); + bool defined = false; + _focus_rom.xml().with_optional_sub_node("window", [&] (Xml_node const &window) { + _with_win_id_from_xml(window, [&] (Window_registry::Id id) { + _gui_root.with_gui_session(id, [&] (Capability<Gui::Session> cap) { + _focus_gui_session.focus(cap); + defined = true; }); }); }); + if (!defined) + _focus_gui_session.focus({ }); + } + + Signal_handler<Main> _focus_handler { + _env.ep(), *this, &Main::_handle_focus_update }; + + void _handle_resize_request_update() + { + _resize_request_rom.update(); + _resize_request_rom.xml().for_each_sub_node("window", [&] (Xml_node const &window) { + _with_win_id_from_xml(window, [&] (Window_registry::Id id) { + _gui_root.request_resize(id, Area::from_xml(window)); }); }); + } + + Signal_handler<Main> _resize_request_handler { + _env.ep(), *this, &Main::_handle_resize_request_update }; + + Report_forwarder _report_forwarder { _env, _heap }; + Rom_forwarder _rom_forwarder { _env, _heap }; + + Signal_handler<Main> _update_pointer_report_handler { + _env.ep(), *this, &Main::_handle_update_pointer_report }; void _handle_update_pointer_report() { - Pointer::Position pos = gui_root.last_observed_pointer_pos(); + Pointer::Position const pos = _gui_root.last_observed_pointer_pos(); - Reporter::Xml_generator xml(pointer_reporter, [&] () - { + _pointer_reporter.generate([&] (Xml_generator &xml) { if (pos.valid) { xml.attribute("xpos", pos.value.x); xml.attribute("ypos", pos.value.y); @@ -140,28 +136,17 @@ struct Wm::Main : Pointer::Tracker _update_pointer_report_handler.local_submit(); } - Main(Genode::Env &env) : env(env) + Main(Env &env) : _env(env) { - pointer_reporter.enabled(true); - /* initially report an empty window list */ - window_list_reporter.enabled(true); - Genode::Reporter::Xml_generator xml(window_list_reporter, [&] () { }); + _window_list_reporter.generate([&] (Xml_generator &) { }); - focus_request_reporter.enabled(true); - - focus_rom.sigh(focus_handler); - resize_request_rom.sigh(resize_request_handler); + _focus_rom.sigh(_focus_handler); + _resize_request_rom.sigh(_resize_request_handler); + _focus_gui_session.info_sigh(_mode_handler); + _handle_mode(); } }; -/*************** - ** Component ** - ***************/ - -Genode::size_t Component::stack_size() { - return 16*1024*sizeof(long); } - -void Component::construct(Genode::Env &env) { - static Wm::Main desktop(env); } +void Component::construct(Genode::Env &env) { static Wm::Main desktop(env); } diff --git a/repos/gems/src/server/wm/pointer.h b/repos/gems/src/server/wm/pointer.h index fbff2b7b12..25a5c9efbc 100644 --- a/repos/gems/src/server/wm/pointer.h +++ b/repos/gems/src/server/wm/pointer.h @@ -14,7 +14,8 @@ #ifndef _POINTER_H_ #define _POINTER_H_ -#include <util/noncopyable.h> +/* local includes */ +#include <types.h> namespace Wm { struct Pointer; } @@ -28,13 +29,13 @@ struct Wm::Pointer }; - struct Tracker : Genode::Interface, Genode::Noncopyable + struct Tracker : Interface, Noncopyable { virtual void update_pointer_report() = 0; }; - class State : Genode::Noncopyable + class State : Noncopyable { private: diff --git a/repos/gems/src/server/wm/real_gui.h b/repos/gems/src/server/wm/real_gui.h index f41af24b0e..ec9643af50 100644 --- a/repos/gems/src/server/wm/real_gui.h +++ b/repos/gems/src/server/wm/real_gui.h @@ -17,7 +17,6 @@ /* Genode includes */ #include <base/connection.h> #include <base/attached_dataspace.h> -#include <gui_session/client.h> namespace Wm { struct Real_gui; } @@ -26,29 +25,31 @@ struct Wm::Real_gui { private: - Genode::Env &_env; + Env &_env; public: - Genode::Session_label const &label; + Session_label const &label; using Command_buffer = Gui::Session::Command_buffer; + static constexpr size_t RAM_QUOTA = 36*1024; + public: - Real_gui(Genode::Env &env, Genode::Session_label const &label) + Real_gui(Env &env, Session_label const &label) : _env(env), label(label) { } - Genode::Connection<Gui::Session> connection { - _env, label, Genode::Ram_quota { 36*1024 }, /* Args */ { } }; + Connection<Gui::Session> connection { + _env, label, Genode::Ram_quota { RAM_QUOTA }, /* Args */ { } }; Gui::Session_client session { connection.cap() }; private: - Genode::Attached_dataspace _command_ds { _env.rm(), session.command_dataspace() }; + Attached_dataspace _command_ds { _env.rm(), session.command_dataspace() }; Command_buffer &_command_buffer { *_command_ds.local_addr<Command_buffer>() }; diff --git a/repos/gems/src/server/wm/report_forwarder.h b/repos/gems/src/server/wm/report_forwarder.h index ddf90d1471..796b731653 100644 --- a/repos/gems/src/server/wm/report_forwarder.h +++ b/repos/gems/src/server/wm/report_forwarder.h @@ -32,19 +32,17 @@ namespace Wm { struct Report_forwarder; } struct Wm::Report_forwarder { - struct Session : Genode::Rpc_object<Report::Session> + struct Session : Session_object<Report::Session> { - Genode::Env &_env; Report::Connection _connection; - Session(Genode::Env &env, Genode::Session_label const &label, - size_t buffer_size) - : _env(env), _connection(env, label.string(), buffer_size) - { _env.ep().manage(*this); } + Session(Env &env, size_t buffer_size, auto &&... args) + : + Session_object<Report::Session>(env.ep(), args...), + _connection(env, label(), buffer_size) + { } - ~Session() { _env.ep().dissolve(*this); } - - void upgrade(Genode::Session::Resources const &resources) + void upgrade(Session::Resources const &resources) { _connection.upgrade(resources); } @@ -54,47 +52,49 @@ struct Wm::Report_forwarder ** Report::Session interface ** *******************************/ - Genode::Dataspace_capability dataspace() override + Dataspace_capability dataspace() override { return _connection.dataspace(); } - void submit(Genode::size_t length) override + void submit(size_t length) override { _connection.submit(length); } - void response_sigh(Genode::Signal_context_capability sigh) override + void response_sigh(Signal_context_capability sigh) override { _connection.response_sigh(sigh); } - Genode::size_t obtain_response() override + size_t obtain_response() override { return _connection.obtain_response(); } }; - struct Root : Genode::Root_component<Session> + struct Root : Root_component<Session> { - Genode::Env &_env; - Genode::Allocator &_alloc; + Env &_env; + Allocator &_alloc; Session *_create_session(char const *args) override { return new (md_alloc()) - Session(_env, Genode::label_from_args(args), - Arg_string::find_arg(args, "buffer_size").ulong_value(0)); + Session(_env, Arg_string::find_arg(args, "buffer_size").ulong_value(0), + session_resources_from_args(args), + session_label_from_args(args), + session_diag_from_args(args)); } void _upgrade_session(Session *session, const char *args) override { - session->upgrade(Genode::session_resources_from_args(args)); + session->upgrade(session_resources_from_args(args)); } - Root(Genode::Env &env, Genode::Allocator &alloc) + Root(Env &env, Allocator &alloc) : - Genode::Root_component<Session>(env.ep(), alloc), + Root_component<Session>(env.ep(), alloc), _env(env), _alloc(alloc) { _env.parent().announce(env.ep().manage(*this)); @@ -102,8 +102,7 @@ struct Wm::Report_forwarder } _root; - Report_forwarder(Genode::Env &env, Genode::Allocator &alloc) - : _root(env, alloc) { } + Report_forwarder(Env &env, Allocator &alloc) : _root(env, alloc) { } }; #endif /* _REPORT_FORWARDER_H_ */ diff --git a/repos/gems/src/server/wm/rom_forwarder.h b/repos/gems/src/server/wm/rom_forwarder.h index b73c7d8513..783dd3698f 100644 --- a/repos/gems/src/server/wm/rom_forwarder.h +++ b/repos/gems/src/server/wm/rom_forwarder.h @@ -27,18 +27,17 @@ namespace Wm { struct Rom_forwarder; } struct Wm::Rom_forwarder { - struct Session : Genode::Rpc_object<Genode::Rom_session> + struct Session : Session_object<Rom_session> { - Genode::Env &_env; - Genode::Rom_connection _connection; + Rom_connection _connection; - Session(Genode::Env &env, Genode::Session_label const &label) - : _env(env), _connection(env, label.string()) - { _env.ep().manage(*this); } + Session(Env &env, auto &&... args) + : + Session_object<Rom_session>(env.ep(), args...), + _connection(env, label()) + { } - ~Session() { _env.ep().dissolve(*this); } - - void upgrade(Genode::Session::Resources const &resources) + void upgrade(Session::Resources const &resources) { _connection.upgrade(resources); } @@ -48,7 +47,7 @@ struct Wm::Rom_forwarder ** Rom_session interface ** ***************************/ - Genode::Rom_dataspace_capability dataspace() override + Rom_dataspace_capability dataspace() override { return _connection.dataspace(); } @@ -64,24 +63,26 @@ struct Wm::Rom_forwarder } }; - struct Root : Genode::Root_component<Session> + struct Root : Root_component<Session> { - Genode::Env &_env; - Genode::Allocator &_alloc; + Env &_env; + Allocator &_alloc; Session *_create_session(char const *args) override { - return new (md_alloc()) Session(_env, Genode::label_from_args(args)); + return new (md_alloc()) Session(_env, session_resources_from_args(args), + session_label_from_args(args), + session_diag_from_args(args)); } void _upgrade_session(Session *session, const char *args) override { - session->upgrade(Genode::session_resources_from_args(args)); + session->upgrade(session_resources_from_args(args)); } - Root(Genode::Env &env, Genode::Allocator &alloc) + Root(Env &env, Allocator &alloc) : - Genode::Root_component<Session>(env.ep(), alloc), + Root_component<Session>(env.ep(), alloc), _env(env), _alloc(alloc) { _env.parent().announce(env.ep().manage(*this)); @@ -89,8 +90,7 @@ struct Wm::Rom_forwarder } _root; - Rom_forwarder(Genode::Env &env, Genode::Allocator &alloc) - : _root(env, alloc) { } + Rom_forwarder(Env &env, Allocator &alloc) : _root(env, alloc) { } }; #endif /* _ROM_FORWARDER_H_ */ diff --git a/repos/gems/src/server/wm/types.h b/repos/gems/src/server/wm/types.h new file mode 100644 index 0000000000..4274a972d1 --- /dev/null +++ b/repos/gems/src/server/wm/types.h @@ -0,0 +1,78 @@ +/* + * \brief Common types used within the window manager + * \author Norman Feske + * \date 2024-09-04 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _TYPES_H_ +#define _TYPES_H_ + +/* Genode includes */ +#include <util/reconstructible.h> +#include <util/list.h> +#include <base/tslab.h> +#include <base/attached_rom_dataspace.h> +#include <base/attached_ram_dataspace.h> +#include <base/heap.h> +#include <base/session_object.h> +#include <os/surface.h> +#include <os/reporter.h> +#include <os/session_policy.h> +#include <gui_session/gui_session.h> + +namespace Wm { + + using namespace Genode; + + using Area = Surface_base::Area; + using Point = Surface_base::Point; + using Rect = Surface_base::Rect; + + /* + * Slab allocator that includes an initial block as member + */ + template <size_t BLOCK_SIZE> + struct Initial_slab_block { uint8_t buf[BLOCK_SIZE]; }; + template <typename T, size_t BLOCK_SIZE> + struct Slab : private Initial_slab_block<BLOCK_SIZE>, Tslab<T, BLOCK_SIZE> + { + Slab(Allocator &block_alloc) + : Tslab<T, BLOCK_SIZE>(block_alloc, Initial_slab_block<BLOCK_SIZE>::buf) { }; + }; + + struct Upgradeable : Noncopyable + { + bool _starved_for_ram = false, _starved_for_caps = false; + + void _upgrade_local_or_remote(auto const &resources, auto &session_obj, auto &real_gui) + { + Ram_quota ram = resources.ram_quota; + Cap_quota caps = resources.cap_quota; + + if (_starved_for_caps && caps.value) { + session_obj.upgrade(caps); + _starved_for_caps = false; + caps = { }; + } + + if (_starved_for_ram && ram.value) { + session_obj.upgrade(ram); + _starved_for_ram = false; + ram = { }; + } + + if (ram.value || caps.value) { + real_gui.connection.upgrade({ ram, caps }); + } + } + }; +} + +#endif /* _TYPES_H_ */ diff --git a/repos/gems/src/server/wm/window_registry.h b/repos/gems/src/server/wm/window_registry.h index 3f62bd27c0..2b734d29be 100644 --- a/repos/gems/src/server/wm/window_registry.h +++ b/repos/gems/src/server/wm/window_registry.h @@ -16,102 +16,89 @@ /* Genode includes */ #include <util/bit_allocator.h> -#include <util/list.h> -#include <base/allocator.h> -#include <os/surface.h> -#include <os/reporter.h> -#include <os/session_policy.h> +#include <base/id_space.h> /* gems includes */ #include <gems/local_reporter.h> +/* local includes */ +#include <types.h> + namespace Wm { class Window_registry; } -namespace Wm { - using Genode::Allocator; - using Genode::List; - using Genode::Xml_generator; - using Genode::Reporter; - - using Area = Genode::Surface_base::Area; - using Point = Genode::Surface_base::Point; - using Rect = Genode::Surface_base::Rect; -} - - class Wm::Window_registry { public: - struct Id - { - unsigned value; + class Window; - Id(unsigned value) : value(value) { } + using Windows = Id_space<Window>; + using Id = Windows::Id; - Id() /* invalid */ : value(0) { } + struct Alpha { bool value; }; + struct Hidden { bool value; }; + struct Resizeable { bool value; }; - bool operator == (Id const &other) const { return value == other.value; } - - bool valid() const { return value != 0; } - }; - - class Window : public List<Window>::Element + class Window : Noncopyable { public: - using Title = Gui::Title; - using Session_label = Genode::Session_label; - - enum Has_alpha { HAS_ALPHA, HAS_NO_ALPHA }; - - enum Hidden { HIDDEN, NOT_HIDDEN }; - - enum Resizeable { RESIZEABLE, NOT_RESIZEABLE }; - - private: - - Id const _id; - struct Attr { - Title title { }; - Session_label label { }; - Area size { }; - Has_alpha has_alpha = HAS_NO_ALPHA; - Hidden hidden = NOT_HIDDEN; - Resizeable resizeable = NOT_RESIZEABLE; + Gui::Title title; + Session_label label; + Area area; + Alpha alpha; + Hidden hidden; + Resizeable resizeable; bool operator == (Attr const &other) const { - return title == other.title - && label == other.label - && size == other.size - && has_alpha == other.has_alpha - && hidden == other.hidden - && resizeable == other.resizeable; + return title == other.title + && label == other.label + && area == other.area + && alpha.value == other.alpha.value + && hidden.value == other.hidden.value + && resizeable.value == other.resizeable.value; + } + + void gen_window_attr(Xml_generator &xml) const + { + xml.attribute("label", label); + xml.attribute("title", title); + xml.attribute("width", area.w); + xml.attribute("height", area.h); + + if (alpha.value) xml.attribute("has_alpha", "yes"); + if (hidden.value) xml.attribute("hidden", "yes"); + if (resizeable.value) xml.attribute("resizeable", "yes"); } }; - Attr _attr { }; + private: + + Windows::Element _id; + + Attr _attr; Attr mutable _flushed_attr { }; friend class Window_registry; - Window(Id id) : _id(id) { } + Window(Windows &windows, Id id, Attr const &attr) + : _id(*this, windows, id), _attr(attr) { } public: - Id id() const { return _id; } + Id id() const { return _id.id(); } /* * Accessors for setting attributes */ - void attr(Title const &title) { _attr.title = title; } + void attr(Gui::Title const &title) { _attr.title = title; } void attr(Session_label const &label) { _attr.label = label; } - void attr(Area size) { _attr.size = size; } - void attr(Has_alpha has_alpha) { _attr.has_alpha = has_alpha; } + void attr(Area area) { _attr.area = area; } + void attr(Alpha alpha) { _attr.alpha = alpha; } void attr(Hidden hidden) { _attr.hidden = hidden; } void attr(Resizeable resizeable) { _attr.resizeable = resizeable; } @@ -120,28 +107,17 @@ class Wm::Window_registry void generate_window_list_entry_xml(Xml_generator &xml) const { /* - * Skip windows that have no defined size, which happens - * between the creation of a new window and the first - * time when the window's properties are assigned. + * Skip windows that have no defined size, which may happen + * between the creation of a new window for a view w/o size + * and the first time when the top-level view's size is + * assigned. */ - if (!_attr.size.valid()) + if (!_attr.area.valid()) return; xml.node("window", [&] () { - xml.attribute("id", _id.value); - xml.attribute("label", _attr.label.string()); - xml.attribute("title", _attr.title.string()); - xml.attribute("width", _attr.size.w); - xml.attribute("height", _attr.size.h); - - if (_attr.has_alpha == HAS_ALPHA) - xml.attribute("has_alpha", "yes"); - - if (_attr.hidden == HIDDEN) - xml.attribute("hidden", "yes"); - - if (_attr.resizeable == RESIZEABLE) - xml.attribute("resizeable", "yes"); + xml.attribute("id", id().value); + _attr.gen_window_attr(xml); }); } @@ -151,61 +127,49 @@ class Wm::Window_registry bool _flushed() const { bool result = true; - for (Window const *w = _windows.first(); w; w = w->next()) - result &= w->flushed(); - + _windows.for_each<Window const>([&] (Window const &w) { + result &= w.flushed(); }); return result; } private: - Allocator &_alloc; - Reporter &_window_list_reporter; + Allocator &_alloc; + Expanding_reporter &_window_list_reporter; static constexpr unsigned MAX_WINDOWS = 1024; - Genode::Bit_allocator<MAX_WINDOWS> _window_ids { }; + Bit_allocator<MAX_WINDOWS> _window_ids { }; unsigned _next_id = 0; /* used to alloc subsequent numbers */ - List<Window> _windows { }; + Windows _windows { }; - Window *_lookup(Id id) + void _with_window(Id id, auto const &fn, auto const &missing_fn) { - for (Window *w = _windows.first(); w; w = w->next()) - if (w->id() == id) - return w; - - return 0; + _windows.apply<Window>(id, fn, missing_fn); } void _report_updated_window_list_model() const { - Reporter::Xml_generator xml(_window_list_reporter, [&] () - { - for (Window const *w = _windows.first(); w; w = w->next()) { - w->generate_window_list_entry_xml(xml); - w->mark_as_flushed(); - } + _window_list_reporter.generate([&] (Xml_generator &xml) { + _windows.for_each<Window>([&] (Window const &w) { + w.generate_window_list_entry_xml(xml); + w.mark_as_flushed(); + }); }); } - template <typename ATTR> - void _set_attr(Id const id, ATTR const &value) + void _set_attr(Id const id, auto const &value) { - Window * const win = _lookup(id); - - if (!win) { - Genode::warning("lookup for window ID ", id.value, " failed"); - return; - } - - win->attr(value); + _with_window(id, + [&] (Window &window) { window.attr(value); }, + [&] { warning("lookup for window ID ", id.value, " failed"); }); } public: - Window_registry(Allocator &alloc, Reporter &window_list_reporter) + Window_registry(Allocator &alloc, Expanding_reporter &window_list_reporter) : _alloc(alloc), _window_list_reporter(window_list_reporter) { @@ -213,72 +177,60 @@ class Wm::Window_registry _window_ids.alloc(); } - Id create() + enum class Create_error { IDS_EXHAUSTED }; + using Create_result = Attempt<Id, Create_error>; + + Create_result create(Window::Attr const &attr) { - auto alloc_id = [&] + auto alloc_id = [&] () -> Create_result { - for (;;) { + for (unsigned i = 0; i < MAX_WINDOWS; i++) { unsigned try_id = _next_id; _next_id = (_next_id + 1) % MAX_WINDOWS; try { _window_ids.alloc_addr(try_id); - return try_id; + return Id { try_id }; } catch (...) { } } + return Create_error::IDS_EXHAUSTED; }; - Window * const win = new (_alloc) Window(alloc_id()); + Create_result const result = alloc_id(); - _windows.insert(win); + result.with_result( + [&] (Id id) { + new (_alloc) Window(_windows, id, attr); + _report_updated_window_list_model(); + }, + [&] (Create_error) { } + ); - /* - * Even though we change the window-list model by adding a - * window, we don't call '_report_updated_window_list_model' here - * because the window does not have any useful properties before - * the 'size' function has been called. - * - * XXX should we pass the initial size as argument to this function? - */ - - return win->id(); + return result; } void destroy(Id id) { - Window * const win = _lookup(id); - if (!win) + Window *win_ptr = nullptr; + _with_window(id, [&] (Window &window) { win_ptr = &window; }, [&] { }); + + if (!win_ptr) return; - _windows.remove(win); + _window_ids.free(win_ptr->id().value); - _window_ids.free(win->id().value); - - Genode::destroy(&_alloc, win); + Genode::destroy(&_alloc, win_ptr); _report_updated_window_list_model(); } - void size(Id id, Area size) { _set_attr(id, size); } + void area (Id id, Area const area) { _set_attr(id, area); } + void title(Id id, Gui::Title const &title) { _set_attr(id, title); } + void label(Id id, Session_label const &label) { _set_attr(id, label); } - void title(Id id, Window::Title const &title) { _set_attr(id, title); } - - void label(Id id, Window::Session_label const &label) { _set_attr(id, label); } - - void has_alpha(Id id, bool has_alpha) - { - _set_attr(id, has_alpha ? Window::HAS_ALPHA : Window::HAS_NO_ALPHA); - } - - void hidden(Id id, bool hidden) - { - _set_attr(id, hidden ? Window::HIDDEN : Window::NOT_HIDDEN); - } - - void resizeable(Id id, bool resizeable) - { - _set_attr(id, resizeable ? Window::RESIZEABLE : Window::NOT_RESIZEABLE); - } + void alpha (Id id, bool value) { _set_attr(id, Alpha { value }); } + void hidden (Id id, bool value) { _set_attr(id, Hidden { value }); } + void resizeable(Id id, bool value) { _set_attr(id, Resizeable { value }); } void flush() { diff --git a/repos/gems/src/test/dialog/target.mk b/repos/gems/src/test/dialog/target.mk index 665880b032..a47b7f11bc 100644 --- a/repos/gems/src/test/dialog/target.mk +++ b/repos/gems/src/test/dialog/target.mk @@ -1,3 +1,3 @@ TARGET = test-dialog SRC_CC = main.cc -LIBS += base dialog +LIBS += base dialog sandbox diff --git a/repos/gems/src/test/text_painter/main.cc b/repos/gems/src/test/text_painter/main.cc index 6ad5a28685..fd0455ef5c 100644 --- a/repos/gems/src/test/text_painter/main.cc +++ b/repos/gems/src/test/text_painter/main.cc @@ -80,7 +80,7 @@ struct Test::Main Vfs_font _font_4 { _heap, _root, "fonts/regular" }; - void _refresh() { _fb.refresh(0, 0, _size.w, _size.h); } + void _refresh() { _fb.refresh({ { 0, 0 }, _size }); } Main(Env &env) : _env(env) { diff --git a/repos/gems/src/test/tiled_wm/app/app.pro b/repos/gems/src/test/tiled_wm/app/app.pro index 0953a7bf26..c3c3b64c40 100644 --- a/repos/gems/src/test/tiled_wm/app/app.pro +++ b/repos/gems/src/test/tiled_wm/app/app.pro @@ -5,3 +5,5 @@ CONFIG += c++2a SOURCES += main.cpp app.cpp HEADERS += app.h ../util.h RESOURCES = app.qrc + +INCLUDEPATH = .. diff --git a/repos/gems/src/test/tiled_wm/overlay/overlay.pro b/repos/gems/src/test/tiled_wm/overlay/overlay.pro index 5f06b5e8ea..a743fe6927 100644 --- a/repos/gems/src/test/tiled_wm/overlay/overlay.pro +++ b/repos/gems/src/test/tiled_wm/overlay/overlay.pro @@ -5,3 +5,5 @@ CONFIG += c++2a SOURCES += main.cpp overlay.cpp HEADERS += overlay.h ../util.h RESOURCES = overlay.qrc + +INCLUDEPATH = .. diff --git a/repos/gems/src/test/tiled_wm/panel/panel.pro b/repos/gems/src/test/tiled_wm/panel/panel.pro index 40b1fe3d5a..a803db8416 100644 --- a/repos/gems/src/test/tiled_wm/panel/panel.pro +++ b/repos/gems/src/test/tiled_wm/panel/panel.pro @@ -5,3 +5,5 @@ CONFIG += c++2a SOURCES += main.cpp panel.cpp HEADERS += panel.h icon.h ../util.h RESOURCES = panel.qrc + +INCLUDEPATH = .. diff --git a/repos/gems/src/test/tiled_wm/target.inc b/repos/gems/src/test/tiled_wm/target.inc index 258fdcad73..de6ed49956 100644 --- a/repos/gems/src/test/tiled_wm/target.inc +++ b/repos/gems/src/test/tiled_wm/target.inc @@ -8,8 +8,6 @@ QT5_GENODE_LIBS_APP += ld.lib.so qmake_prepared.tag: $(addprefix build_dependencies/lib/,$(QT5_GENODE_LIBS_APP)) -INC_DIR += $(PRG_DIR)/.. - # # We need Qt headers in a local directory for MOC to work correctly # diff --git a/repos/libports/lib/import/import-libc.mk b/repos/libports/lib/import/import-libc.mk index 98113f5745..ef14d7e6e8 100644 --- a/repos/libports/lib/import/import-libc.mk +++ b/repos/libports/lib/import/import-libc.mk @@ -51,6 +51,11 @@ endif # REP_INC_DIR += include/libc-genode +# +# Enable definition of __STDC_HOSTED__ +# +CC_OPT_FREESTANDING = + # # Prevent gcc headers from defining __size_t. This definition is done in # machine/_types.h. diff --git a/repos/libports/lib/import/import-qt5_cmake.mk b/repos/libports/lib/import/import-qt5_cmake.mk index 18984a9e8a..66e279b01f 100644 --- a/repos/libports/lib/import/import-qt5_cmake.mk +++ b/repos/libports/lib/import/import-qt5_cmake.mk @@ -23,7 +23,7 @@ GENODE_CMAKE_CFLAGS += \ $(CC_OPT_NOSTDINC) \ $(CC_MARCH) \ $(CC_OPT_PIC) \ - $(filter-out -I.,$(INCLUDES)) \ + $(filter-out -I. $(foreach i,$(INCLUDES),$(if $(findstring /base-$(KERNEL)/include,$(i)),$(i))),$(INCLUDES)) \ -I$(CURDIR)/build_dependencies/include/QtCore/spec/$(QT_PLATFORM) GENODE_CMAKE_LFLAGS_APP += \ diff --git a/repos/libports/lib/import/import-qt5_qmake.mk b/repos/libports/lib/import/import-qt5_qmake.mk index fb1d6c485a..49732bd3e5 100644 --- a/repos/libports/lib/import/import-qt5_qmake.mk +++ b/repos/libports/lib/import/import-qt5_qmake.mk @@ -25,7 +25,7 @@ GENODE_QMAKE_CFLAGS += \ $(CC_OPT_NOSTDINC) \ $(CC_MARCH) \ $(CC_OPT_PIC) \ - $(filter-out -I.,$(INCLUDES)) \ + $(filter-out -I. $(foreach i,$(INCLUDES),$(if $(findstring /base-$(KERNEL)/include,$(i)),$(i))),$(INCLUDES)) \ -I$(CURDIR)/build_dependencies/include/QtCore/spec/$(QT_PLATFORM) GENODE_QMAKE_LFLAGS_APP += \ diff --git a/repos/libports/lib/import/import-qt6.inc b/repos/libports/lib/import/import-qt6.inc index 0ed9eba9e2..ca746b3874 100644 --- a/repos/libports/lib/import/import-qt6.inc +++ b/repos/libports/lib/import/import-qt6.inc @@ -13,13 +13,11 @@ $(error Error: unsupported platform) endif ifeq ($(CONTRIB_DIR),) -QT_DIR = $(call select_from_repositories,src/lib/qt6) -QT_API_DIR = $(call select_from_repositories,mkspecs)/.. +QT_API_DIR = $(abspath $(call select_from_repositories,lib/import/import-qt6.inc)/../../..) abi_symbol_path = $(wildcard $(call select_from_repositories,lib/symbols/$1)) else -QT_PORT_DIR := $(call select_from_ports,qt6) -QT_DIR = $(QT_PORT_DIR)/src/lib/qt6 -QT_API_DIR = $(QT_DIR)/genode/api +QT_API_PORT_DIR := $(call select_from_ports,qt6_api) +QT_API_DIR = $(QT_API_PORT_DIR)/src/lib/qt6_api abi_symbol_path = $(wildcard $(addprefix $(QT_API_DIR)/lib/symbols/,$1)) endif diff --git a/repos/libports/lib/import/import-qt6_cmake.mk b/repos/libports/lib/import/import-qt6_cmake.mk index e9ef66d25b..0b1f35bdae 100644 --- a/repos/libports/lib/import/import-qt6_cmake.mk +++ b/repos/libports/lib/import/import-qt6_cmake.mk @@ -23,7 +23,7 @@ GENODE_CMAKE_CFLAGS += \ $(CC_OPT_NOSTDINC) \ $(CC_MARCH) \ $(CC_OPT_PIC) \ - $(filter-out -I.,$(INCLUDES)) \ + $(filter-out -I. $(foreach i,$(INCLUDES),$(if $(findstring /base-$(KERNEL)/include,$(i)),$(i))),$(INCLUDES)) \ -I$(CURDIR)/build_dependencies/mkspecs/$(QT_PLATFORM) GENODE_CMAKE_LFLAGS_APP += \ diff --git a/repos/libports/lib/import/import-qt6_qmake.mk b/repos/libports/lib/import/import-qt6_qmake.mk index 5b4e340444..0c100e9312 100644 --- a/repos/libports/lib/import/import-qt6_qmake.mk +++ b/repos/libports/lib/import/import-qt6_qmake.mk @@ -25,7 +25,7 @@ GENODE_QMAKE_CFLAGS += \ $(CC_OPT_NOSTDINC) \ $(CC_MARCH) \ $(CC_OPT_PIC) \ - $(filter-out -I.,$(INCLUDES)) \ + $(filter-out -I. $(foreach i,$(INCLUDES),$(if $(findstring /base-$(KERNEL)/include,$(i)),$(i))),$(INCLUDES)) \ -I$(CURDIR)/build_dependencies/include/QtCore/spec/$(QT_PLATFORM) GENODE_QMAKE_LFLAGS_APP += \ diff --git a/repos/libports/lib/mk/libc.mk b/repos/libports/lib/mk/libc.mk index e491954a97..e7a4d1e942 100644 --- a/repos/libports/lib/mk/libc.mk +++ b/repos/libports/lib/mk/libc.mk @@ -12,14 +12,14 @@ LIBS += base vfs # Back end # SRC_CC = atexit.cc dummies.cc rlimit.cc sysctl.cc \ - issetugid.cc errno.cc gai_strerror.cc time.cc \ + issetugid.cc errno.cc gai_strerror.cc time.cc alarm.cc \ malloc.cc progname.cc fd_alloc.cc file_operations.cc \ plugin.cc plugin_registry.cc select.cc exit.cc environ.cc sleep.cc \ pread_pwrite.cc readv_writev.cc poll.cc \ vfs_plugin.cc dynamic_linker.cc signal.cc \ socket_operations.cc socket_fs_plugin.cc syscall.cc \ getpwent.cc getrandom.cc fork.cc execve.cc kernel.cc component.cc \ - genode.cc spinlock.cc + genode.cc spinlock.cc kqueue.cc # # Pthreads @@ -40,10 +40,6 @@ CC_OPT_dummies += -I$(LIBC_DIR)/sys INC_DIR += $(REP_DIR)/src/lib/libc INC_DIR += $(REP_DIR)/src/lib/libc/include -# needed for base/internal/unmanaged_singleton.h -INC_DIR += $(BASE_DIR)/src/include -INC_DIR += $(BASE_DIR)/sys - # # Files from string library that are not included in libc-raw_string because # they depend on the locale library. diff --git a/repos/libports/lib/mk/libgcov.mk b/repos/libports/lib/mk/libgcov.mk index 0f8b111b69..9fdd89f8b5 100644 --- a/repos/libports/lib/mk/libgcov.mk +++ b/repos/libports/lib/mk/libgcov.mk @@ -35,6 +35,8 @@ LIBGCOV_INTERFACE = _gcov_dump \ LIBGCOV_DRIVER = _gcov +CC_OPT_FREESTANDING = + CC_OPT += -fbuilding-libgcc -DIN_GCC -DIN_LIBGCC2 CC_OPT += $(addprefix -DL,$(LIBGCOV_MERGE)) diff --git a/repos/libports/lib/mk/mesa.inc b/repos/libports/lib/mk/mesa.inc index 33211dcad7..fa9451eeaa 100644 --- a/repos/libports/lib/mk/mesa.inc +++ b/repos/libports/lib/mk/mesa.inc @@ -691,6 +691,7 @@ SRC_C += c11/impl/threads_posix.c \ util/format/u_format_other.c \ util/format/u_format_rgtc.c \ util/format/u_format_s3tc.c \ + util/format/u_format_unpack_neon.c \ util/format/u_format_yuv.c \ util/format/u_format_zs.c \ util/half_float.c \ diff --git a/repos/libports/lib/mk/x86emu.mk b/repos/libports/lib/mk/x86emu.mk index 27de24f25f..6fccb59f16 100644 --- a/repos/libports/lib/mk/x86emu.mk +++ b/repos/libports/lib/mk/x86emu.mk @@ -6,6 +6,8 @@ X86EMU_DIR := $(call select_from_ports,x86emu)/src/lib/x86emu/contrib INC_DIR += $(X86EMU_DIR) $(REP_DIR)/include/x86emu CC_OPT += -fomit-frame-pointer -Wno-maybe-uninitialized +CC_OPT_FREESTANDING = + SRC_C = decode.c fpu.c ops.c ops2.c prim_ops.c sys.c vpath %.c $(X86EMU_DIR) diff --git a/repos/libports/lib/symbols/libc b/repos/libports/lib/symbols/libc index 445452a50d..15f04724fa 100644 --- a/repos/libports/lib/symbols/libc +++ b/repos/libports/lib/symbols/libc @@ -5,6 +5,7 @@ # # libc # +_Exit T ___mb_cur_max D 50 ___runetype T ___tolower T @@ -39,7 +40,6 @@ __stdoutp D 8 __swbuf T __test_sse T __xuname T -_Exit T _exit T _getlong T _getshort T @@ -412,8 +412,10 @@ iswupper T iswxdigit T isxdigit T jrand48 T +kevent T kill W killpg T +kqueue T ksem_init T l64a T l64a_r T @@ -479,6 +481,8 @@ nlist T nrand48 T offtime T open T +open_memstream T +open_wmemstream T openat T opendir T openlog T @@ -500,8 +504,8 @@ posix_fadvise T posix_madvise T posix_memalign T posix_spawn T -posix_spawn_file_actions_addclose T posix_spawn_file_actions_addchdir_np T +posix_spawn_file_actions_addclose T posix_spawn_file_actions_adddup2 T posix_spawn_file_actions_addopen T posix_spawn_file_actions_destroy T diff --git a/repos/libports/ports/libc.hash b/repos/libports/ports/libc.hash index e90372ce28..97776a9234 100644 --- a/repos/libports/ports/libc.hash +++ b/repos/libports/ports/libc.hash @@ -1 +1 @@ -b36b17e21acc3a6b70bc550e19d08abbb15db71a +ec685e91ee80735b4a067fea4582aa7f5d06c192 diff --git a/repos/libports/ports/libc.port b/repos/libports/ports/libc.port index 9a3911546c..6ebcee4723 100644 --- a/repos/libports/ports/libc.port +++ b/repos/libports/ports/libc.port @@ -129,7 +129,8 @@ DIR_CONTENT(include/libc/sys) := \ utsname.h elf.h mtio.h _stdint.h atomic_common.h _ucontext.h \ _cpuset.h _bitset.h bitset.h _stdarg.h _uio.h auxv.h random.h \ _sockaddr_storage.h termios.h _termios.h _umtx.h kerneldump.h \ - conf.h disk_zone.h counter.h soundcard.h pciio.h timex.h) + conf.h disk_zone.h counter.h soundcard.h pciio.h timex.h \ + cdio.h sched.h thr.h) DIRS += include/libc/sys/disk DIR_CONTENT(include/libc/sys/disk) := $(D)/sys/sys/disk/*h diff --git a/repos/libports/ports/mesa.hash b/repos/libports/ports/mesa.hash index 19666da459..c80c193080 100644 --- a/repos/libports/ports/mesa.hash +++ b/repos/libports/ports/mesa.hash @@ -1 +1 @@ -3aef4a625536591a08a8579caec868abe0115106 +9b5223fd7e5948d6c6e2dc2ad16605f3d539a27a diff --git a/repos/libports/ports/qt5.hash b/repos/libports/ports/qt5.hash index d345afade6..c1bc22cd7a 100644 --- a/repos/libports/ports/qt5.hash +++ b/repos/libports/ports/qt5.hash @@ -1 +1 @@ -e23cb2bb7b48d139b8ada3f2f9fec60637212f38 +0f70c667591b15b2bc5b89a2ce227fbf1a26896f diff --git a/repos/libports/ports/qt5.port b/repos/libports/ports/qt5.port index 5e9b55374a..69842b785b 100644 --- a/repos/libports/ports/qt5.port +++ b/repos/libports/ports/qt5.port @@ -4,5 +4,5 @@ VERSION := 5.15.2 DOWNLOADS := qt5.git URL(qt5) := https://github.com/cproc/qt5.git -REV(qt5) := issue5242 +REV(qt5) := issue5372 DIR(qt5) := src/lib/qt5 diff --git a/repos/libports/ports/qt6-host.hash b/repos/libports/ports/qt6-host.hash index 6010c9fc10..c186fb474c 100644 --- a/repos/libports/ports/qt6-host.hash +++ b/repos/libports/ports/qt6-host.hash @@ -1 +1 @@ -65bfe06368aa913897c75ac819acb9d1efdf367f +1a0072de9fae10738f0d32d367ffff063e6cdc7b diff --git a/repos/libports/ports/qt6-host.port b/repos/libports/ports/qt6-host.port index 107b9edb78..b79721f5f8 100644 --- a/repos/libports/ports/qt6-host.port +++ b/repos/libports/ports/qt6-host.port @@ -3,6 +3,6 @@ VERSION := 6.6.2 DOWNLOADS := qt6.archive -URL(qt6) := https://download.qt.io/official_releases/qt/6.6/6.6.2/single/qt-everywhere-src-6.6.2.tar.xz +URL(qt6) := https://download.qt.io/archive/qt/6.6/6.6.2/single/qt-everywhere-src-6.6.2.tar.xz SHA(qt6) := 3c1e42b3073ade1f7adbf06863c01e2c59521b7cc2349df2f74ecd7ebfcb922d DIR(qt6) := src/lib/qt6 diff --git a/repos/libports/ports/qt6.hash b/repos/libports/ports/qt6.hash deleted file mode 100644 index b19de305d9..0000000000 --- a/repos/libports/ports/qt6.hash +++ /dev/null @@ -1 +0,0 @@ -22e90c4bc425795166ebec55fd1853311862bc99 diff --git a/repos/libports/ports/qt6.port b/repos/libports/ports/qt6.port deleted file mode 100644 index a4f5229ba8..0000000000 --- a/repos/libports/ports/qt6.port +++ /dev/null @@ -1,8 +0,0 @@ -LICENSE := GPL -VERSION := 6.6.2 - -DOWNLOADS := qt6.git - -URL(qt6) := https://github.com/cproc/qt6.git -REV(qt6) := issue5325 -DIR(qt6) := src/lib/qt6 diff --git a/repos/libports/ports/qt6_api.hash b/repos/libports/ports/qt6_api.hash new file mode 100644 index 0000000000..caef29603d --- /dev/null +++ b/repos/libports/ports/qt6_api.hash @@ -0,0 +1 @@ +695f32b36de504cc9d882cba9c1bb539721939e8 diff --git a/repos/libports/ports/qt6_api.port b/repos/libports/ports/qt6_api.port new file mode 100644 index 0000000000..f25d5756c4 --- /dev/null +++ b/repos/libports/ports/qt6_api.port @@ -0,0 +1,8 @@ +LICENSE := LGPL +VERSION := 6.6.2 + +DOWNLOADS := qt6_api.git + +URL(qt6_api) := https://github.com/cproc/qt6_api.git +REV(qt6_api) := issue5419 +DIR(qt6_api) := src/lib/qt6_api diff --git a/repos/libports/ports/qt6_base.hash b/repos/libports/ports/qt6_base.hash new file mode 100644 index 0000000000..1e84ecdb7a --- /dev/null +++ b/repos/libports/ports/qt6_base.hash @@ -0,0 +1 @@ +41fd9fc068d730b69d2a64bae20fb4984ddc652c diff --git a/repos/libports/ports/qt6_base.port b/repos/libports/ports/qt6_base.port new file mode 100644 index 0000000000..b3f42503f8 --- /dev/null +++ b/repos/libports/ports/qt6_base.port @@ -0,0 +1,8 @@ +LICENSE := LGPL +VERSION := 6.6.2 + +DOWNLOADS := qt6_base.git + +URL(qt6_base) := https://github.com/cproc/qt6_base.git +REV(qt6_base) := issue5426 +DIR(qt6_base) := src/lib/qt6_base diff --git a/repos/libports/ports/qt6_declarative.hash b/repos/libports/ports/qt6_declarative.hash new file mode 100644 index 0000000000..c0a3278b0f --- /dev/null +++ b/repos/libports/ports/qt6_declarative.hash @@ -0,0 +1 @@ +2bcee8ddd2456a084c91e32d01387fa7392d3997 diff --git a/repos/libports/ports/qt6_declarative.port b/repos/libports/ports/qt6_declarative.port new file mode 100644 index 0000000000..c3af8e82f5 --- /dev/null +++ b/repos/libports/ports/qt6_declarative.port @@ -0,0 +1,8 @@ +LICENSE := LGPL +VERSION := 6.6.2 + +DOWNLOADS := qt6_declarative.git + +URL(qt6_declarative) := https://github.com/cproc/qt6_declarative.git +REV(qt6_declarative) := issue5402 +DIR(qt6_declarative) := src/lib/qt6_declarative diff --git a/repos/libports/ports/qt6_shadertools.hash b/repos/libports/ports/qt6_shadertools.hash new file mode 100644 index 0000000000..79b5891ab8 --- /dev/null +++ b/repos/libports/ports/qt6_shadertools.hash @@ -0,0 +1 @@ +ec9f67054cfafae32e1e811a738f9a0ae2f333d1 diff --git a/repos/libports/ports/qt6_shadertools.port b/repos/libports/ports/qt6_shadertools.port new file mode 100644 index 0000000000..8518bea2b1 --- /dev/null +++ b/repos/libports/ports/qt6_shadertools.port @@ -0,0 +1,8 @@ +LICENSE := LGPL +VERSION := 6.6.2 + +DOWNLOADS := qt6_shadertools.archive + +URL(qt6_shadertools) := https://download.qt.io/archive/qt/6.6/6.6.2/submodules/qtshadertools-everywhere-src-6.6.2.tar.xz +SHA(qt6_shadertools) := 628bead7ff4e7f42cb910f47d2adefbdea0d8c71a0234baef8ca709bf467b92f +DIR(qt6_shadertools) := src/lib/qt6_shadertools diff --git a/repos/libports/ports/qt6_svg.hash b/repos/libports/ports/qt6_svg.hash new file mode 100644 index 0000000000..f148f6d322 --- /dev/null +++ b/repos/libports/ports/qt6_svg.hash @@ -0,0 +1 @@ +30ec422bd2a6d26bd70a4e9d609a53e0cd45392d diff --git a/repos/libports/ports/qt6_svg.port b/repos/libports/ports/qt6_svg.port new file mode 100644 index 0000000000..6eba77717b --- /dev/null +++ b/repos/libports/ports/qt6_svg.port @@ -0,0 +1,8 @@ +LICENSE := LGPL +VERSION := 6.6.2 + +DOWNLOADS := qt6_svg.archive + +URL(qt6_svg) := https://download.qt.io/archive/qt/6.6/6.6.2/submodules/qtsvg-everywhere-src-6.6.2.tar.xz +SHA(qt6_svg) := 5a231d59ef1b42bfbaa5174d4ff39f8e1b4ba070ef984a70b069b4b2576d8181 +DIR(qt6_svg) := src/lib/qt6_svg diff --git a/repos/libports/ports/qt6_tools.hash b/repos/libports/ports/qt6_tools.hash new file mode 100644 index 0000000000..4c7c374354 --- /dev/null +++ b/repos/libports/ports/qt6_tools.hash @@ -0,0 +1 @@ +178b2eaa49d51ac12313e755a2cb51957256cbfb diff --git a/repos/libports/ports/qt6_tools.port b/repos/libports/ports/qt6_tools.port new file mode 100644 index 0000000000..abe38a6b29 --- /dev/null +++ b/repos/libports/ports/qt6_tools.port @@ -0,0 +1,8 @@ +LICENSE := LGPL +VERSION := 6.6.2 + +DOWNLOADS := qt6_tools.archive + +URL(qt6_tools) := https://download.qt.io/archive/qt/6.6/6.6.2/submodules/qttools-everywhere-src-6.6.2.tar.xz +SHA(qt6_tools) := e6d49e9f52111287f77878ecb8b708cce682f10b03ba2476d9247603bc6c4746 +DIR(qt6_tools) := src/lib/qt6_tools diff --git a/repos/libports/recipes/api/libc/hash b/repos/libports/recipes/api/libc/hash index daa176ea06..3e711ee8ba 100644 --- a/repos/libports/recipes/api/libc/hash +++ b/repos/libports/recipes/api/libc/hash @@ -1 +1 @@ -2024-08-28 9379c5dffb979872b30bd0eb4b1c25f8d48aa2c1 +2024-10-07 a6e2ece598616bef586df2a764ec3eb3f04e9912 diff --git a/repos/libports/recipes/api/qt5_base/hash b/repos/libports/recipes/api/qt5_base/hash index 98caf4b75b..94bd77b744 100644 --- a/repos/libports/recipes/api/qt5_base/hash +++ b/repos/libports/recipes/api/qt5_base/hash @@ -1 +1 @@ -2024-08-28 8102f6383f9a553220ca2517b91e503f61504a0d +2024-10-08 7995b0bc72b98634581a2fdf01fa8b7ef45c8f68 diff --git a/repos/libports/recipes/api/qt6_base/content.mk b/repos/libports/recipes/api/qt6_base/content.mk index 25745c7270..fedc48767a 100644 --- a/repos/libports/recipes/api/qt6_base/content.mk +++ b/repos/libports/recipes/api/qt6_base/content.mk @@ -9,8 +9,8 @@ content: $(MIRROR_FROM_REP_DIR) $(MIRROR_FROM_REP_DIR): $(mirror_from_rep_dir) -PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6) -API_DIR := $(PORT_DIR)/src/lib/qt6/genode/api +PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6_api) +API_DIR := $(PORT_DIR)/src/lib/qt6_api MIRROR_FROM_PORT_DIR := include \ metatypes \ @@ -45,4 +45,4 @@ $(MIRROR_SYMBOLS): content: LICENSE LICENSE: - cp $(PORT_DIR)/src/lib/qt6/LICENSE.LGPL3 $@ + cp $(PORT_DIR)/src/lib/qt6_api/LICENSE.LGPL3 $@ diff --git a/repos/libports/recipes/api/qt6_base/hash b/repos/libports/recipes/api/qt6_base/hash index 271db52a32..b5cd7493fc 100644 --- a/repos/libports/recipes/api/qt6_base/hash +++ b/repos/libports/recipes/api/qt6_base/hash @@ -1 +1 @@ -2024-08-28 35586b2d126274d93cd9ba9c5fdc562ba839e2f0 +2024-10-08 b3fc4960265c42de87bc1c770046fb7f3b9f071d diff --git a/repos/libports/recipes/api/qt6_declarative/content.mk b/repos/libports/recipes/api/qt6_declarative/content.mk index aca3de601a..59708129ae 100644 --- a/repos/libports/recipes/api/qt6_declarative/content.mk +++ b/repos/libports/recipes/api/qt6_declarative/content.mk @@ -1,4 +1,4 @@ -PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6) +PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6_api) MIRROR_LIB_SYMBOLS := libQt6LabsAnimation \ libQt6LabsFolderListModel \ @@ -31,9 +31,9 @@ content: $(MIRROR_LIB_SYMBOLS) $(MIRROR_LIB_SYMBOLS): mkdir -p lib/symbols - cp $(PORT_DIR)/src/lib/qt6/genode/api/lib/symbols/$@ lib/symbols/ + cp $(PORT_DIR)/src/lib/qt6_api/lib/symbols/$@ lib/symbols/ content: LICENSE LICENSE: - cp $(PORT_DIR)/src/lib/qt6/LICENSE.LGPL3 $@ + cp $(PORT_DIR)/src/lib/qt6_api/LICENSE.LGPL3 $@ diff --git a/repos/libports/recipes/api/qt6_shadertools/content.mk b/repos/libports/recipes/api/qt6_shadertools/content.mk index 8b264b5c17..f24ea73c36 100644 --- a/repos/libports/recipes/api/qt6_shadertools/content.mk +++ b/repos/libports/recipes/api/qt6_shadertools/content.mk @@ -1,4 +1,4 @@ -PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6) +PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6_api) MIRROR_LIB_SYMBOLS := libQt6ShaderTools @@ -6,9 +6,9 @@ content: $(MIRROR_LIB_SYMBOLS) $(MIRROR_LIB_SYMBOLS): mkdir -p lib/symbols - cp $(PORT_DIR)/src/lib/qt6/genode/api/lib/symbols/$@ lib/symbols/ + cp $(PORT_DIR)/src/lib/qt6_api/lib/symbols/$@ lib/symbols/ content: LICENSE LICENSE: - cp $(PORT_DIR)/src/lib/qt6/LICENSE.LGPL3 $@ + cp $(PORT_DIR)/src/lib/qt6_api/LICENSE.LGPL3 $@ diff --git a/repos/libports/recipes/api/qt6_svg/content.mk b/repos/libports/recipes/api/qt6_svg/content.mk index a85b1a8c41..5eb948b85a 100644 --- a/repos/libports/recipes/api/qt6_svg/content.mk +++ b/repos/libports/recipes/api/qt6_svg/content.mk @@ -1,14 +1,15 @@ -PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6) +PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6_api) -MIRROR_LIB_SYMBOLS := libQt6Svg +MIRROR_LIB_SYMBOLS := libQt6Svg \ + libQt6SvgWidgets content: $(MIRROR_LIB_SYMBOLS) $(MIRROR_LIB_SYMBOLS): mkdir -p lib/symbols - cp $(PORT_DIR)/src/lib/qt6/genode/api/lib/symbols/$@ lib/symbols/ + cp $(PORT_DIR)/src/lib/qt6_api/lib/symbols/$@ lib/symbols/ content: LICENSE LICENSE: - cp $(PORT_DIR)/src/lib/qt6/LICENSE.LGPL3 $@ + cp $(PORT_DIR)/src/lib/qt6_api/LICENSE.LGPL3 $@ diff --git a/repos/libports/recipes/pkg/acpica/hash b/repos/libports/recipes/pkg/acpica/hash index 459cdd4e9c..ab728d69a1 100644 --- a/repos/libports/recipes/pkg/acpica/hash +++ b/repos/libports/recipes/pkg/acpica/hash @@ -1 +1 @@ -2024-08-28 1ee2d143d5c06464cd106807bca73882397b24ba +2024-12-10 121ec4ccd1bb65240ce5000ca49a48bf58bb74d8 diff --git a/repos/libports/recipes/pkg/gcov/hash b/repos/libports/recipes/pkg/gcov/hash index 8a44bd427d..3e93ba3b91 100644 --- a/repos/libports/recipes/pkg/gcov/hash +++ b/repos/libports/recipes/pkg/gcov/hash @@ -1 +1 @@ -2024-08-28 5cdec0dd8c3a3516d907b10646388d67598b6150 +2024-12-10 af269e32d413b8ef33796a3bf00407307f6d727b diff --git a/repos/libports/recipes/pkg/mesa_gears/hash b/repos/libports/recipes/pkg/mesa_gears/hash index 00c2722926..7cb293d0e4 100644 --- a/repos/libports/recipes/pkg/mesa_gears/hash +++ b/repos/libports/recipes/pkg/mesa_gears/hash @@ -1 +1 @@ -2024-08-28 3510c564a279f4c4d1b8fb0916e36404fcb0b197 +2024-12-10 dda272c83b32ea84701cf2ae8d88a075330a1d31 diff --git a/repos/libports/recipes/pkg/mesa_gears/runtime b/repos/libports/recipes/pkg/mesa_gears/runtime index 10ad36f9e2..a75fad3dd5 100644 --- a/repos/libports/recipes/pkg/mesa_gears/runtime +++ b/repos/libports/recipes/pkg/mesa_gears/runtime @@ -1,4 +1,4 @@ -<runtime ram="40M" caps="400" binary="gears"> +<runtime ram="52M" caps="400" binary="gears"> <requires> <gui/> diff --git a/repos/libports/recipes/pkg/mesa_gpu-cpu/hash b/repos/libports/recipes/pkg/mesa_gpu-cpu/hash index 9eb3f338c1..c14603879f 100644 --- a/repos/libports/recipes/pkg/mesa_gpu-cpu/hash +++ b/repos/libports/recipes/pkg/mesa_gpu-cpu/hash @@ -1 +1 @@ -2024-08-28 e7434626ac0bc82f9a84912c0547517825509065 +2024-12-10 48918ee462c6fc17752b9e49cd1542e47eb89b38 diff --git a/repos/libports/recipes/pkg/mesa_gpu-etnaviv/hash b/repos/libports/recipes/pkg/mesa_gpu-etnaviv/hash index 57bf54be50..b452372ec1 100644 --- a/repos/libports/recipes/pkg/mesa_gpu-etnaviv/hash +++ b/repos/libports/recipes/pkg/mesa_gpu-etnaviv/hash @@ -1 +1 @@ -2024-08-28 f539670a9aac5e2c6a8d0e4e3e1d3d73ce2e9c5e +2024-12-10 6942da742f12b10bad1e722a3f35a3adb57e7ccf diff --git a/repos/libports/recipes/pkg/mesa_gpu-intel/hash b/repos/libports/recipes/pkg/mesa_gpu-intel/hash index fd4ab2d710..48528234ae 100644 --- a/repos/libports/recipes/pkg/mesa_gpu-intel/hash +++ b/repos/libports/recipes/pkg/mesa_gpu-intel/hash @@ -1 +1 @@ -2024-08-28 cf4031a18d658db8221ece9e838cae7030c84c7b +2024-12-10 fe0faac47649d3c25dfc42bb764f18802862def9 diff --git a/repos/libports/recipes/pkg/mesa_gpu-lima/hash b/repos/libports/recipes/pkg/mesa_gpu-lima/hash index b28ac65539..426049d6b9 100644 --- a/repos/libports/recipes/pkg/mesa_gpu-lima/hash +++ b/repos/libports/recipes/pkg/mesa_gpu-lima/hash @@ -1 +1 @@ -2024-08-28 3db59b0f7fde31a625191a3b049c7b633b6df06e +2024-12-10 bbdf91328a4fcb2a63ef33cbd4ebc56e721fe338 diff --git a/repos/libports/recipes/pkg/pdf_view/hash b/repos/libports/recipes/pkg/pdf_view/hash index 5b3f785b69..fa261b3fbf 100644 --- a/repos/libports/recipes/pkg/pdf_view/hash +++ b/repos/libports/recipes/pkg/pdf_view/hash @@ -1 +1 @@ -2024-08-28 b0b695aa384655b242ffc55e87e15a80cdb33d18 +2024-12-10 bc9018e108e8a1e1952f90269cb3b62b1d1ea299 diff --git a/repos/libports/recipes/pkg/qt5_textedit/hash b/repos/libports/recipes/pkg/qt5_textedit/hash index d9edd703e6..fb85ce39db 100644 --- a/repos/libports/recipes/pkg/qt5_textedit/hash +++ b/repos/libports/recipes/pkg/qt5_textedit/hash @@ -1 +1 @@ -2024-08-28 c49e99d322ee3a06253dd84bd6de12f31a76586b +2024-12-10 ca397cfe2adea2dc1448c915a0d755cdfd23cbce diff --git a/repos/libports/recipes/pkg/sntp_dummy_rtc/hash b/repos/libports/recipes/pkg/sntp_dummy_rtc/hash index 954806c415..5559d81ebf 100644 --- a/repos/libports/recipes/pkg/sntp_dummy_rtc/hash +++ b/repos/libports/recipes/pkg/sntp_dummy_rtc/hash @@ -1 +1 @@ -2024-08-28 9c221f3f3960e012155bb0e9a884bcc79a918059 +2024-12-10 5ad5a2a6da1d082c14f970af2c8a4c99cd6bdcf0 diff --git a/repos/libports/recipes/pkg/stdin2out/hash b/repos/libports/recipes/pkg/stdin2out/hash index 3d5802b4fd..225fc65981 100644 --- a/repos/libports/recipes/pkg/stdin2out/hash +++ b/repos/libports/recipes/pkg/stdin2out/hash @@ -1 +1 @@ -2024-08-28 59c1e981b6eb839e967fac60fb5eb5d2db2de5de +2024-12-10 db496256fec365489f324ff92ee72b4aaa651b8e diff --git a/repos/libports/recipes/pkg/system_clock-dummy/hash b/repos/libports/recipes/pkg/system_clock-dummy/hash index a0460021e7..851043db77 100644 --- a/repos/libports/recipes/pkg/system_clock-dummy/hash +++ b/repos/libports/recipes/pkg/system_clock-dummy/hash @@ -1 +1 @@ -2024-08-28 26d008dde90d8f2cc8fb344b8ca68a0a45b91cec +2024-12-10 0ad8aa8c45e8cf7dd0871be0718ddc92689056af diff --git a/repos/libports/recipes/pkg/system_clock-pc/hash b/repos/libports/recipes/pkg/system_clock-pc/hash index 493980f3e5..6e17ab27b1 100644 --- a/repos/libports/recipes/pkg/system_clock-pc/hash +++ b/repos/libports/recipes/pkg/system_clock-pc/hash @@ -1 +1 @@ -2024-08-28 a872253f6c55b71c4778c580033cfb6469d650b2 +2024-12-10 fcda51329ca8462ada61596bcf1ab809ded39599 diff --git a/repos/libports/recipes/pkg/system_rtc-linux/hash b/repos/libports/recipes/pkg/system_rtc-linux/hash index 7d567eafa4..1f3b847c52 100644 --- a/repos/libports/recipes/pkg/system_rtc-linux/hash +++ b/repos/libports/recipes/pkg/system_rtc-linux/hash @@ -1 +1 @@ -2024-08-28 bc61dcc556e69667fe8f996bed5342723109e90c +2024-12-10 08421b5a46a7ce90a846fdb3bed81ad4ba915df8 diff --git a/repos/libports/recipes/pkg/system_rtc-pc/hash b/repos/libports/recipes/pkg/system_rtc-pc/hash index 8ecf07363e..406ae70cb0 100644 --- a/repos/libports/recipes/pkg/system_rtc-pc/hash +++ b/repos/libports/recipes/pkg/system_rtc-pc/hash @@ -1 +1 @@ -2024-08-28 4e0a2ae8d9997100bfc261f78d0e5122346227f1 +2024-12-10 93660c8ddb82a609c314e1a55a02d4a566bc6cbe diff --git a/repos/libports/recipes/pkg/test-expat/hash b/repos/libports/recipes/pkg/test-expat/hash index d031ee157d..92846c66f6 100644 --- a/repos/libports/recipes/pkg/test-expat/hash +++ b/repos/libports/recipes/pkg/test-expat/hash @@ -1 +1 @@ -2024-08-28 44da74de0017a93c29bae0efc0c987a1090e2129 +2024-12-10 664553d3662c65ac29a769659603a48c12a6b9fb diff --git a/repos/libports/recipes/pkg/test-ldso/hash b/repos/libports/recipes/pkg/test-ldso/hash index 47a467b2b7..cc29191da7 100644 --- a/repos/libports/recipes/pkg/test-ldso/hash +++ b/repos/libports/recipes/pkg/test-ldso/hash @@ -1 +1 @@ -2024-08-28 7474fb492dbc0d22c766cbec7646b8ece3d1595a +2024-12-10 a1dc6f056987c1a96492b91668a0e9516a4e09a5 diff --git a/repos/libports/recipes/pkg/test-libc/hash b/repos/libports/recipes/pkg/test-libc/hash index 4e8a6cf4d1..bdeacab157 100644 --- a/repos/libports/recipes/pkg/test-libc/hash +++ b/repos/libports/recipes/pkg/test-libc/hash @@ -1 +1 @@ -2024-08-28 a6696dfc682e12a5a3bf9b82ae20e10b47cfc3da +2024-12-10 a4eef0829067c1b0419e58c5a114ac508fbad0b8 diff --git a/repos/libports/recipes/pkg/test-libc_alarm/README b/repos/libports/recipes/pkg/test-libc_alarm/README new file mode 100644 index 0000000000..77680bcf90 --- /dev/null +++ b/repos/libports/recipes/pkg/test-libc_alarm/README @@ -0,0 +1 @@ +Libc alarm() test. diff --git a/repos/libports/recipes/pkg/test-libc_alarm/archives b/repos/libports/recipes/pkg/test-libc_alarm/archives new file mode 100644 index 0000000000..170cda551e --- /dev/null +++ b/repos/libports/recipes/pkg/test-libc_alarm/archives @@ -0,0 +1,5 @@ +_/src/init +_/src/test-libc_alarm +_/src/libc +_/src/posix +_/src/vfs diff --git a/repos/libports/recipes/pkg/test-libc_alarm/hash b/repos/libports/recipes/pkg/test-libc_alarm/hash new file mode 100644 index 0000000000..e96472d591 --- /dev/null +++ b/repos/libports/recipes/pkg/test-libc_alarm/hash @@ -0,0 +1 @@ +2024-12-10 6fe397534cdb350b062acc6cc1315384da1e268e diff --git a/repos/libports/recipes/pkg/test-libc_alarm/runtime b/repos/libports/recipes/pkg/test-libc_alarm/runtime new file mode 100644 index 0000000000..24bf4b4bce --- /dev/null +++ b/repos/libports/recipes/pkg/test-libc_alarm/runtime @@ -0,0 +1,22 @@ +<runtime ram="3M" caps="200" binary="test-libc_alarm"> + + <requires> <timer/> </requires> + + <fail after_seconds="13"/> + <succeed>triggered_alarms=3</succeed> + + <content> + <rom label="ld.lib.so"/> + <rom label="test-libc_alarm"/> + <rom label="libc.lib.so"/> + <rom label="libm.lib.so"/> + <rom label="vfs.lib.so"/> + <rom label="posix.lib.so"/> + </content> + + <config> + <vfs> <dir name="dev"> <log/> </dir> </vfs> + <libc stdout="/dev/log" stderr="/dev/log"/> + <arg value="test-libc_alarm"/> + </config> +</runtime> diff --git a/repos/libports/recipes/pkg/test-libc_connect_lwip/hash b/repos/libports/recipes/pkg/test-libc_connect_lwip/hash index 9fefa5a06e..e0287d6540 100644 --- a/repos/libports/recipes/pkg/test-libc_connect_lwip/hash +++ b/repos/libports/recipes/pkg/test-libc_connect_lwip/hash @@ -1 +1 @@ -2024-08-28 80bcf60784c0414a9c23d0f96a87d1ea58b26d1b +2024-12-10 6af3ac567ae5a1a44c5023b917c55240538a9f74 diff --git a/repos/libports/recipes/pkg/test-libc_connect_lxip/hash b/repos/libports/recipes/pkg/test-libc_connect_lxip/hash index 03833dae5e..a4c35f2ec4 100644 --- a/repos/libports/recipes/pkg/test-libc_connect_lxip/hash +++ b/repos/libports/recipes/pkg/test-libc_connect_lxip/hash @@ -1 +1 @@ -2024-08-28 00e9c32ef8ad6637042b647d1f3e0199aacc3931 +2024-12-10 7326696121c89c181551e630489fccef693d7985 diff --git a/repos/libports/recipes/pkg/test-libc_connect_vfs_server_lwip/hash b/repos/libports/recipes/pkg/test-libc_connect_vfs_server_lwip/hash index 641c18f6d1..3c77e0d8d0 100644 --- a/repos/libports/recipes/pkg/test-libc_connect_vfs_server_lwip/hash +++ b/repos/libports/recipes/pkg/test-libc_connect_vfs_server_lwip/hash @@ -1 +1 @@ -2024-08-28 9a85a1c95c43016d5d5e6ab157efb7166948bda1 +2024-12-10 b731c3a9cbce909e8d253a7605be787ec73f9999 diff --git a/repos/libports/recipes/pkg/test-libc_connect_vfs_server_lxip/hash b/repos/libports/recipes/pkg/test-libc_connect_vfs_server_lxip/hash index 5df68c449b..773f5bbff1 100644 --- a/repos/libports/recipes/pkg/test-libc_connect_vfs_server_lxip/hash +++ b/repos/libports/recipes/pkg/test-libc_connect_vfs_server_lxip/hash @@ -1 +1 @@ -2024-08-28 278fb455c44f616f22c74eee623bcdef841a251a +2024-12-10 de6b3ad2871b7b0cdac4f116f9d3f1a9ad82ef96 diff --git a/repos/libports/recipes/pkg/test-libc_counter/hash b/repos/libports/recipes/pkg/test-libc_counter/hash index 31d468e8bc..7ffa79ffae 100644 --- a/repos/libports/recipes/pkg/test-libc_counter/hash +++ b/repos/libports/recipes/pkg/test-libc_counter/hash @@ -1 +1 @@ -2024-08-28 241918fa6247f5ecdd582489a2ca361b486533c0 +2024-12-10 00eee3dd9ce33aaa002f4a7bb3a1e534f4d218dd diff --git a/repos/libports/recipes/pkg/test-libc_deferred_unlink/hash b/repos/libports/recipes/pkg/test-libc_deferred_unlink/hash index ddecb890e2..0030507452 100644 --- a/repos/libports/recipes/pkg/test-libc_deferred_unlink/hash +++ b/repos/libports/recipes/pkg/test-libc_deferred_unlink/hash @@ -1 +1 @@ -2024-08-28 b6fdd7ee35ef64dbe95d9bc596e7be3a3b2aa14f +2024-12-10 cdd03118be7a56a561061714a83268e9f9ec2478 diff --git a/repos/libports/recipes/pkg/test-libc_execve/hash b/repos/libports/recipes/pkg/test-libc_execve/hash index 554f156e3f..8db2a8aa02 100644 --- a/repos/libports/recipes/pkg/test-libc_execve/hash +++ b/repos/libports/recipes/pkg/test-libc_execve/hash @@ -1 +1 @@ -2024-08-28 afb55f4e983a0b7ca78390aa26dcb01da3f539d7 +2024-12-10 1c18330413564c7330d6242c0fe889b39720cf73 diff --git a/repos/libports/recipes/pkg/test-libc_fifo_pipe/hash b/repos/libports/recipes/pkg/test-libc_fifo_pipe/hash index a4911daf0e..12e5a327a0 100644 --- a/repos/libports/recipes/pkg/test-libc_fifo_pipe/hash +++ b/repos/libports/recipes/pkg/test-libc_fifo_pipe/hash @@ -1 +1 @@ -2024-08-28 0aa7429c224923424e5c38f1dac97c01eb4895e5 +2024-12-10 1e94492019fbca38e656921805a37c54c3395db6 diff --git a/repos/libports/recipes/pkg/test-libc_fifo_pipe/runtime b/repos/libports/recipes/pkg/test-libc_fifo_pipe/runtime index 8084fa3a45..073007e196 100644 --- a/repos/libports/recipes/pkg/test-libc_fifo_pipe/runtime +++ b/repos/libports/recipes/pkg/test-libc_fifo_pipe/runtime @@ -114,7 +114,7 @@ </config> </start> - <start name="fifo-pipe-test"> + <start name="fifo-pipe-test" caps="150"> <binary name="test-libc_fifo_pipe"/> <resource name="RAM" quantum="8M"/> <config iterations="15"> diff --git a/repos/libports/recipes/pkg/test-libc_fork/hash b/repos/libports/recipes/pkg/test-libc_fork/hash index aa762556f3..96ec5d25ed 100644 --- a/repos/libports/recipes/pkg/test-libc_fork/hash +++ b/repos/libports/recipes/pkg/test-libc_fork/hash @@ -1 +1 @@ -2024-08-28 dc3035dfb5ac1aaf1b5e8792dd3f42e5a62db693 +2024-12-10 1cae3c32f35211ef9d5fadd2912ca0cdb1c33778 diff --git a/repos/libports/recipes/pkg/test-libc_getenv/hash b/repos/libports/recipes/pkg/test-libc_getenv/hash index 9a6a2bc161..902ff18de3 100644 --- a/repos/libports/recipes/pkg/test-libc_getenv/hash +++ b/repos/libports/recipes/pkg/test-libc_getenv/hash @@ -1 +1 @@ -2024-08-28 c40edbbd8af8cd5abb52febe5d2cb57c463a50ab +2024-12-10 c747699be50cf46caac1b0646ca7a830bd2eb3dd diff --git a/repos/libports/recipes/pkg/test-libc_kqueue/README b/repos/libports/recipes/pkg/test-libc_kqueue/README new file mode 100644 index 0000000000..441a3c17f2 --- /dev/null +++ b/repos/libports/recipes/pkg/test-libc_kqueue/README @@ -0,0 +1 @@ +Libc kqueue() test. diff --git a/repos/libports/recipes/pkg/test-libc_kqueue/archives b/repos/libports/recipes/pkg/test-libc_kqueue/archives new file mode 100644 index 0000000000..ba509bbbea --- /dev/null +++ b/repos/libports/recipes/pkg/test-libc_kqueue/archives @@ -0,0 +1,5 @@ +_/src/init +_/src/libc +_/src/posix +_/src/test-libc_kqueue +_/src/vfs diff --git a/repos/libports/recipes/pkg/test-libc_kqueue/hash b/repos/libports/recipes/pkg/test-libc_kqueue/hash new file mode 100644 index 0000000000..b3e5d45800 --- /dev/null +++ b/repos/libports/recipes/pkg/test-libc_kqueue/hash @@ -0,0 +1 @@ +2024-12-10 647d576e00ce86b009a2a6f9e23826b9b024c544 diff --git a/repos/libports/recipes/pkg/test-libc_kqueue/runtime b/repos/libports/recipes/pkg/test-libc_kqueue/runtime new file mode 100644 index 0000000000..c2f00c7caf --- /dev/null +++ b/repos/libports/recipes/pkg/test-libc_kqueue/runtime @@ -0,0 +1,24 @@ +<runtime ram="3M" caps="200" binary="test-libc_kqueue"> + + <requires> <timer/> </requires> + + <fail after_seconds="8"/> + <succeed>--- test succeeded ---</succeed> + + <content> + <rom label="ld.lib.so"/> + <rom label="libc.lib.so"/> + <rom label="libm.lib.so"/> + <rom label="posix.lib.so"/> + <rom label="test-libc_kqueue"/> + <rom label="vfs.lib.so"/> + </content> + + <config> + <vfs> <dir name="dev"> <log/> <inline name="rtc">2019-08-20 15:01</inline> </dir> </vfs> + <libc stdout="/dev/log" stderr="/dev/log" rtc="/dev/rtc"/> + <arg value="test-libc_kqueue"/> + <arg value="/dev/log"/> + </config> + +</runtime> diff --git a/repos/libports/recipes/pkg/test-libc_pipe/hash b/repos/libports/recipes/pkg/test-libc_pipe/hash index cabfdf1256..c114e9ae69 100644 --- a/repos/libports/recipes/pkg/test-libc_pipe/hash +++ b/repos/libports/recipes/pkg/test-libc_pipe/hash @@ -1 +1 @@ -2024-08-28 f55cc506f155d11f4f5c01bacbd218b231a66df4 +2024-12-10 cff5f1ca6b50ee2dbd94b48836c0b0c94d7f2d92 diff --git a/repos/libports/recipes/pkg/test-libc_vfs/hash b/repos/libports/recipes/pkg/test-libc_vfs/hash index 193cc2c87f..ce0ff18aec 100644 --- a/repos/libports/recipes/pkg/test-libc_vfs/hash +++ b/repos/libports/recipes/pkg/test-libc_vfs/hash @@ -1 +1 @@ -2024-08-28 c22a975e629999c616087dcee53c15ec492334cd +2024-12-10 8ee1d295a355d93fcf41d9b54e1c7ac644f9fc80 diff --git a/repos/libports/recipes/pkg/test-libc_vfs_block/hash b/repos/libports/recipes/pkg/test-libc_vfs_block/hash index b0fd157325..3366d285db 100644 --- a/repos/libports/recipes/pkg/test-libc_vfs_block/hash +++ b/repos/libports/recipes/pkg/test-libc_vfs_block/hash @@ -1 +1 @@ -2024-08-28 d446f17a8d192495a99dfaea37cd4aa61bfcf7b2 +2024-12-10 a710420d89ebf3d1f7cb3f7260e8be1581d20e3e diff --git a/repos/libports/recipes/pkg/test-libc_vfs_counter/hash b/repos/libports/recipes/pkg/test-libc_vfs_counter/hash index 24061b66f6..5486325636 100644 --- a/repos/libports/recipes/pkg/test-libc_vfs_counter/hash +++ b/repos/libports/recipes/pkg/test-libc_vfs_counter/hash @@ -1 +1 @@ -2024-08-28 30c1a830a974b89d6929e5aaff8f63d3269f1b98 +2024-12-10 867cd9017ef096410fc11ea4d2c1c82f4ed5cdee diff --git a/repos/libports/recipes/pkg/test-libc_vfs_fs/hash b/repos/libports/recipes/pkg/test-libc_vfs_fs/hash index 91ebe3e84e..709b197278 100644 --- a/repos/libports/recipes/pkg/test-libc_vfs_fs/hash +++ b/repos/libports/recipes/pkg/test-libc_vfs_fs/hash @@ -1 +1 @@ -2024-08-28 e21f251b902d518ea7c55eaa7772751d4dfd740c +2024-12-10 559a9941aaa696bec6b3ddd07961ba7116c66106 diff --git a/repos/libports/recipes/pkg/test-libc_vfs_fs_chained/hash b/repos/libports/recipes/pkg/test-libc_vfs_fs_chained/hash index d0c1c726ac..a64f81496f 100644 --- a/repos/libports/recipes/pkg/test-libc_vfs_fs_chained/hash +++ b/repos/libports/recipes/pkg/test-libc_vfs_fs_chained/hash @@ -1 +1 @@ -2024-08-28 a9a1c3c394fbf08746779b2a843defe692e1c66e +2024-12-10 b7f55a88ddb7a1267f1eca4f510a45a8507bba5f diff --git a/repos/libports/recipes/pkg/test-libc_vfs_oss/hash b/repos/libports/recipes/pkg/test-libc_vfs_oss/hash index 8c2d68e1c3..363734560c 100644 --- a/repos/libports/recipes/pkg/test-libc_vfs_oss/hash +++ b/repos/libports/recipes/pkg/test-libc_vfs_oss/hash @@ -1 +1 @@ -2024-08-28 a49d4d2740107d776c5b6e96472eec3aaab10469 +2024-12-10 339bb9e81f62342a6a342b336cf1f926e44845be diff --git a/repos/libports/recipes/pkg/test-libc_vfs_ram/hash b/repos/libports/recipes/pkg/test-libc_vfs_ram/hash index 4518e8ed8d..96b0365ba7 100644 --- a/repos/libports/recipes/pkg/test-libc_vfs_ram/hash +++ b/repos/libports/recipes/pkg/test-libc_vfs_ram/hash @@ -1 +1 @@ -2024-08-28 17e6617df1e36fb7c1ec28fcc9912cc0b603f526 +2024-12-10 2891f418ab62e1a3cc09b4ab0162c68ef64f4344 diff --git a/repos/libports/recipes/pkg/test-pipe_read_ready/hash b/repos/libports/recipes/pkg/test-pipe_read_ready/hash index 0a74e6c366..3bfd46a854 100644 --- a/repos/libports/recipes/pkg/test-pipe_read_ready/hash +++ b/repos/libports/recipes/pkg/test-pipe_read_ready/hash @@ -1 +1 @@ -2024-08-28 0c3c755a179011155c23cbb541a054a1a3e758cb +2024-12-10 216db93c6d2370a0251d16fbcdcfbd12474ab708 diff --git a/repos/libports/recipes/pkg/test-pthread/hash b/repos/libports/recipes/pkg/test-pthread/hash index 13eaab2ede..59cbed34d6 100644 --- a/repos/libports/recipes/pkg/test-pthread/hash +++ b/repos/libports/recipes/pkg/test-pthread/hash @@ -1 +1 @@ -2024-08-28 96de69554cb3993d7f907077bdcacf8ff21a3cc7 +2024-12-10 d36d6ddbf70c3a20d8fba33b7491ee08ccf5cba0 diff --git a/repos/libports/recipes/pkg/test-pthread/runtime b/repos/libports/recipes/pkg/test-pthread/runtime index 1c2a9a8283..1e3ba85f3c 100644 --- a/repos/libports/recipes/pkg/test-pthread/runtime +++ b/repos/libports/recipes/pkg/test-pthread/runtime @@ -27,7 +27,7 @@ <default-route> <any-service> <parent/> <any-child/> </any-service> </default-route> - <start name="test-pthread" caps="200"> + <start name="test-pthread" caps="600"> <resource name="RAM" quantum="64M"/> <config> <vfs> <dir name="dev"> <log/> </dir> </vfs> diff --git a/repos/libports/recipes/pkg/test-sequence/hash b/repos/libports/recipes/pkg/test-sequence/hash index 3e54e14fd3..0c7225a6f0 100644 --- a/repos/libports/recipes/pkg/test-sequence/hash +++ b/repos/libports/recipes/pkg/test-sequence/hash @@ -1 +1 @@ -2024-08-28 9acdab39ff9c7930a34696300097d6c085afe016 +2024-12-10 b4128c2ae28b4302ed04a92d919771a26fbd7405 diff --git a/repos/libports/recipes/pkg/test-spark/hash b/repos/libports/recipes/pkg/test-spark/hash index 51c09c4037..b9679bc45a 100644 --- a/repos/libports/recipes/pkg/test-spark/hash +++ b/repos/libports/recipes/pkg/test-spark/hash @@ -1 +1 @@ -2024-08-28 dba38ef565a0a5c2aef8e0186184ccd2e97b73b8 +2024-12-10 882475b6306a0cc6480c36c7b7abc03858caed70 diff --git a/repos/libports/recipes/pkg/test-spark_exception/hash b/repos/libports/recipes/pkg/test-spark_exception/hash index 0be527b8b2..029cb1cb34 100644 --- a/repos/libports/recipes/pkg/test-spark_exception/hash +++ b/repos/libports/recipes/pkg/test-spark_exception/hash @@ -1 +1 @@ -2024-08-28 eff0e5679067aa3ffef960656d6b60fca51f715a +2024-12-10 02175a50adda2e689b55fdd11890d60b6841d2a3 diff --git a/repos/libports/recipes/pkg/test-spark_secondary_stack/hash b/repos/libports/recipes/pkg/test-spark_secondary_stack/hash index 27595ff18e..a0257f7030 100644 --- a/repos/libports/recipes/pkg/test-spark_secondary_stack/hash +++ b/repos/libports/recipes/pkg/test-spark_secondary_stack/hash @@ -1 +1 @@ -2024-08-28 045922085f23518bd50d625fc8ccd6812b982fae +2024-12-10 fd2594bc1226b6cbd3c6fac3538ba38c7f8a0c88 diff --git a/repos/libports/recipes/pkg/test-stdcxx/hash b/repos/libports/recipes/pkg/test-stdcxx/hash index 5046fda7b2..1cca32631d 100644 --- a/repos/libports/recipes/pkg/test-stdcxx/hash +++ b/repos/libports/recipes/pkg/test-stdcxx/hash @@ -1 +1 @@ -2024-08-28 38263ab7a5902d67f6d71800f94102b692b4fb26 +2024-12-10 2b9306803fe8a55f3c67f2091e3f4811805e065b diff --git a/repos/libports/recipes/pkg/test-tcp_bulk_lwip/hash b/repos/libports/recipes/pkg/test-tcp_bulk_lwip/hash index a82822416d..35b6a6fecd 100644 --- a/repos/libports/recipes/pkg/test-tcp_bulk_lwip/hash +++ b/repos/libports/recipes/pkg/test-tcp_bulk_lwip/hash @@ -1 +1 @@ -2024-08-28 a349b37e9cfbf9417a97158e36472f800e9f67d3 +2024-12-10 0f89c2441fc764052adebac1cfe1c8bdf50635da diff --git a/repos/libports/recipes/pkg/test-tcp_bulk_lxip/hash b/repos/libports/recipes/pkg/test-tcp_bulk_lxip/hash index 4a9aa11485..a0d8472f10 100644 --- a/repos/libports/recipes/pkg/test-tcp_bulk_lxip/hash +++ b/repos/libports/recipes/pkg/test-tcp_bulk_lxip/hash @@ -1 +1 @@ -2024-08-28 33b2b5af63001370de24d181be08bb46299a261e +2024-12-10 e38acbd4c96483f8e19a0bd6defb33dbd7389262 diff --git a/repos/libports/recipes/pkg/usb_webcam/archives b/repos/libports/recipes/pkg/usb_webcam/archives index 1b2091cf70..57eaa345ef 100644 --- a/repos/libports/recipes/pkg/usb_webcam/archives +++ b/repos/libports/recipes/pkg/usb_webcam/archives @@ -1,5 +1,4 @@ _/src/usb_webcam -_/raw/usb_webcam _/src/init _/src/jpeg _/src/libc diff --git a/repos/libports/recipes/pkg/usb_webcam/hash b/repos/libports/recipes/pkg/usb_webcam/hash index e3e09adb9b..bf037f8bee 100644 --- a/repos/libports/recipes/pkg/usb_webcam/hash +++ b/repos/libports/recipes/pkg/usb_webcam/hash @@ -1 +1 @@ -2024-08-28 de8ba1e0f36a99c560ce60d382ae4cc57f553094 +2024-12-10 8fb43b26ae9dcbd80356a53b1b11a9dbcc7947cf diff --git a/repos/libports/recipes/pkg/usb_webcam/runtime b/repos/libports/recipes/pkg/usb_webcam/runtime index aa1db16023..aaf9eae234 100644 --- a/repos/libports/recipes/pkg/usb_webcam/runtime +++ b/repos/libports/recipes/pkg/usb_webcam/runtime @@ -1,6 +1,6 @@ -<runtime binary="init" caps="800" ram="64M" config="usb_webcam.config"> +<runtime binary="init" caps="900" ram="64M"> <provides> <capture /> </provides> - <requires> <timer /> <usb /> <rm /> </requires> + <requires> <timer /> <usb /> </requires> <content> <rom label="ld.lib.so"/> <rom label="init"/> @@ -15,9 +15,120 @@ <rom label="libusb.lib.so"/> <rom label="libuvc.lib.so"/> <rom label="stdcxx.lib.so"/> - <rom label="usb_webcam.config"/> <rom label="nitpicker"/> <rom label="report_rom"/> <rom label="rom_filter"/> </content> + + <config> + <parent-provides> + <service name="ROM"/> + <service name="PD"/> + <service name="RM"/> + <service name="CPU"/> + <service name="LOG"/> + <service name="Timer"/> + <service name="Usb"/> + </parent-provides> + + <default caps="100"/> + + <service name="Capture"> <default-policy> <child name="nitpicker_camera"/> </default-policy> </service> + + <start name="nitpicker_camera" caps="150"> + <binary name="nitpicker"/> + <resource name="RAM" quantum="4M"/> + <provides> + <service name="Gui"/> <service name="Capture"/> + </provides> + <config request_framebuffer="no"> + <report panorama="yes"/> + <capture/> + <domain name="" layer="1" content="client" label="no" /> + <default-policy domain=""/> + </config> + <route> + <service name="Report"> <child name="report_rom"/> </service> + <any-service> <parent/> </any-service> + </route> + </start> + + <start name="report_rom"> + <binary name="report_rom"/> + <resource name="RAM" quantum="2M"/> + <provides> <service name="Report"/> <service name="ROM"/> </provides> + <config verbose="no"> + <policy label="webcam_config -> panorama" report="nitpicker_camera -> panorama"/> + </config> + <route> + <any-service> <parent /> </any-service> + </route> + </start> + + <start name="webcam_config"> + <binary name="rom_filter"/> + <resource name="RAM" quantum="1M"/> + <provides> <service name="ROM"/> </provides> + <config verbose="no"> + <input name="capture_width" rom="panorama" node="panorama" default=""> + <node type="capture"> + <attribute name="width"/> + </node> + </input> + + <output node="config"> + <if> <has_value input="capture_width" value=""/> + <then> </then> + <else> + <inline> + <parent-provides> + <service name="ROM"/> + <service name="PD"/> + <service name="RM"/> + <service name="CPU"/> + <service name="LOG"/> + <service name="Timer"/> + <service name="Gui"/> + <service name="Usb"/> + </parent-provides> + <start name="usb_webcam" caps="300"> + <resource name="RAM" quantum="52M"/> + <config ld_verbose="no" enabled="yes" width="640" height="480" format="yuv" fps="15"> + <vfs> + <dir name="dev"> + <log/> + <inline name="rtc">2018-01-01 00:01</inline> + <libusb/> + </dir> + <dir name="pipe"> <pipe/> </dir> + </vfs> + <libc stdout="/dev/log" stderr="/dev/log" rtc="/dev/rtc" pipe="/pipe"/> + <env key="LIBUSB_DEBUG" value="0"/> + </config> + <route> + <any-service> <parent/> </any-service> + </route> + </start> + </inline> + </else></if> + </output> + </config> + <route> + <service name="ROM" label="panorama"> <child name="report_rom"/> </service> + <any-service> <parent/> </any-service> + </route> + </start> + + <start name="webcam" caps="400"> + <binary name="init"/> + <resource name="RAM" quantum="54M"/> + <route> + <service name="ROM" label="config"> + <child name="webcam_config" label="config"/> + </service> + <service name="Gui"> <child name="nitpicker_camera"/> </service> + <any-service> <parent/> </any-service> + </route> + </start> + </config> </runtime> diff --git a/repos/libports/recipes/raw/qt6_dejavusans/content.mk b/repos/libports/recipes/raw/qt6_dejavusans/content.mk index 2570abca6b..38b861acf2 100644 --- a/repos/libports/recipes/raw/qt6_dejavusans/content.mk +++ b/repos/libports/recipes/raw/qt6_dejavusans/content.mk @@ -1,14 +1,14 @@ content: qt6_dejavusans.tar LICENSE -PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6) +PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6_base) qt/lib/fonts/DejaVuSans.ttf: mkdir -p $(dir $@) - cp $(PORT_DIR)/src/lib/qt6/qtbase/src/3rdparty/wasm/$(notdir $@) $@ + cp $(PORT_DIR)/src/lib/qt6_base/src/3rdparty/wasm/$(notdir $@) $@ qt6_dejavusans.tar: qt/lib/fonts/DejaVuSans.ttf tar --owner=0 --group=0 --numeric-owner --mode='go=' --mtime='1970-01-01 00:00+00' -cf $@ qt rm -rf qt LICENSE: - cp $(PORT_DIR)/src/lib/qt6/qtbase/src/3rdparty/wasm/DEJAVU-LICENSE $@ + cp $(PORT_DIR)/src/lib/qt6_base/src/3rdparty/wasm/DEJAVU-LICENSE $@ diff --git a/repos/libports/recipes/raw/qt6_samegame/content.mk b/repos/libports/recipes/raw/qt6_samegame/content.mk index 1aa147c3ff..126c22294d 100644 --- a/repos/libports/recipes/raw/qt6_samegame/content.mk +++ b/repos/libports/recipes/raw/qt6_samegame/content.mk @@ -1,6 +1,6 @@ content: qt6_samegame.tar -PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6) +PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6_declarative) SAMEGAME3_RESOURCES := samegame.qml \ Dialog.qml \ @@ -20,10 +20,10 @@ samegame/pics: mkdir -p $@ $(addprefix samegame/, $(SAMEGAME3_RESOURCES)): samegame - cp $(PORT_DIR)/src/lib/qt6/qtdeclarative/examples/quick/tutorials/samegame/samegame3/$(notdir $@) $@ + cp $(PORT_DIR)/src/lib/qt6_declarative/examples/quick/tutorials/samegame/samegame3/$(notdir $@) $@ $(addprefix samegame/pics/, $(SAMEGAME_RESOURCES)): samegame/pics - cp $(PORT_DIR)/src/lib/qt6/qtdeclarative/examples/quick/tutorials/samegame/samegame3/pics/$(notdir $@) $@ + cp $(PORT_DIR)/src/lib/qt6_declarative/examples/quick/tutorials/samegame/samegame3/pics/$(notdir $@) $@ qt6_samegame.tar: $(addprefix samegame/, $(SAMEGAME3_RESOURCES)) \ diff --git a/repos/libports/recipes/raw/usb_webcam/content.mk b/repos/libports/recipes/raw/usb_webcam/content.mk deleted file mode 100644 index 6c8427df24..0000000000 --- a/repos/libports/recipes/raw/usb_webcam/content.mk +++ /dev/null @@ -1,4 +0,0 @@ -content: usb_webcam.config - -usb_webcam.config: - cp $(REP_DIR)/recipes/raw/usb_webcam/$@ $@ diff --git a/repos/libports/recipes/raw/usb_webcam/hash b/repos/libports/recipes/raw/usb_webcam/hash deleted file mode 100644 index 0566bcfa41..0000000000 --- a/repos/libports/recipes/raw/usb_webcam/hash +++ /dev/null @@ -1 +0,0 @@ -2024-04-11 042763e6ad780ed62be632f90d4b6550836ffd14 diff --git a/repos/libports/recipes/raw/usb_webcam/usb_webcam.config b/repos/libports/recipes/raw/usb_webcam/usb_webcam.config deleted file mode 100644 index a1cba8a896..0000000000 --- a/repos/libports/recipes/raw/usb_webcam/usb_webcam.config +++ /dev/null @@ -1,114 +0,0 @@ -<config verbose="no"> - - <parent-provides> - <service name="ROM"/> - <service name="PD"/> - <service name="RM"/> - <service name="CPU"/> - <service name="LOG"/> - <service name="Timer"/> - <service name="Usb"/> - </parent-provides> - - <default caps="100"/> - - <service name="Capture"> <default-policy> <child name="nitpicker_camera"/> </default-policy> </service> - - <start name="nitpicker_camera" caps="150"> - <binary name="nitpicker"/> - <resource name="RAM" quantum="4M"/> - <provides> - <service name="Gui"/> <service name="Capture"/> - </provides> - <config request_framebuffer="no"> - <report displays="yes"/> - <capture/> - <domain name="" layer="1" content="client" label="no" /> - <default-policy domain=""/> - </config> - <route> - <service name="Report"> <child name="report_rom"/> </service> - <any-service> <parent/> </any-service> - </route> - </start> - - <start name="report_rom"> - <binary name="report_rom"/> - <resource name="RAM" quantum="2M"/> - <provides> <service name="Report"/> <service name="ROM"/> </provides> - <config verbose="no"> - <policy label="webcam_config -> displays" report="nitpicker_camera -> displays"/> - </config> - <route> - <any-service> <parent /> </any-service> - </route> - </start> - - <start name="webcam_config"> - <binary name="rom_filter"/> - <resource name="RAM" quantum="1M"/> - <provides> <service name="ROM"/> </provides> - <config verbose="no"> - <input name="capture_width" rom="displays" node="displays" default=""> - <node type="display"> - <attribute name="width"/> - </node> - </input> - - <output node="config"> - <if> <has_value input="capture_width" value=""/> - <then> </then> - <else> - <inline> - <parent-provides> - <service name="ROM"/> - <service name="PD"/> - <service name="RM"/> - <service name="CPU"/> - <service name="LOG"/> - <service name="Timer"/> - <service name="Gui"/> - <service name="Usb"/> - </parent-provides> - <default caps="128"/> - <start name="usb_webcam" caps="250"> - <resource name="RAM" quantum="52M"/> - <config ld_verbose="no" enabled="yes" width="640" height="480" format="yuv" fps="15"> - <vfs> - <dir name="dev"> - <log/> - <inline name="rtc">2018-01-01 00:01</inline> - <libusb/> - </dir> - <dir name="pipe"> <pipe/> </dir> - </vfs> - <libc stdout="/dev/log" stderr="/dev/log" rtc="/dev/rtc" pipe="/pipe"/> - <env key="LIBUSB_DEBUG" value="0"/> - </config> - <route> - <any-service> <parent/> </any-service> - </route> - </start> - </inline> - </else></if> - </output> - </config> - <route> - <service name="ROM" label="displays"> <child name="report_rom"/> </service> - <any-service> <parent/> </any-service> - </route> - </start> - - <start name="webcam" caps="350"> - <binary name="init"/> - <resource name="RAM" quantum="54M"/> - <route> - <service name="ROM" label="config"> - <child name="webcam_config" label="config"/> - </service> - <service name="Gui"> <child name="nitpicker_camera"/> </service> - <any-service> <parent/> </any-service> - </route> - </start> - -</config> diff --git a/repos/libports/recipes/src/acpi_event/hash b/repos/libports/recipes/src/acpi_event/hash index 6d8915f39c..b3820c5d8a 100644 --- a/repos/libports/recipes/src/acpi_event/hash +++ b/repos/libports/recipes/src/acpi_event/hash @@ -1 +1 @@ -2024-08-28 7e1b511ce667125e75aa285d18601ea9565b4088 +2024-12-10 e6f56eabf60ecc7ef3d270ea8e1b1e74797b3d23 diff --git a/repos/libports/recipes/src/acpica/hash b/repos/libports/recipes/src/acpica/hash index a663339a34..32c81104da 100644 --- a/repos/libports/recipes/src/acpica/hash +++ b/repos/libports/recipes/src/acpica/hash @@ -1 +1 @@ -2024-08-28 7ee24b094bbc91f887b71329162bc05402aacea6 +2024-12-10 7fdaf553f171d5af35643f456d09af93f4167e69 diff --git a/repos/libports/recipes/src/compat-libc/hash b/repos/libports/recipes/src/compat-libc/hash index 2474e72e96..3b92773039 100644 --- a/repos/libports/recipes/src/compat-libc/hash +++ b/repos/libports/recipes/src/compat-libc/hash @@ -1 +1 @@ -2024-08-28 ac4db2d2a8640919a3a1c78e5cd2b329d66c10ac +2024-10-07 7a13583a59e99b4c22d62cfeabe0f9ce6dba44b6 diff --git a/repos/libports/recipes/src/curl/hash b/repos/libports/recipes/src/curl/hash index 47cfe73fc1..14ed23a560 100644 --- a/repos/libports/recipes/src/curl/hash +++ b/repos/libports/recipes/src/curl/hash @@ -1 +1 @@ -2024-08-28 531347c4babd68aaf68a78266f4a6772b814a390 +2024-10-07 c868b84c7e02011e5471594876e593894ae9573f diff --git a/repos/libports/recipes/src/expat/hash b/repos/libports/recipes/src/expat/hash index 2fac86f6da..8fd584e272 100644 --- a/repos/libports/recipes/src/expat/hash +++ b/repos/libports/recipes/src/expat/hash @@ -1 +1 @@ -2024-08-28 3e8670688ad1d24eb2fc33fe09fe164175a76b56 +2024-10-07 6e42e25ca423dfbfb33f75ef51eb681037f77937 diff --git a/repos/libports/recipes/src/extract/hash b/repos/libports/recipes/src/extract/hash index 477042ce75..94b709fba1 100644 --- a/repos/libports/recipes/src/extract/hash +++ b/repos/libports/recipes/src/extract/hash @@ -1 +1 @@ -2024-08-28 f406428767771456b29a7516aa9880b285d961fd +2024-12-10 3f48f809682ca63a9134fdaf477e38f1e01e63d2 diff --git a/repos/libports/recipes/src/fetchurl/hash b/repos/libports/recipes/src/fetchurl/hash index 31527af50a..8c8e6c0459 100644 --- a/repos/libports/recipes/src/fetchurl/hash +++ b/repos/libports/recipes/src/fetchurl/hash @@ -1 +1 @@ -2024-08-28 38f70f9121762b50fb8e65094097ef11ffa20c91 +2024-12-10 c63c0c19329f58fe74658724b3f7d96bd7d68d02 diff --git a/repos/libports/recipes/src/ffi/hash b/repos/libports/recipes/src/ffi/hash index 51e805f089..11f1666b42 100644 --- a/repos/libports/recipes/src/ffi/hash +++ b/repos/libports/recipes/src/ffi/hash @@ -1 +1 @@ -2024-08-28 88605d93ba05e40bdd08b338a5d927d538b1a1c3 +2024-10-07 d29ca29db529036fe29c64d9cdc80d3bb754a7ae diff --git a/repos/libports/recipes/src/freetype/hash b/repos/libports/recipes/src/freetype/hash index c0f850d1b6..a12b33aa2b 100644 --- a/repos/libports/recipes/src/freetype/hash +++ b/repos/libports/recipes/src/freetype/hash @@ -1 +1 @@ -2024-08-28 e6bf913b0f700c6d8d67cf21662e977309f87d09 +2024-10-07 b71866cbe221054b27f1153038994c2acde19813 diff --git a/repos/libports/recipes/src/fs_utils/hash b/repos/libports/recipes/src/fs_utils/hash index a83cd4d93c..7c6c0f2eea 100644 --- a/repos/libports/recipes/src/fs_utils/hash +++ b/repos/libports/recipes/src/fs_utils/hash @@ -1 +1 @@ -2024-08-28 d3dc1ca871f93023bff9af92c7281b0e53cf79b7 +2024-10-07 534a3e3d2ceeb3a1360afcdd51ad41ced7957762 diff --git a/repos/libports/recipes/src/gcov/hash b/repos/libports/recipes/src/gcov/hash index 760c76402b..8bebaf78eb 100644 --- a/repos/libports/recipes/src/gcov/hash +++ b/repos/libports/recipes/src/gcov/hash @@ -1 +1 @@ -2024-08-28 c5424892a2de8c3627c5dbbd4273b5b55c40d362 +2024-12-10 6e0d7b500e9dc33615df4bc6df27ba0345bca9d1 diff --git a/repos/libports/recipes/src/gmp/hash b/repos/libports/recipes/src/gmp/hash index 35fcc1471e..1cb14b9463 100644 --- a/repos/libports/recipes/src/gmp/hash +++ b/repos/libports/recipes/src/gmp/hash @@ -1 +1 @@ -2024-08-28 30aee7134f40daa37af1412d01edf059e83cfb7a +2024-10-07 f0c7a473461c2c117744186b758ab5e06127017c diff --git a/repos/libports/recipes/src/jbig2dec/hash b/repos/libports/recipes/src/jbig2dec/hash index 2475ea0537..312364e9c2 100644 --- a/repos/libports/recipes/src/jbig2dec/hash +++ b/repos/libports/recipes/src/jbig2dec/hash @@ -1 +1 @@ -2024-08-28 301a9b75bdc32f13deb86695dec0b91dc3c495ed +2024-10-07 423e8f99ab035abe1dfa0a8fc41bdd845e27389e diff --git a/repos/libports/recipes/src/jpeg/hash b/repos/libports/recipes/src/jpeg/hash index 97c0ed36ac..11c97f3505 100644 --- a/repos/libports/recipes/src/jpeg/hash +++ b/repos/libports/recipes/src/jpeg/hash @@ -1 +1 @@ -2024-08-28 ded6125f239a12529ea412417cfbe7bd6e154cc6 +2024-10-07 35fe809179eeb0f0b1bfa6989475638d2f8ab97b diff --git a/repos/libports/recipes/src/libarchive/hash b/repos/libports/recipes/src/libarchive/hash index 9fa9ee5875..20b5136d2e 100644 --- a/repos/libports/recipes/src/libarchive/hash +++ b/repos/libports/recipes/src/libarchive/hash @@ -1 +1 @@ -2024-08-28 830abe72a027ae63fbae0e0d6b2ec21691e4a0cf +2024-10-07 c8111b67a5ec12c38d2d060e8410cc69407f8c6b diff --git a/repos/libports/recipes/src/libc/hash b/repos/libports/recipes/src/libc/hash index a051d4146f..ed4b55d9b6 100644 --- a/repos/libports/recipes/src/libc/hash +++ b/repos/libports/recipes/src/libc/hash @@ -1 +1 @@ -2024-08-28 55932a8f55d1976361d935c59267373cb13c9762 +2024-12-10 5d4785f66d6c46dcad3a8afde61e8071c1d0cd9e diff --git a/repos/libports/recipes/src/libdrm/hash b/repos/libports/recipes/src/libdrm/hash index a2b53f4174..56760279fe 100644 --- a/repos/libports/recipes/src/libdrm/hash +++ b/repos/libports/recipes/src/libdrm/hash @@ -1 +1 @@ -2024-08-28 ed7f2f4daa888ccd9f9f3315338272a3d90fab38 +2024-12-10 ed43bf54540fd8dbd58476c6795e7be26013c55a diff --git a/repos/libports/recipes/src/libiconv/hash b/repos/libports/recipes/src/libiconv/hash index 8f6b95b42b..3a6ae474ed 100644 --- a/repos/libports/recipes/src/libiconv/hash +++ b/repos/libports/recipes/src/libiconv/hash @@ -1 +1 @@ -2024-08-28 8c8ee799da0cccb3051771f7f15e39fa4f910233 +2024-10-07 029ae793f0b90e886f5f9b0e29de97cee38cc0b6 diff --git a/repos/libports/recipes/src/liblzma/hash b/repos/libports/recipes/src/liblzma/hash index e8fc6f803c..8cb1c6622d 100644 --- a/repos/libports/recipes/src/liblzma/hash +++ b/repos/libports/recipes/src/liblzma/hash @@ -1 +1 @@ -2024-08-28 76cf230175bae7a4ee00766e5ad98b676d970b3b +2024-10-07 8869476b02ff8c4a35ead717bc40b072c9219b29 diff --git a/repos/libports/recipes/src/libpng/hash b/repos/libports/recipes/src/libpng/hash index f8350b531c..f893c683ca 100644 --- a/repos/libports/recipes/src/libpng/hash +++ b/repos/libports/recipes/src/libpng/hash @@ -1 +1 @@ -2024-08-28 8954a7dbe623dd0f36f8bc2e983639dd5db015cb +2024-10-07 8bfa12a828825bbf3d03945b36cd02d9cba068ea diff --git a/repos/libports/recipes/src/libqgenodeviewwidget/hash b/repos/libports/recipes/src/libqgenodeviewwidget/hash index 151a6fe71b..dd21946ef2 100644 --- a/repos/libports/recipes/src/libqgenodeviewwidget/hash +++ b/repos/libports/recipes/src/libqgenodeviewwidget/hash @@ -1 +1 @@ -2024-08-28 6d003a0c416b52b05ded4c7ffd2921dcf6b383bd +2024-12-10 9dd3add8ad6462f845a137b49e3b98ee7bebd966 diff --git a/repos/libports/recipes/src/libssh/hash b/repos/libports/recipes/src/libssh/hash index 922fe07d81..29cc64c2d5 100644 --- a/repos/libports/recipes/src/libssh/hash +++ b/repos/libports/recipes/src/libssh/hash @@ -1 +1 @@ -2024-08-28 52cdc44f7ff8860ba4a2c5e933577e2d482f73ad +2024-10-07 b0fa4b50929766f9bba3d39247db4b6365d585c5 diff --git a/repos/libports/recipes/src/libusb/hash b/repos/libports/recipes/src/libusb/hash index 9b91a8abda..25afc99ee5 100644 --- a/repos/libports/recipes/src/libusb/hash +++ b/repos/libports/recipes/src/libusb/hash @@ -1 +1 @@ -2024-08-28 1f4e447434d3121b8fb6691f3005af61797cf332 +2024-12-10 f5924594785fae8f51e2af300808ed75dae9c6be diff --git a/repos/libports/recipes/src/libuvc/hash b/repos/libports/recipes/src/libuvc/hash index de2352c589..d8b4b94070 100644 --- a/repos/libports/recipes/src/libuvc/hash +++ b/repos/libports/recipes/src/libuvc/hash @@ -1 +1 @@ -2024-08-28 39d58419db5eb3724de1cd742cb1787eedcb652d +2024-10-07 53a7aa2da338109e7eff1740971b7a6f0d35b897 diff --git a/repos/libports/recipes/src/libyuv/hash b/repos/libports/recipes/src/libyuv/hash index f8907806f3..97f3f48e8d 100644 --- a/repos/libports/recipes/src/libyuv/hash +++ b/repos/libports/recipes/src/libyuv/hash @@ -1 +1 @@ -2024-08-28 5f8e804f74f836b7a1e9e257418f42416b80d814 +2024-12-10 17be5055cfcd976c5e89942ee96e9619f3ce7a37 diff --git a/repos/libports/recipes/src/mesa/hash b/repos/libports/recipes/src/mesa/hash index a239bc90e3..917bba2c1b 100644 --- a/repos/libports/recipes/src/mesa/hash +++ b/repos/libports/recipes/src/mesa/hash @@ -1 +1 @@ -2024-08-28 980fd81ee76888891f3a0b103be0541a1c2dc617 +2024-12-10 7203470430ebee6839548f1364de891b1a9036ff diff --git a/repos/libports/recipes/src/mesa_gears/hash b/repos/libports/recipes/src/mesa_gears/hash index 84143a1414..cbebb744c8 100644 --- a/repos/libports/recipes/src/mesa_gears/hash +++ b/repos/libports/recipes/src/mesa_gears/hash @@ -1 +1 @@ -2024-08-28 1a71604e56d25b64413eec8add614fce51e041f6 +2024-12-10 7f428e95e4b2c230e6b63c05d68fcf0aa8063424 diff --git a/repos/libports/recipes/src/mupdf/hash b/repos/libports/recipes/src/mupdf/hash index 8c4df95482..42043d50ef 100644 --- a/repos/libports/recipes/src/mupdf/hash +++ b/repos/libports/recipes/src/mupdf/hash @@ -1 +1 @@ -2024-08-28 59ac9cce57814450c9cd602dae31b24258183f41 +2024-10-07 2ceae7b51955b01b6411f021559c09bc240cd515 diff --git a/repos/libports/recipes/src/ncurses/hash b/repos/libports/recipes/src/ncurses/hash index a0bf37e2f8..e00763c077 100644 --- a/repos/libports/recipes/src/ncurses/hash +++ b/repos/libports/recipes/src/ncurses/hash @@ -1 +1 @@ -2024-08-28 3ad381419f006510519a6bf61fa20d3134988918 +2024-10-07 b5071cb4904f6302a3a6591c399cf96d668fc74c diff --git a/repos/libports/recipes/src/openjpeg/hash b/repos/libports/recipes/src/openjpeg/hash index 648098a28a..b71eadaa19 100644 --- a/repos/libports/recipes/src/openjpeg/hash +++ b/repos/libports/recipes/src/openjpeg/hash @@ -1 +1 @@ -2024-08-28 75bbd7ec35e57863ab731e5ab7d9a898d7768695 +2024-10-07 11ed245aeb65436ac9096c8ba10f7fd9860fd6c1 diff --git a/repos/libports/recipes/src/openssl/hash b/repos/libports/recipes/src/openssl/hash index 0f94b547d7..1cd73c5e33 100644 --- a/repos/libports/recipes/src/openssl/hash +++ b/repos/libports/recipes/src/openssl/hash @@ -1 +1 @@ -2024-08-28 c1f54d3e33d1be3ef2cd6193523de8536b48ef56 +2024-10-07 765a65aac2202d40fd12b9d54dc7d5b94aaede08 diff --git a/repos/libports/recipes/src/pcre/hash b/repos/libports/recipes/src/pcre/hash index b3aabeffcc..0847c499d9 100644 --- a/repos/libports/recipes/src/pcre/hash +++ b/repos/libports/recipes/src/pcre/hash @@ -1 +1 @@ -2024-08-28 c216336c492d36d2e6265faaf79518c6b5551a21 +2024-10-07 d6a3ba30419d57be5134cb704d845d87c4534acd diff --git a/repos/libports/recipes/src/pcsc-lite/hash b/repos/libports/recipes/src/pcsc-lite/hash index 2b2e9e0dd7..36d6826cf2 100644 --- a/repos/libports/recipes/src/pcsc-lite/hash +++ b/repos/libports/recipes/src/pcsc-lite/hash @@ -1 +1 @@ -2024-08-28 771e16362b305ac03b39687d3be496f5514f8878 +2024-12-10 f3cbd01bc297315f866d9fdf50566885f5ca806a diff --git a/repos/libports/recipes/src/pdf_view/hash b/repos/libports/recipes/src/pdf_view/hash index 6f244f7823..18c432b2e5 100644 --- a/repos/libports/recipes/src/pdf_view/hash +++ b/repos/libports/recipes/src/pdf_view/hash @@ -1 +1 @@ -2024-08-28 f8ce67b42b779dd951e810466273c51481fa58be +2024-12-10 715fac6080ac94af663e4902d59f802033857e2f diff --git a/repos/libports/recipes/src/posix/hash b/repos/libports/recipes/src/posix/hash index cf7a8ad417..425bd69e64 100644 --- a/repos/libports/recipes/src/posix/hash +++ b/repos/libports/recipes/src/posix/hash @@ -1 +1 @@ -2024-08-28 09ceef853d6bad4370ed36d17edca31302f34e35 +2024-12-10 5ddd70009c99b45f32b377e80df72c784af335d1 diff --git a/repos/libports/recipes/src/qt5_base/hash b/repos/libports/recipes/src/qt5_base/hash index b1d4daafeb..e5547a03e9 100644 --- a/repos/libports/recipes/src/qt5_base/hash +++ b/repos/libports/recipes/src/qt5_base/hash @@ -1 +1 @@ -2024-08-28 f2e9072e10dda467ffb8398fc73e4c03bb528697 +2024-12-10 fa9b38be15e280bd7ac87946b8a84f5dede858d0 diff --git a/repos/libports/recipes/src/qt5_calculatorform/hash b/repos/libports/recipes/src/qt5_calculatorform/hash index f1c37c889c..31ff1c9cb0 100644 --- a/repos/libports/recipes/src/qt5_calculatorform/hash +++ b/repos/libports/recipes/src/qt5_calculatorform/hash @@ -1 +1 @@ -2024-08-28 3cb0212b000276f539be1b6b729a47d5d73db537 +2024-10-29 b63ce371230fe653fa7a001fc15f21d50bcf0078 diff --git a/repos/libports/recipes/src/qt5_component/hash b/repos/libports/recipes/src/qt5_component/hash index 8d10c3174a..58d18b058f 100644 --- a/repos/libports/recipes/src/qt5_component/hash +++ b/repos/libports/recipes/src/qt5_component/hash @@ -1 +1 @@ -2024-08-28 ce189c35df3a9ca2ae59d092cd401e041ea1ba30 +2024-12-10 a0d9cfff80be3587966f6faf1081b6e56d72f0b1 diff --git a/repos/libports/recipes/src/qt5_declarative/hash b/repos/libports/recipes/src/qt5_declarative/hash index caac9972f9..91915a654a 100644 --- a/repos/libports/recipes/src/qt5_declarative/hash +++ b/repos/libports/recipes/src/qt5_declarative/hash @@ -1 +1 @@ -2024-08-28 a3037d3a3449c5644c471c925dbc288734c5f8a1 +2024-10-29 2ae88aef780d6b8d8c07fb20d27c8d0c01461b1b diff --git a/repos/libports/recipes/src/qt5_graphicaleffects/hash b/repos/libports/recipes/src/qt5_graphicaleffects/hash index 5e21a61a82..9747f3a2be 100644 --- a/repos/libports/recipes/src/qt5_graphicaleffects/hash +++ b/repos/libports/recipes/src/qt5_graphicaleffects/hash @@ -1 +1 @@ -2024-08-28 3b00021cd4d0a7ce04ecfc6ae74a3f195a94b820 +2024-10-29 51455c59fea72b23f47263cfe365b799653f4818 diff --git a/repos/libports/recipes/src/qt5_launchpad/hash b/repos/libports/recipes/src/qt5_launchpad/hash index 188fbc31c2..49212359d2 100644 --- a/repos/libports/recipes/src/qt5_launchpad/hash +++ b/repos/libports/recipes/src/qt5_launchpad/hash @@ -1 +1 @@ -2024-08-28 3523debd6a94ffe4d04d7a10ed4a7655e7cd7071 +2024-12-10 9d6569c5c17a1f45ee72e1e64efdef521145871d diff --git a/repos/libports/recipes/src/qt5_openglwindow/hash b/repos/libports/recipes/src/qt5_openglwindow/hash index 459c2a37d1..ab84cc04a5 100644 --- a/repos/libports/recipes/src/qt5_openglwindow/hash +++ b/repos/libports/recipes/src/qt5_openglwindow/hash @@ -1 +1 @@ -2024-08-28 47e86b9a1081f717c5a218387ca1cd9b79e4bb1d +2024-10-29 7eb0652c00f2591b0dd800b1f0cca5d5f4e1aad1 diff --git a/repos/libports/recipes/src/qt5_quickcontrols/hash b/repos/libports/recipes/src/qt5_quickcontrols/hash index c19167f9fd..aedaee5111 100644 --- a/repos/libports/recipes/src/qt5_quickcontrols/hash +++ b/repos/libports/recipes/src/qt5_quickcontrols/hash @@ -1 +1 @@ -2024-08-28 08b7f2cbde261a0aee461d6d1a3e0df1661b90e5 +2024-10-29 3050be32fe73381825ef7c72c31631e909863a1f diff --git a/repos/libports/recipes/src/qt5_quickcontrols2/hash b/repos/libports/recipes/src/qt5_quickcontrols2/hash index 1f72a0da32..cef03ce831 100644 --- a/repos/libports/recipes/src/qt5_quickcontrols2/hash +++ b/repos/libports/recipes/src/qt5_quickcontrols2/hash @@ -1 +1 @@ -2024-08-28 63884737aed335e1da22dcf2018dad5252a8adb7 +2024-12-10 8a2d7a83267d388a3662986a1151faaeb1caeed8 diff --git a/repos/libports/recipes/src/qt5_samegame/hash b/repos/libports/recipes/src/qt5_samegame/hash index d10ea67d8a..f74ecaafa3 100644 --- a/repos/libports/recipes/src/qt5_samegame/hash +++ b/repos/libports/recipes/src/qt5_samegame/hash @@ -1 +1 @@ -2024-08-28 245d816203ae87c369cde5026fb13119ae3e9104 +2024-10-29 7dbe41e8f254e2d705d5c42d01504cd77f3ee7eb diff --git a/repos/libports/recipes/src/qt5_svg/hash b/repos/libports/recipes/src/qt5_svg/hash index 46f9c8aaeb..2e01fffa78 100644 --- a/repos/libports/recipes/src/qt5_svg/hash +++ b/repos/libports/recipes/src/qt5_svg/hash @@ -1 +1 @@ -2024-08-28 2898b48fce322aea94510cb7a8cb91b12636baf4 +2024-12-10 fd5aaf291b283b39d2eaae0658766c8052300250 diff --git a/repos/libports/recipes/src/qt5_testqstring/hash b/repos/libports/recipes/src/qt5_testqstring/hash index 639ee0c344..79ccae9f65 100644 --- a/repos/libports/recipes/src/qt5_testqstring/hash +++ b/repos/libports/recipes/src/qt5_testqstring/hash @@ -1 +1 @@ -2024-08-28 6555f9ee8b84ee2942e3f9fee93fb18165717871 +2024-10-29 7efe449425336227e1b689eecbd724eff5c2f1d5 diff --git a/repos/libports/recipes/src/qt5_tetrix/hash b/repos/libports/recipes/src/qt5_tetrix/hash index 7c230eb61f..a58a02e7cb 100644 --- a/repos/libports/recipes/src/qt5_tetrix/hash +++ b/repos/libports/recipes/src/qt5_tetrix/hash @@ -1 +1 @@ -2024-08-28 92e6a7426b9c3a9ade1a40cf3c8549e32fc04fdd +2024-10-29 6393a4668fb5a3e1f7f370f7e158edecb2518c4d diff --git a/repos/libports/recipes/src/qt5_textedit/hash b/repos/libports/recipes/src/qt5_textedit/hash index 40dcad4d43..15d36b2d09 100644 --- a/repos/libports/recipes/src/qt5_textedit/hash +++ b/repos/libports/recipes/src/qt5_textedit/hash @@ -1 +1 @@ -2024-08-28 d15e17e5e99242e2f6e80345ecac9b2ba5392fde +2024-10-08 f86dfb339b9532c9a46ccc88de6618e526d160ed diff --git a/repos/libports/recipes/src/qt5_tooltips/hash b/repos/libports/recipes/src/qt5_tooltips/hash index dddf68810d..847f420fca 100644 --- a/repos/libports/recipes/src/qt5_tooltips/hash +++ b/repos/libports/recipes/src/qt5_tooltips/hash @@ -1 +1 @@ -2024-08-28 457f580bae3b063a41b4f44eea2a1d27c76c59e3 +2024-10-29 69b1f30f56eed5ca80a2abb5af621fd6a4be84cf diff --git a/repos/libports/recipes/src/qt5_virtualkeyboard/hash b/repos/libports/recipes/src/qt5_virtualkeyboard/hash index e7f68bc83d..211c48a044 100644 --- a/repos/libports/recipes/src/qt5_virtualkeyboard/hash +++ b/repos/libports/recipes/src/qt5_virtualkeyboard/hash @@ -1 +1 @@ -2024-08-28 c4aa72ca1779fdffba3388f1a2ec55dcebf88614 +2024-10-29 193938878855d20270284a04cc181ef4496192b8 diff --git a/repos/libports/recipes/src/qt5_virtualkeyboard_example/hash b/repos/libports/recipes/src/qt5_virtualkeyboard_example/hash index 1265725f99..0e5ff78229 100644 --- a/repos/libports/recipes/src/qt5_virtualkeyboard_example/hash +++ b/repos/libports/recipes/src/qt5_virtualkeyboard_example/hash @@ -1 +1 @@ -2024-08-28 4fe62c6ced9d01a3b4cf8613c7d3c639ff3967b2 +2024-10-29 a4ffa97a7458d6e6dfabb400803c4387c1343ca0 diff --git a/repos/libports/recipes/src/qt6_base/content.mk b/repos/libports/recipes/src/qt6_base/content.mk index e8383e1f2b..2ebea032cb 100644 --- a/repos/libports/recipes/src/qt6_base/content.mk +++ b/repos/libports/recipes/src/qt6_base/content.mk @@ -5,9 +5,9 @@ content: $(MIRROR_FROM_REP_DIR) $(MIRROR_FROM_REP_DIR): $(mirror_from_rep_dir) -PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6) +PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6_base) -MIRROR_FROM_PORT_DIR := src/lib/qt6/qtbase +MIRROR_FROM_PORT_DIR := src/lib/qt6_base content: $(MIRROR_FROM_PORT_DIR) @@ -26,4 +26,4 @@ $(MIRROR_FROM_OS): content: LICENSE LICENSE: - cp $(PORT_DIR)/src/lib/qt6/LICENSE.LGPL3 $@ + cp $(PORT_DIR)/src/lib/qt6_base/LICENSES/LGPL-3.0-only.txt $@ diff --git a/repos/libports/recipes/src/qt6_base/hash b/repos/libports/recipes/src/qt6_base/hash index a829588f3f..dbb54685e0 100644 --- a/repos/libports/recipes/src/qt6_base/hash +++ b/repos/libports/recipes/src/qt6_base/hash @@ -1 +1 @@ -2024-08-28 3be896bebae38e51e7fb7df8f5d748e2c94eec12 +2024-12-10 c8e8357175b1a7af9c295289015b0849a10db71b diff --git a/repos/libports/recipes/src/qt6_calculatorform/content.mk b/repos/libports/recipes/src/qt6_calculatorform/content.mk index 58558b9945..fa35478347 100644 --- a/repos/libports/recipes/src/qt6_calculatorform/content.mk +++ b/repos/libports/recipes/src/qt6_calculatorform/content.mk @@ -5,9 +5,9 @@ content: $(MIRROR_FROM_REP_DIR) LICENSE $(MIRROR_FROM_REP_DIR): $(mirror_from_rep_dir) -PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6) +PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6_tools) -MIRROR_FROM_PORT_DIR := src/lib/qt6/qttools/examples/designer/calculatorform +MIRROR_FROM_PORT_DIR := src/lib/qt6_tools/examples/designer/calculatorform content: $(MIRROR_FROM_PORT_DIR) @@ -16,5 +16,5 @@ $(MIRROR_FROM_PORT_DIR): cp -r $(PORT_DIR)/$@ $(dir $@) LICENSE: - cp $(PORT_DIR)/src/lib/qt6/LICENSE.GPL3 $@ + cp $(PORT_DIR)/src/lib/qt6_tools/LICENSES/GPL-3.0-only.txt $@ diff --git a/repos/libports/recipes/src/qt6_calculatorform/hash b/repos/libports/recipes/src/qt6_calculatorform/hash index ed03a9c3ee..86bb77348e 100644 --- a/repos/libports/recipes/src/qt6_calculatorform/hash +++ b/repos/libports/recipes/src/qt6_calculatorform/hash @@ -1 +1 @@ -2024-08-28 2a9936ed0289096620cb4ade0af398c86f92a261 +2024-10-29 11d7252273dbbd88b47d382b40cc682c149c271c diff --git a/repos/libports/recipes/src/qt6_component/hash b/repos/libports/recipes/src/qt6_component/hash index 4aaca56f5d..fd3a799716 100644 --- a/repos/libports/recipes/src/qt6_component/hash +++ b/repos/libports/recipes/src/qt6_component/hash @@ -1 +1 @@ -2024-08-28 9517fad583902de01449eb7add145e7c528f3a15 +2024-12-10 ed28dda01981301bd96d564518b52dce929a4850 diff --git a/repos/libports/recipes/src/qt6_declarative/content.mk b/repos/libports/recipes/src/qt6_declarative/content.mk index cd6776c727..2091a9dd99 100644 --- a/repos/libports/recipes/src/qt6_declarative/content.mk +++ b/repos/libports/recipes/src/qt6_declarative/content.mk @@ -5,9 +5,9 @@ content: $(MIRROR_FROM_REP_DIR) $(MIRROR_FROM_REP_DIR): $(mirror_from_rep_dir) -PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6) +PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6_declarative) -MIRROR_FROM_PORT_DIR := src/lib/qt6/qtdeclarative +MIRROR_FROM_PORT_DIR := src/lib/qt6_declarative content: $(MIRROR_FROM_PORT_DIR) @@ -18,4 +18,4 @@ $(MIRROR_FROM_PORT_DIR): content: LICENSE LICENSE: - cp $(PORT_DIR)/src/lib/qt6/LICENSE.LGPL3 $@ + cp $(PORT_DIR)/src/lib/qt6_declarative/LICENSES/LGPL-3.0-only.txt $@ diff --git a/repos/libports/recipes/src/qt6_declarative/hash b/repos/libports/recipes/src/qt6_declarative/hash index c7ddc16f1f..b876454c61 100644 --- a/repos/libports/recipes/src/qt6_declarative/hash +++ b/repos/libports/recipes/src/qt6_declarative/hash @@ -1 +1 @@ -2024-08-28 9b1968e946162b38ad76c2daf7d029be82587b33 +2024-10-29 158ad98027580136a097028cbe9f1b279848117f diff --git a/repos/libports/recipes/src/qt6_i18n_cmake/content.mk b/repos/libports/recipes/src/qt6_i18n_cmake/content.mk new file mode 100644 index 0000000000..94afa448c1 --- /dev/null +++ b/repos/libports/recipes/src/qt6_i18n_cmake/content.mk @@ -0,0 +1,19 @@ +MIRROR_FROM_REP_DIR := src/app/qt6/examples/i18n_cmake + +content: $(MIRROR_FROM_REP_DIR) LICENSE + +$(MIRROR_FROM_REP_DIR): + $(mirror_from_rep_dir) + +PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6_tools) + +MIRROR_FROM_PORT_DIR := src/lib/qt6_tools/examples/linguist/i18n + +content: $(MIRROR_FROM_PORT_DIR) + +$(MIRROR_FROM_PORT_DIR): + mkdir -p $(dir $@) + cp -r $(PORT_DIR)/$@ $(dir $@) + +LICENSE: + cp $(PORT_DIR)/src/lib/qt6_tools/LICENSES/GPL-3.0-only.txt $@ diff --git a/repos/libports/recipes/src/qt6_i18n_cmake/hash b/repos/libports/recipes/src/qt6_i18n_cmake/hash new file mode 100644 index 0000000000..e6918f992f --- /dev/null +++ b/repos/libports/recipes/src/qt6_i18n_cmake/hash @@ -0,0 +1 @@ +2025-01-15 a954ed52258bcb371fb38df7c1ce01df38d8844b diff --git a/repos/libports/recipes/src/qt6_i18n_cmake/used_apis b/repos/libports/recipes/src/qt6_i18n_cmake/used_apis new file mode 100644 index 0000000000..8d31aa5904 --- /dev/null +++ b/repos/libports/recipes/src/qt6_i18n_cmake/used_apis @@ -0,0 +1,5 @@ +libc +mesa +qt6_base +qt6_component +stdcxx diff --git a/repos/libports/recipes/src/qt6_i18n_qmake/content.mk b/repos/libports/recipes/src/qt6_i18n_qmake/content.mk new file mode 100644 index 0000000000..3d5ec05426 --- /dev/null +++ b/repos/libports/recipes/src/qt6_i18n_qmake/content.mk @@ -0,0 +1,19 @@ +MIRROR_FROM_REP_DIR := src/app/qt6/examples/i18n_qmake + +content: $(MIRROR_FROM_REP_DIR) LICENSE + +$(MIRROR_FROM_REP_DIR): + $(mirror_from_rep_dir) + +PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6_tools) + +MIRROR_FROM_PORT_DIR := src/lib/qt6_tools/examples/linguist/i18n + +content: $(MIRROR_FROM_PORT_DIR) + +$(MIRROR_FROM_PORT_DIR): + mkdir -p $(dir $@) + cp -r $(PORT_DIR)/$@ $(dir $@) + +LICENSE: + cp $(PORT_DIR)/src/lib/qt6_tools/LICENSES/GPL-3.0-only.txt $@ diff --git a/repos/libports/recipes/src/qt6_i18n_qmake/hash b/repos/libports/recipes/src/qt6_i18n_qmake/hash new file mode 100644 index 0000000000..e6918f992f --- /dev/null +++ b/repos/libports/recipes/src/qt6_i18n_qmake/hash @@ -0,0 +1 @@ +2025-01-15 a954ed52258bcb371fb38df7c1ce01df38d8844b diff --git a/repos/libports/recipes/src/qt6_i18n_qmake/used_apis b/repos/libports/recipes/src/qt6_i18n_qmake/used_apis new file mode 100644 index 0000000000..8d31aa5904 --- /dev/null +++ b/repos/libports/recipes/src/qt6_i18n_qmake/used_apis @@ -0,0 +1,5 @@ +libc +mesa +qt6_base +qt6_component +stdcxx diff --git a/repos/libports/recipes/src/qt6_launchpad/hash b/repos/libports/recipes/src/qt6_launchpad/hash index b69793af84..cfc3e52be8 100644 --- a/repos/libports/recipes/src/qt6_launchpad/hash +++ b/repos/libports/recipes/src/qt6_launchpad/hash @@ -1 +1 @@ -2024-08-28 8b63705142327db708d6a1bccedad8c682ad159a +2024-12-10 6cc4d0425059dfa62b58f6f91e540f074da5efe6 diff --git a/repos/libports/recipes/src/qt6_openglwindow/content.mk b/repos/libports/recipes/src/qt6_openglwindow/content.mk index 36bdfa04b4..3d30bd8777 100644 --- a/repos/libports/recipes/src/qt6_openglwindow/content.mk +++ b/repos/libports/recipes/src/qt6_openglwindow/content.mk @@ -5,9 +5,9 @@ content: $(MIRROR_FROM_REP_DIR) LICENSE $(MIRROR_FROM_REP_DIR): $(mirror_from_rep_dir) -PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6) +PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6_base) -MIRROR_FROM_PORT_DIR := src/lib/qt6/qtbase/examples/opengl/openglwindow +MIRROR_FROM_PORT_DIR := src/lib/qt6_base/examples/opengl/openglwindow content: $(MIRROR_FROM_PORT_DIR) @@ -16,5 +16,5 @@ $(MIRROR_FROM_PORT_DIR): cp -r $(PORT_DIR)/$@ $(dir $@) LICENSE: - cp $(PORT_DIR)/src/lib/qt6/LICENSE.GPL3 $@ + cp $(PORT_DIR)/src/lib/qt6_base/LICENSES/GPL-3.0-only.txt $@ diff --git a/repos/libports/recipes/src/qt6_openglwindow/hash b/repos/libports/recipes/src/qt6_openglwindow/hash index 34f1a49d8d..c5cd6e9b36 100644 --- a/repos/libports/recipes/src/qt6_openglwindow/hash +++ b/repos/libports/recipes/src/qt6_openglwindow/hash @@ -1 +1 @@ -2024-08-28 d8c59ad02ae7a00401943527b8e29505ea1f510a +2024-10-29 fcb0260a9c2bc904ded4e5d14ff7d4b6c3996bb1 diff --git a/repos/libports/recipes/src/qt6_samegame/hash b/repos/libports/recipes/src/qt6_samegame/hash index 9087b0bcf4..5484492d2d 100644 --- a/repos/libports/recipes/src/qt6_samegame/hash +++ b/repos/libports/recipes/src/qt6_samegame/hash @@ -1 +1 @@ -2024-08-28 e87b8822dcadc2fa0883b514004123b98a8635dc +2024-10-29 98f8f07b282a346375d85c050189688671e91a32 diff --git a/repos/libports/recipes/src/qt6_shadertools/content.mk b/repos/libports/recipes/src/qt6_shadertools/content.mk index 7b5efaad0f..2b8663b089 100644 --- a/repos/libports/recipes/src/qt6_shadertools/content.mk +++ b/repos/libports/recipes/src/qt6_shadertools/content.mk @@ -5,9 +5,9 @@ content: $(MIRROR_FROM_REP_DIR) $(MIRROR_FROM_REP_DIR): $(mirror_from_rep_dir) -PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6) +PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6_shadertools) -MIRROR_FROM_PORT_DIR := src/lib/qt6/qtshadertools +MIRROR_FROM_PORT_DIR := src/lib/qt6_shadertools content: $(MIRROR_FROM_PORT_DIR) @@ -18,4 +18,4 @@ $(MIRROR_FROM_PORT_DIR): content: LICENSE LICENSE: - cp $(PORT_DIR)/src/lib/qt6/LICENSE.LGPL3 $@ + cp $(PORT_DIR)/src/lib/qt6_shadertools/LICENSES/LGPL-3.0-only.txt $@ diff --git a/repos/libports/recipes/src/qt6_shadertools/hash b/repos/libports/recipes/src/qt6_shadertools/hash index 7a69316d12..eda34d01c0 100644 --- a/repos/libports/recipes/src/qt6_shadertools/hash +++ b/repos/libports/recipes/src/qt6_shadertools/hash @@ -1 +1 @@ -2024-08-28 e98e7e2011e1e979fd5819fcf7f7b80d4930bbc2 +2024-10-29 9c021e249534e1678973424a3d588fd46161e396 diff --git a/repos/libports/recipes/src/qt6_svg/content.mk b/repos/libports/recipes/src/qt6_svg/content.mk index 999fabd87c..c1c9a0b520 100644 --- a/repos/libports/recipes/src/qt6_svg/content.mk +++ b/repos/libports/recipes/src/qt6_svg/content.mk @@ -5,9 +5,9 @@ content: $(MIRROR_FROM_REP_DIR) $(MIRROR_FROM_REP_DIR): $(mirror_from_rep_dir) -PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6) +PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6_svg) -MIRROR_FROM_PORT_DIR := src/lib/qt6/qtsvg +MIRROR_FROM_PORT_DIR := src/lib/qt6_svg content: $(MIRROR_FROM_PORT_DIR) @@ -18,4 +18,4 @@ $(MIRROR_FROM_PORT_DIR): content: LICENSE LICENSE: - cp $(PORT_DIR)/src/lib/qt6/LICENSE.LGPL3 $@ + cp $(PORT_DIR)/src/lib/qt6_svg/LICENSES/LGPL-3.0-only.txt $@ diff --git a/repos/libports/recipes/src/qt6_svg/hash b/repos/libports/recipes/src/qt6_svg/hash index 3359d21ee2..d8d3bba729 100644 --- a/repos/libports/recipes/src/qt6_svg/hash +++ b/repos/libports/recipes/src/qt6_svg/hash @@ -1 +1 @@ -2024-08-28 45e357c46696dc2ec3388afc48b4677ef4366bfa +2024-10-29 4bf29963a4548bdebe03e1d5460de5cfa8a9d295 diff --git a/repos/libports/recipes/src/qt6_testqstring/content.mk b/repos/libports/recipes/src/qt6_testqstring/content.mk index 523366684d..54d86421ba 100644 --- a/repos/libports/recipes/src/qt6_testqstring/content.mk +++ b/repos/libports/recipes/src/qt6_testqstring/content.mk @@ -5,9 +5,9 @@ content: $(MIRROR_FROM_REP_DIR) LICENSE $(MIRROR_FROM_REP_DIR): $(mirror_from_rep_dir) -PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6) +PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6_base) -MIRROR_FROM_PORT_DIR := src/lib/qt6/qtbase/examples/qtestlib/tutorial1 +MIRROR_FROM_PORT_DIR := src/lib/qt6_base/examples/qtestlib/tutorial1 content: $(MIRROR_FROM_PORT_DIR) @@ -16,5 +16,5 @@ $(MIRROR_FROM_PORT_DIR): cp -r $(PORT_DIR)/$@ $(dir $@) LICENSE: - cp $(PORT_DIR)/src/lib/qt6/LICENSE.GPL3 $@ + cp $(PORT_DIR)/src/lib/qt6_base/LICENSES/GPL-3.0-only.txt $@ diff --git a/repos/libports/recipes/src/qt6_testqstring/hash b/repos/libports/recipes/src/qt6_testqstring/hash index 929ea87cba..6e14b38de4 100644 --- a/repos/libports/recipes/src/qt6_testqstring/hash +++ b/repos/libports/recipes/src/qt6_testqstring/hash @@ -1 +1 @@ -2024-08-28 561246d5cd69b8691a41a9eb818e549c3d5a5c01 +2024-10-29 61ff70fdb603b68d553c3bb9d92fbe8170413a85 diff --git a/repos/libports/recipes/src/qt6_tetrix/content.mk b/repos/libports/recipes/src/qt6_tetrix/content.mk index 71a175a68e..7bcfbea163 100644 --- a/repos/libports/recipes/src/qt6_tetrix/content.mk +++ b/repos/libports/recipes/src/qt6_tetrix/content.mk @@ -5,9 +5,9 @@ content: $(MIRROR_FROM_REP_DIR) LICENSE $(MIRROR_FROM_REP_DIR): $(mirror_from_rep_dir) -PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6) +PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6_base) -MIRROR_FROM_PORT_DIR := src/lib/qt6/qtbase/tests/manual/examples/widgets/widgets/tetrix +MIRROR_FROM_PORT_DIR := src/lib/qt6_base/tests/manual/examples/widgets/widgets/tetrix content: $(MIRROR_FROM_PORT_DIR) @@ -16,4 +16,4 @@ $(MIRROR_FROM_PORT_DIR): cp -r $(PORT_DIR)/$@ $(dir $@) LICENSE: - cp $(PORT_DIR)/src/lib/qt6/LICENSE.GPL3 $@ + cp $(PORT_DIR)/src/lib/qt6_base/LICENSES/GPL-3.0-only.txt $@ diff --git a/repos/libports/recipes/src/qt6_tetrix/hash b/repos/libports/recipes/src/qt6_tetrix/hash index c7dd10e14c..35c576449f 100644 --- a/repos/libports/recipes/src/qt6_tetrix/hash +++ b/repos/libports/recipes/src/qt6_tetrix/hash @@ -1 +1 @@ -2024-08-28 9bcac492dc4f5cfc0345a8d47b9d2005c51eee70 +2024-10-29 ac4ae126f0c6c08680f639837e00d6494effa6b1 diff --git a/repos/libports/recipes/src/qt6_textedit/content.mk b/repos/libports/recipes/src/qt6_textedit/content.mk index e94a734523..cabd380c8e 100644 --- a/repos/libports/recipes/src/qt6_textedit/content.mk +++ b/repos/libports/recipes/src/qt6_textedit/content.mk @@ -5,9 +5,9 @@ content: $(MIRROR_FROM_REP_DIR) LICENSE $(MIRROR_FROM_REP_DIR): $(mirror_from_rep_dir) -PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6) +PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6_base) -MIRROR_FROM_PORT_DIR := src/lib/qt6/qtbase/tests/manual/examples/widgets/richtext/textedit +MIRROR_FROM_PORT_DIR := src/lib/qt6_base/tests/manual/examples/widgets/richtext/textedit content: $(MIRROR_FROM_PORT_DIR) @@ -16,5 +16,5 @@ $(MIRROR_FROM_PORT_DIR): cp -r $(PORT_DIR)/$@ $(dir $@) LICENSE: - cp $(PORT_DIR)/src/lib/qt6/LICENSE.GPL3 $@ + cp $(PORT_DIR)/src/lib/qt6_base/LICENSES/GPL-3.0-only.txt $@ diff --git a/repos/libports/recipes/src/qt6_textedit/hash b/repos/libports/recipes/src/qt6_textedit/hash index a92193c8d4..46df5cc1cc 100644 --- a/repos/libports/recipes/src/qt6_textedit/hash +++ b/repos/libports/recipes/src/qt6_textedit/hash @@ -1 +1 @@ -2024-08-28 9378e8bbed51f267817e3ca711e7cd9aedccd009 +2024-10-29 4d1e5c1c5ddb554668b84168265c2e43356676ab diff --git a/repos/libports/recipes/src/sanitizer/hash b/repos/libports/recipes/src/sanitizer/hash index 254d7c4d17..8a7951157d 100644 --- a/repos/libports/recipes/src/sanitizer/hash +++ b/repos/libports/recipes/src/sanitizer/hash @@ -1 +1 @@ -2024-08-28 e9e915021361f201538bc5d79fc6b80724d8b3a2 +2024-12-10 619bc7064c88412edb23f8587304c699f81dd169 diff --git a/repos/libports/recipes/src/sntp_client/hash b/repos/libports/recipes/src/sntp_client/hash index 6b53659f09..91f77aa845 100644 --- a/repos/libports/recipes/src/sntp_client/hash +++ b/repos/libports/recipes/src/sntp_client/hash @@ -1 +1 @@ -2024-08-28 c7e8afbe657f6965c941f78e954c2c925d6b8473 +2024-12-10 ff89189cce3873c87db1528cf17c53e261497688 diff --git a/repos/libports/recipes/src/spark/hash b/repos/libports/recipes/src/spark/hash index 92d7aaadfb..e74df04977 100644 --- a/repos/libports/recipes/src/spark/hash +++ b/repos/libports/recipes/src/spark/hash @@ -1 +1 @@ -2024-08-28 8d353d12452bbfced681db40b0a6196decc0ddea +2024-12-10 7f51d25b9b9a1d220a3df506a4cf3152f4bcb81b diff --git a/repos/libports/recipes/src/stdcxx/hash b/repos/libports/recipes/src/stdcxx/hash index 039067e160..2693a5b727 100644 --- a/repos/libports/recipes/src/stdcxx/hash +++ b/repos/libports/recipes/src/stdcxx/hash @@ -1 +1 @@ -2024-08-28 8d5731b1a5a6ddb256a2220969507b42f15f1b00 +2024-10-07 46226d58601558a46f1d58536f17729cfab63f2a diff --git a/repos/libports/recipes/src/stdin2out/hash b/repos/libports/recipes/src/stdin2out/hash index bb9e94b8a6..1ec2c36d82 100644 --- a/repos/libports/recipes/src/stdin2out/hash +++ b/repos/libports/recipes/src/stdin2out/hash @@ -1 +1 @@ -2024-08-28 a5c319bf73cb3b64b55a1fbc41b18aa06ba3767e +2024-10-07 932abf85634fdce9e09f710134df9d737ad9325c diff --git a/repos/libports/recipes/src/system_rtc/hash b/repos/libports/recipes/src/system_rtc/hash index 24837fb616..efee823178 100644 --- a/repos/libports/recipes/src/system_rtc/hash +++ b/repos/libports/recipes/src/system_rtc/hash @@ -1 +1 @@ -2024-08-28 0da33fc21f63b90043ef541d88244d1f22d16fb9 +2024-12-10 28fd93ca450980a59d4b01cdc911c58dadb1795f diff --git a/repos/libports/recipes/src/test-expat/hash b/repos/libports/recipes/src/test-expat/hash index 31f78b3e08..f456c26fb8 100644 --- a/repos/libports/recipes/src/test-expat/hash +++ b/repos/libports/recipes/src/test-expat/hash @@ -1 +1 @@ -2024-08-28 3219f82afe78a4af9e257db0f2e3b78d0f5a3d4d +2024-10-07 83ff28285252bbe3774df491d56978848f8aa228 diff --git a/repos/libports/recipes/src/test-ldso/hash b/repos/libports/recipes/src/test-ldso/hash index c4fd6ad57d..de075fd747 100644 --- a/repos/libports/recipes/src/test-ldso/hash +++ b/repos/libports/recipes/src/test-ldso/hash @@ -1 +1 @@ -2024-08-28 6d00f0f00f2ee77a25c55a904a31612023e255c9 +2024-12-10 d12ad1e939b257d5700ddb62fccc470e35536ea2 diff --git a/repos/libports/recipes/src/test-libc/hash b/repos/libports/recipes/src/test-libc/hash index 9f0ac6856d..1b7e69efcc 100644 --- a/repos/libports/recipes/src/test-libc/hash +++ b/repos/libports/recipes/src/test-libc/hash @@ -1 +1 @@ -2024-08-28 37b9a30f9a5947013e1403620d1bf6c6b5f9b215 +2024-10-07 e45926149c319d2c116581c1891f726e5f70fa71 diff --git a/repos/libports/recipes/src/test-libc_alarm/content.mk b/repos/libports/recipes/src/test-libc_alarm/content.mk new file mode 100644 index 0000000000..7a6c4ee906 --- /dev/null +++ b/repos/libports/recipes/src/test-libc_alarm/content.mk @@ -0,0 +1,2 @@ +SRC_DIR := src/test/libc_alarm +include $(GENODE_DIR)/repos/base/recipes/src/content.inc diff --git a/repos/libports/recipes/src/test-libc_alarm/hash b/repos/libports/recipes/src/test-libc_alarm/hash new file mode 100644 index 0000000000..8e220addba --- /dev/null +++ b/repos/libports/recipes/src/test-libc_alarm/hash @@ -0,0 +1 @@ +2024-10-07 b201decd115dad41908d5141d0b96d4f043c0773 diff --git a/repos/libports/recipes/src/test-libc_alarm/used_apis b/repos/libports/recipes/src/test-libc_alarm/used_apis new file mode 100644 index 0000000000..0c483273a8 --- /dev/null +++ b/repos/libports/recipes/src/test-libc_alarm/used_apis @@ -0,0 +1,2 @@ +libc +posix diff --git a/repos/libports/recipes/src/test-libc_connect/hash b/repos/libports/recipes/src/test-libc_connect/hash index 805eef815c..311a24da6b 100644 --- a/repos/libports/recipes/src/test-libc_connect/hash +++ b/repos/libports/recipes/src/test-libc_connect/hash @@ -1 +1 @@ -2024-08-28 d51cfa933a25c73534e8b8626c90e973aa898e50 +2024-10-07 c548d9a82d3ee0bdd029611810e3170512cc9942 diff --git a/repos/libports/recipes/src/test-libc_counter/hash b/repos/libports/recipes/src/test-libc_counter/hash index 834ee0e500..bd7acf08ec 100644 --- a/repos/libports/recipes/src/test-libc_counter/hash +++ b/repos/libports/recipes/src/test-libc_counter/hash @@ -1 +1 @@ -2024-08-28 1fff853bb417793299613c096e7e094570f18034 +2024-10-07 cd07c7ff14217dbcaf32d143cb4f1cbc78fe26c6 diff --git a/repos/libports/recipes/src/test-libc_deferred_unlink/hash b/repos/libports/recipes/src/test-libc_deferred_unlink/hash index f225da861d..549b126bde 100644 --- a/repos/libports/recipes/src/test-libc_deferred_unlink/hash +++ b/repos/libports/recipes/src/test-libc_deferred_unlink/hash @@ -1 +1 @@ -2024-08-28 6b594fb196de81a4b931541d1291539dda1f9df9 +2024-10-07 bff421de28692d4f156c8750f1ae81a3f99be6ba diff --git a/repos/libports/recipes/src/test-libc_execve/hash b/repos/libports/recipes/src/test-libc_execve/hash index 49aa8a9e13..8f8fbc0bc6 100644 --- a/repos/libports/recipes/src/test-libc_execve/hash +++ b/repos/libports/recipes/src/test-libc_execve/hash @@ -1 +1 @@ -2024-08-28 602122954be26a9012f020add6a61cf341294153 +2024-10-07 ae596c3763cf4817987b2886dee19eeceaf7acd1 diff --git a/repos/libports/recipes/src/test-libc_fifo_pipe/hash b/repos/libports/recipes/src/test-libc_fifo_pipe/hash index 136b0969a6..8884e418a0 100644 --- a/repos/libports/recipes/src/test-libc_fifo_pipe/hash +++ b/repos/libports/recipes/src/test-libc_fifo_pipe/hash @@ -1 +1 @@ -2024-08-28 93a752c4eb40a39262df598a43cedd72de8af7fc +2024-12-10 94844befa19cb9770bfec93be7c02b0271ff34ed diff --git a/repos/libports/recipes/src/test-libc_fork/hash b/repos/libports/recipes/src/test-libc_fork/hash index 40331521d3..601dc65a81 100644 --- a/repos/libports/recipes/src/test-libc_fork/hash +++ b/repos/libports/recipes/src/test-libc_fork/hash @@ -1 +1 @@ -2024-08-28 d9acdc150e8d4d5af47e0e8af72fc7c26a3e802e +2024-10-07 328a83ac2b7ca0ff851a9fda4cd3ebfd278b31fd diff --git a/repos/libports/recipes/src/test-libc_getenv/hash b/repos/libports/recipes/src/test-libc_getenv/hash index d63129c844..8f851c777c 100644 --- a/repos/libports/recipes/src/test-libc_getenv/hash +++ b/repos/libports/recipes/src/test-libc_getenv/hash @@ -1 +1 @@ -2024-08-28 bb880d061f08582b1cbafc61733393f0819b0dce +2024-10-07 6a8be8b83fe469f5651f555f13ac7c72910f0d8a diff --git a/repos/libports/recipes/src/test-libc_kqueue/content.mk b/repos/libports/recipes/src/test-libc_kqueue/content.mk new file mode 100644 index 0000000000..8fcda74a85 --- /dev/null +++ b/repos/libports/recipes/src/test-libc_kqueue/content.mk @@ -0,0 +1,2 @@ +SRC_DIR := src/test/libc_kqueue +include $(GENODE_DIR)/repos/base/recipes/src/content.inc diff --git a/repos/libports/recipes/src/test-libc_kqueue/hash b/repos/libports/recipes/src/test-libc_kqueue/hash new file mode 100644 index 0000000000..742b0f64d4 --- /dev/null +++ b/repos/libports/recipes/src/test-libc_kqueue/hash @@ -0,0 +1 @@ +2024-10-07 0ca19f64e8a503dbd0c2161001694d3494b03e09 diff --git a/repos/libports/recipes/src/test-libc_kqueue/used_apis b/repos/libports/recipes/src/test-libc_kqueue/used_apis new file mode 100644 index 0000000000..0c483273a8 --- /dev/null +++ b/repos/libports/recipes/src/test-libc_kqueue/used_apis @@ -0,0 +1,2 @@ +libc +posix diff --git a/repos/libports/recipes/src/test-libc_pipe/hash b/repos/libports/recipes/src/test-libc_pipe/hash index 38a5ccdd1f..78a541d5d2 100644 --- a/repos/libports/recipes/src/test-libc_pipe/hash +++ b/repos/libports/recipes/src/test-libc_pipe/hash @@ -1 +1 @@ -2024-08-28 0f22c978023497292a10934052747b15c75a6263 +2024-10-07 c18775f774b4385ee73949342d1231c46f87cfdb diff --git a/repos/libports/recipes/src/test-libc_vfs/hash b/repos/libports/recipes/src/test-libc_vfs/hash index 98f70ed20d..aa0a1c2c98 100644 --- a/repos/libports/recipes/src/test-libc_vfs/hash +++ b/repos/libports/recipes/src/test-libc_vfs/hash @@ -1 +1 @@ -2024-08-28 93209476f2569b7a77c82d81aafd99d59675d22f +2024-12-10 99bcdc6e0c3f56d927586b57d1be1892aae9efb4 diff --git a/repos/libports/recipes/src/test-libc_vfs_block/hash b/repos/libports/recipes/src/test-libc_vfs_block/hash index 0e29b33c98..b6c22a7142 100644 --- a/repos/libports/recipes/src/test-libc_vfs_block/hash +++ b/repos/libports/recipes/src/test-libc_vfs_block/hash @@ -1 +1 @@ -2024-08-28 0afcdc23ec3686d4c51360c33ba218f0d0fa1894 +2024-12-10 e8443971af9d114abf3d770db59f185feb564d93 diff --git a/repos/libports/recipes/src/test-libc_vfs_oss/hash b/repos/libports/recipes/src/test-libc_vfs_oss/hash index acecbfe856..c9a034d899 100644 --- a/repos/libports/recipes/src/test-libc_vfs_oss/hash +++ b/repos/libports/recipes/src/test-libc_vfs_oss/hash @@ -1 +1 @@ -2024-08-28 36a9e08636a3d9526bcff4a121bbd51d4300d860 +2024-10-07 c0e01c11b02d101074a4045758eacac152351106 diff --git a/repos/libports/recipes/src/test-netty/hash b/repos/libports/recipes/src/test-netty/hash index 7f41c530ab..b69afef505 100644 --- a/repos/libports/recipes/src/test-netty/hash +++ b/repos/libports/recipes/src/test-netty/hash @@ -1 +1 @@ -2024-08-28 8841096d77f101d480719445c1d7dbd4c36fb34f +2024-12-10 d4b13b1aecd897aa42ae600620e47706c4d7cc02 diff --git a/repos/libports/recipes/src/test-pipe_read_ready/hash b/repos/libports/recipes/src/test-pipe_read_ready/hash index 4327b487f3..781820906c 100644 --- a/repos/libports/recipes/src/test-pipe_read_ready/hash +++ b/repos/libports/recipes/src/test-pipe_read_ready/hash @@ -1 +1 @@ -2024-08-28 c813c7fa864963d61a1f2c232bec466c42c1d60e +2024-10-07 ce434b2161931420eb66f72af0167e805b56679c diff --git a/repos/libports/recipes/src/test-pthread/hash b/repos/libports/recipes/src/test-pthread/hash index 744372ca9c..63bbf6589f 100644 --- a/repos/libports/recipes/src/test-pthread/hash +++ b/repos/libports/recipes/src/test-pthread/hash @@ -1 +1 @@ -2024-08-28 41e0b42e078068abba71f0d3ee4f71a0ea78634f +2024-12-10 01ddf263611b06efd62b12d0d60d32c825b3f465 diff --git a/repos/libports/recipes/src/test-qt6_core/hash b/repos/libports/recipes/src/test-qt6_core/hash index d6dfc0e5c8..bc2e99d061 100644 --- a/repos/libports/recipes/src/test-qt6_core/hash +++ b/repos/libports/recipes/src/test-qt6_core/hash @@ -1 +1 @@ -2024-08-28 85800112501dcda7392b8f56879433615b1cf77f +2024-10-29 8b17045ceb3329dba427d4b6f4ec093ddc4958a0 diff --git a/repos/libports/recipes/src/test-qt6_core_cmake/hash b/repos/libports/recipes/src/test-qt6_core_cmake/hash index 13fb091b06..26ec4064a6 100644 --- a/repos/libports/recipes/src/test-qt6_core_cmake/hash +++ b/repos/libports/recipes/src/test-qt6_core_cmake/hash @@ -1 +1 @@ -2024-08-28 c1f6148ab6f1ce8988647d3b2e1262f93286af15 +2024-10-29 0fefe06c18f6ed8b1b1bf733ac64fc6a9df8381e diff --git a/repos/libports/recipes/src/test-qt6_quick/hash b/repos/libports/recipes/src/test-qt6_quick/hash index eb99303c7d..969b5dc8d1 100644 --- a/repos/libports/recipes/src/test-qt6_quick/hash +++ b/repos/libports/recipes/src/test-qt6_quick/hash @@ -1 +1 @@ -2024-08-28 165f99d428b45639421aeb497314968ed6eb06a0 +2024-10-29 4a75632c210cfc4d49ea73f01b70c1450fd64544 diff --git a/repos/libports/recipes/src/test-qt_core/hash b/repos/libports/recipes/src/test-qt_core/hash index 4c077ba41e..2acbed7d0c 100644 --- a/repos/libports/recipes/src/test-qt_core/hash +++ b/repos/libports/recipes/src/test-qt_core/hash @@ -1 +1 @@ -2024-08-28 332930a41be535701acb76f68359b08e818996f5 +2024-10-29 7a6a496c8d994500aaa45a66846f54411518404b diff --git a/repos/libports/recipes/src/test-qt_core_cmake/hash b/repos/libports/recipes/src/test-qt_core_cmake/hash index 02c4823461..d0b2c099a8 100644 --- a/repos/libports/recipes/src/test-qt_core_cmake/hash +++ b/repos/libports/recipes/src/test-qt_core_cmake/hash @@ -1 +1 @@ -2024-08-28 cd7db522526ea50116d7d429d27910621d92025d +2024-10-29 163f6e7b0ff93dff10e90f7181c8b8b43a05bd07 diff --git a/repos/libports/recipes/src/test-qt_quick/hash b/repos/libports/recipes/src/test-qt_quick/hash index d6118c65eb..dbd71f0302 100644 --- a/repos/libports/recipes/src/test-qt_quick/hash +++ b/repos/libports/recipes/src/test-qt_quick/hash @@ -1 +1 @@ -2024-08-28 c69777fa3176382fbebfda827a2286cdba9fea4c +2024-10-29 ee0652f9f7acc5b8c5481f02c19523ad03b54238 diff --git a/repos/libports/recipes/src/test-spark/hash b/repos/libports/recipes/src/test-spark/hash index 2ca869c6e3..845b82db6f 100644 --- a/repos/libports/recipes/src/test-spark/hash +++ b/repos/libports/recipes/src/test-spark/hash @@ -1 +1 @@ -2024-08-28 5bdb1816b76b49960e355d4ff5e2bf16a14ea3ef +2024-12-10 f687a373cad0e8efa246fc59e068302e8b7f19c0 diff --git a/repos/libports/recipes/src/test-spark_exception/hash b/repos/libports/recipes/src/test-spark_exception/hash index 8185beb71b..479d36c108 100644 --- a/repos/libports/recipes/src/test-spark_exception/hash +++ b/repos/libports/recipes/src/test-spark_exception/hash @@ -1 +1 @@ -2024-08-28 a7de8e483e42ecd1a9e2b279b0d61e6d57b5aae8 +2024-12-10 058e943a5debe805346d06021d40724f40f35a8f diff --git a/repos/libports/recipes/src/test-spark_secondary_stack/hash b/repos/libports/recipes/src/test-spark_secondary_stack/hash index 96711934b6..831dd3be4e 100644 --- a/repos/libports/recipes/src/test-spark_secondary_stack/hash +++ b/repos/libports/recipes/src/test-spark_secondary_stack/hash @@ -1 +1 @@ -2024-08-28 57cc4a8caea44a07bcf82c62f36e1ec0ef5dbc68 +2024-12-10 47b572caecbbb1f0917627f7469edaa589b69a1e diff --git a/repos/libports/recipes/src/test-stdcxx/hash b/repos/libports/recipes/src/test-stdcxx/hash index 7d5e8f8fa2..02d3cb1110 100644 --- a/repos/libports/recipes/src/test-stdcxx/hash +++ b/repos/libports/recipes/src/test-stdcxx/hash @@ -1 +1 @@ -2024-08-28 ef091c54902279fd677c5b7713fd2d66e302dcfc +2024-10-07 1ed13680965bc23094a8d1fc51b5bf304a240d42 diff --git a/repos/libports/recipes/src/test-tcp/hash b/repos/libports/recipes/src/test-tcp/hash index 3d32b3b3d3..b92c2b889c 100644 --- a/repos/libports/recipes/src/test-tcp/hash +++ b/repos/libports/recipes/src/test-tcp/hash @@ -1 +1 @@ -2024-08-28 8f8473c640cd2d459def368e2a33f0f107d7146b +2024-12-10 5c6df3a359da18c1b97484252d9bb7fef51b8165 diff --git a/repos/libports/recipes/src/usb_webcam/hash b/repos/libports/recipes/src/usb_webcam/hash index d5ca11af04..f159fd489a 100644 --- a/repos/libports/recipes/src/usb_webcam/hash +++ b/repos/libports/recipes/src/usb_webcam/hash @@ -1 +1 @@ -2024-08-28 65ba8ddf35e5007ae4ff399b6ff1fcb98c196652 +2024-12-10 e31c8cd018de957b8023ea00d8a62c528cfc84b2 diff --git a/repos/libports/recipes/src/vesa_fb/hash b/repos/libports/recipes/src/vesa_fb/hash index f715ed762f..f657cd6afc 100644 --- a/repos/libports/recipes/src/vesa_fb/hash +++ b/repos/libports/recipes/src/vesa_fb/hash @@ -1 +1 @@ -2024-08-28 9eec382e10dad329e2ddddb86f5f983b9362725a +2024-12-10 14d454ded6f23e3d73261ffbab5a5b6fcb6dd0d6 diff --git a/repos/libports/recipes/src/vfs_fatfs/hash b/repos/libports/recipes/src/vfs_fatfs/hash index 14934bdc03..bb0b7106a7 100644 --- a/repos/libports/recipes/src/vfs_fatfs/hash +++ b/repos/libports/recipes/src/vfs_fatfs/hash @@ -1 +1 @@ -2024-08-28 bf8fed48bd8a75b76cbf35367cc2bd5b1f49a387 +2024-12-10 6447801de86db3af675c58e61fe4520efdb569a1 diff --git a/repos/libports/recipes/src/vfs_jitterentropy/hash b/repos/libports/recipes/src/vfs_jitterentropy/hash index ac86af1fc3..166ed65007 100644 --- a/repos/libports/recipes/src/vfs_jitterentropy/hash +++ b/repos/libports/recipes/src/vfs_jitterentropy/hash @@ -1 +1 @@ -2024-08-28 19324aabab5bfcc7b4dec4829282222171bd902e +2024-12-10 d74c28796b2421ecf1b8efc2f1d2096300cf7b04 diff --git a/repos/libports/recipes/src/vfs_legacy_oss/hash b/repos/libports/recipes/src/vfs_legacy_oss/hash index 186baff6d4..33727e453b 100644 --- a/repos/libports/recipes/src/vfs_legacy_oss/hash +++ b/repos/libports/recipes/src/vfs_legacy_oss/hash @@ -1 +1 @@ -2024-08-28 7d3bfe2dd83c39e4035464c4d9c3c7cbc19aef14 +2024-12-10 ffc4e0063a72e9b7aa665f6d1150f9d716ba654a diff --git a/repos/libports/recipes/src/vfs_libusb/hash b/repos/libports/recipes/src/vfs_libusb/hash index 45f6fa1e18..b6b632ac0b 100644 --- a/repos/libports/recipes/src/vfs_libusb/hash +++ b/repos/libports/recipes/src/vfs_libusb/hash @@ -1 +1 @@ -2024-08-28 5b199be66b9fde6157c0d19c670898ad54013996 +2024-12-10 ef24de4bbd051a9e74780094aeee496b873341ff diff --git a/repos/libports/recipes/src/vfs_lwip/hash b/repos/libports/recipes/src/vfs_lwip/hash index 15cbf272f5..b0e2138aef 100644 --- a/repos/libports/recipes/src/vfs_lwip/hash +++ b/repos/libports/recipes/src/vfs_lwip/hash @@ -1 +1 @@ -2024-08-28 bc83e71ddb8dbb52eb648cc3cad07fca45428bcd +2024-12-10 1792496224f84dd0bdba41569a89cd6b5bfc419d diff --git a/repos/libports/recipes/src/zlib/hash b/repos/libports/recipes/src/zlib/hash index c43d08a6e5..a2156ae330 100644 --- a/repos/libports/recipes/src/zlib/hash +++ b/repos/libports/recipes/src/zlib/hash @@ -1 +1 @@ -2024-08-28 12afd01f1bbea9ad8e1f938fe2ab9b4bebb4ab98 +2024-10-07 22198d72e84cdfab5f45815589334c1d34e3ea4e diff --git a/repos/libports/run/mupdf.run b/repos/libports/run/mupdf.run index f6afdc976f..0fd33d44e7 100644 --- a/repos/libports/run/mupdf.run +++ b/repos/libports/run/mupdf.run @@ -1,6 +1,6 @@ build { - lib/libc lib/vfs lib/openjpeg lib/freetype lib/libpng lib/zlib lib/jbig2dec - lib/mupdf lib/jpeg app/pdf_view + lib/libc lib/libm lib/vfs lib/openjpeg lib/freetype lib/libpng lib/zlib + lib/jbig2dec lib/mupdf lib/jpeg app/pdf_view } create_boot_directory diff --git a/repos/libports/run/qt5_common.inc b/repos/libports/run/qt5_common.inc index cc8cda7f3e..873f78a5f4 100644 --- a/repos/libports/run/qt5_common.inc +++ b/repos/libports/run/qt5_common.inc @@ -286,7 +286,7 @@ proc qt5_start_nodes { } { </route> </start> - <start name="layouter"> + <start name="layouter" caps="150"> <binary name="window_layouter"/> <resource name="RAM" quantum="4M"/>} [qt5_layouter_config] { <route> diff --git a/repos/libports/run/qt5_quicktest.run b/repos/libports/run/qt5_quicktest.run index c3daf9def6..24f2ef0922 100644 --- a/repos/libports/run/qt5_quicktest.run +++ b/repos/libports/run/qt5_quicktest.run @@ -14,7 +14,7 @@ install_config { <any-service> <parent/> <any-child/> </any-service> </default-route> } [qt5_start_nodes] { - <start name="test-qt_quick" caps="250"> + <start name="test-qt_quick" caps="300"> <resource name="RAM" quantum="80M"/> <config> <vfs> diff --git a/repos/libports/run/qt5_samegame.run b/repos/libports/run/qt5_samegame.run index 04f59d1f93..27a68825c3 100644 --- a/repos/libports/run/qt5_samegame.run +++ b/repos/libports/run/qt5_samegame.run @@ -15,7 +15,7 @@ install_config { <any-service> <parent/> <any-child/> </any-service> </default-route> } [qt5_start_nodes] { - <start name="samegame" caps="350"> + <start name="samegame" caps="400"> <resource name="RAM" quantum="128M"/> <config> <vfs> diff --git a/repos/libports/run/qt5_textedit.run b/repos/libports/run/qt5_textedit.run index 80f437ecdf..b7b471ae6a 100644 --- a/repos/libports/run/qt5_textedit.run +++ b/repos/libports/run/qt5_textedit.run @@ -25,7 +25,7 @@ install_config { <policy label_prefix="textedit2" root="/" writeable="yes" /> </config> </start> - <start name="textedit" caps="300"> + <start name="textedit" caps="350"> <resource name="RAM" quantum="70M"/> <config> <libc stdout="/dev/log" stderr="/dev/log" pipe="/pipe" rtc="/dev/rtc"/> @@ -49,7 +49,7 @@ install_config { <any-service> <parent /> <any-child/> </any-service> </route> </start> - <start name="textedit2" caps="300"> + <start name="textedit2" caps="350"> <binary name="textedit" /> <resource name="RAM" quantum="70M"/> <config> diff --git a/repos/libports/run/qt5_virtualkeyboard.run b/repos/libports/run/qt5_virtualkeyboard.run index 9010d498ef..bb86dbc53d 100644 --- a/repos/libports/run/qt5_virtualkeyboard.run +++ b/repos/libports/run/qt5_virtualkeyboard.run @@ -17,7 +17,7 @@ install_config { <any-service> <parent/> <child name="wm"/> <any-child/> </any-service> </default-route> } [qt5_start_nodes] { - <start name="basic" caps="450"> + <start name="basic" caps="500"> <resource name="RAM" quantum="100M"/> <config> <vfs> diff --git a/repos/libports/run/qt6_common.inc b/repos/libports/run/qt6_common.inc index b30cfb9919..10319b5f16 100644 --- a/repos/libports/run/qt6_common.inc +++ b/repos/libports/run/qt6_common.inc @@ -286,7 +286,7 @@ proc qt6_start_nodes { } { </route> </start> - <start name="layouter"> + <start name="layouter" caps="150"> <binary name="window_layouter"/> <resource name="RAM" quantum="4M"/>} [qt6_layouter_config] { <route> diff --git a/repos/libports/run/qt6_i18n_cmake.run b/repos/libports/run/qt6_i18n_cmake.run new file mode 100644 index 0000000000..99b79788c1 --- /dev/null +++ b/repos/libports/run/qt6_i18n_cmake.run @@ -0,0 +1,46 @@ +source ${genode_dir}/repos/libports/run/qt6_common.inc + +import_from_depot [depot_user]/src/qt6_component \ + [depot_user]/src/qt6_i18n_cmake + +install_config { +<config> + <parent-provides> + } [qt6_parent_provides] { + </parent-provides> + <default caps="100"/> + <default-route> + <any-service> <parent/> <any-child/> </any-service> + </default-route> + } [qt6_start_nodes] { + <start name="i18n" caps="1000"> + <resource name="RAM" quantum="80M"/> + <config> + <vfs> + <dir name="dev"> + <log/> + <inline name="rtc">2018-01-01 00:01</inline> + </dir> + <dir name="pipe"> <pipe/> </dir> + <tar name="qt6_dejavusans.tar"/> + <tar name="qt6_libqgenode.tar"/> + </vfs> + <libc stdout="/dev/log" stderr="/dev/log" pipe="/pipe" rtc="/dev/rtc"/> + </config> + <route> + <service name="Gui"> <child name="wm"/> </service> + <service name="Report" label="shape"> + <child name="pointer" label="wm -> i18n -> shape"/> + </service> + <service name="ROM" label="mesa_gpu.lib.so"> + <parent label="mesa_gpu-softpipe.lib.so" /> + </service> + <any-service> <parent /> <any-child/> </any-service> + </route> + </start> +</config> +} + +build_boot_image [qt6_boot_modules] + +run_genode_until forever diff --git a/repos/libports/run/qt6_i18n_qmake.run b/repos/libports/run/qt6_i18n_qmake.run new file mode 100644 index 0000000000..a352f668ab --- /dev/null +++ b/repos/libports/run/qt6_i18n_qmake.run @@ -0,0 +1,46 @@ +source ${genode_dir}/repos/libports/run/qt6_common.inc + +import_from_depot [depot_user]/src/qt6_component \ + [depot_user]/src/qt6_i18n_qmake + +install_config { +<config> + <parent-provides> + } [qt6_parent_provides] { + </parent-provides> + <default caps="100"/> + <default-route> + <any-service> <parent/> <any-child/> </any-service> + </default-route> + } [qt6_start_nodes] { + <start name="i18n" caps="1000"> + <resource name="RAM" quantum="80M"/> + <config> + <vfs> + <dir name="dev"> + <log/> + <inline name="rtc">2018-01-01 00:01</inline> + </dir> + <dir name="pipe"> <pipe/> </dir> + <tar name="qt6_dejavusans.tar"/> + <tar name="qt6_libqgenode.tar"/> + </vfs> + <libc stdout="/dev/log" stderr="/dev/log" pipe="/pipe" rtc="/dev/rtc"/> + </config> + <route> + <service name="Gui"> <child name="wm"/> </service> + <service name="Report" label="shape"> + <child name="pointer" label="wm -> i18n -> shape"/> + </service> + <service name="ROM" label="mesa_gpu.lib.so"> + <parent label="mesa_gpu-softpipe.lib.so" /> + </service> + <any-service> <parent /> <any-child/> </any-service> + </route> + </start> +</config> +} + +build_boot_image [qt6_boot_modules] + +run_genode_until forever diff --git a/repos/libports/run/qt6_textedit.run b/repos/libports/run/qt6_textedit.run index 0a4aef9b99..b187021345 100644 --- a/repos/libports/run/qt6_textedit.run +++ b/repos/libports/run/qt6_textedit.run @@ -25,7 +25,7 @@ install_config { <policy label_prefix="textedit2" root="/" writeable="yes" /> </config> </start> - <start name="textedit" caps="300"> + <start name="textedit" caps="350"> <resource name="RAM" quantum="70M"/> <config> <libc stdout="/dev/log" stderr="/dev/log" pipe="/pipe" rtc="/dev/rtc"/> @@ -49,7 +49,7 @@ install_config { <any-service> <parent /> <any-child/> </any-service> </route> </start> - <start name="textedit2" caps="300"> + <start name="textedit2" caps="350"> <binary name="textedit" /> <resource name="RAM" quantum="70M"/> <config> diff --git a/repos/libports/run/webcam.inc b/repos/libports/run/webcam.inc deleted file mode 100644 index 53f312642e..0000000000 --- a/repos/libports/run/webcam.inc +++ /dev/null @@ -1,221 +0,0 @@ -assert_spec x86 - -# fuji4 -proc libuvc_vendor_id {} { return "0x04f2" } -proc libuvc_product_id {} { return "0xb564" } - -# c270 -#proc libuvc_vendor_id {} { return "0x046d" } -#proc libuvc_product_id {} { return "0x0825" } - -# quickcam -#proc libuvc_vendor_id {} { return "0x046d" } -#proc libuvc_product_id {} { return "0x09c1" } - -# t470 -#proc libuvc_vendor_id {} { return "0x0bda" } -#proc libuvc_product_id {} { return "0x58db" } - - -create_boot_directory - -import_from_depot [depot_user]/src/[base_src] \ - [depot_user]/pkg/usb_webcam \ - [depot_user]/src/acpi \ - [depot_user]/src/dynamic_rom \ - [depot_user]/src/init \ - [depot_user]/src/nitpicker \ - [depot_user]/src/pc_usb_host \ - [depot_user]/src/pci_decode \ - [depot_user]/src/platform \ - [depot_user]/src/report_rom \ - [depot_user]/src/rom_reporter \ - [depot_user]/src/vesa_fb - -import_from_depot $test_imports - -append config { -<config verbose="no" prio_levels="2"> - <parent-provides> - <service name="ROM"/> - <service name="IRQ"/> - <service name="IO_MEM"/> - <service name="IO_PORT"/> - <service name="PD"/> - <service name="RM"/> - <service name="CPU"/> - <service name="LOG"/> - <service name="VM"/> - </parent-provides> - <default-route> - <any-service> <parent/> <any-child/> </any-service> - </default-route> - <default caps="100"/> - - <start name="timer"> - <resource name="RAM" quantum="1M"/> - <provides><service name="Timer"/></provides> - <route> - <any-service> <parent/> </any-service> - </route> - </start> - - <start name="report_rom"> - <resource name="RAM" quantum="2M"/> - <provides> <service name="Report"/> <service name="ROM"/> </provides> - <config> - <policy label="pci_decode -> system" report="acpi -> acpi"/> - <policy label="platform -> devices" report="pci_decode -> devices"/> - </config> - </start> - - <start name="acpi" caps="350"> - <resource name="RAM" quantum="4M"/> - <route> - <service name="Report"> <child name="report_rom"/> </service> - <any-service> <parent/> </any-service> - </route> - </start> - - <start name="pci_decode" caps="350"> - <resource name="RAM" quantum="2M"/> - <route> - <service name="Report"> <child name="report_rom"/> </service> - <service name="ROM" label="system"> <child name="report_rom"/> </service> - <any-service> <parent/> </any-service> - </route> - </start> - - <start name="platform" caps="100" managing_system="yes"> - <resource name="RAM" quantum="2M"/> - <provides> - <service name="Platform"/> - </provides> - <route> - <service name="ROM" label="devices"> <child name="report_rom"/> </service> - <service name="Timer"> <child name="timer"/> </service> - <any-service> <parent/> </any-service> - </route> - <config> - <policy label="usb -> " info="yes"> <pci class="USB"/> </policy> - <policy label="fb -> " info="yes"> <pci class="VGA"/> </policy> - </config> - </start> - - <start name="usb" priority="0" caps="200"> - <binary name="pc_usb_host"/> - <resource name="RAM" quantum="16M"/> - <!-- <resource name="CPU" quantum="10"/> --> - <provides><service name="Usb"/></provides> - <config bios_handoff="no"> - <policy label_suffix="usb_webcam -> "> - <device vendor_id="} [libuvc_vendor_id] {" product_id="} [libuvc_product_id] {"/> - </policy> - </config> - <route> - <any-service> <parent/> <any-child/> </any-service> - </route> - </start> - - <start name="fb" priority="-1" caps="150"> - <binary name="vesa_fb"/> - <resource name="RAM" quantum="20M"/> - <config/> - <route> - <service name="Capture"> <child name="nitpicker"/> </service> - <any-service> <parent/> <any-child /> </any-service> - </route> - </start> - - <start name="nitpicker" priority="-1" caps="150"> - <resource name="RAM" quantum="12M"/> - <provides> - <service name="Gui"/> <service name="Capture"/> <service name="Event"/> - </provides> - <config> - <capture/> - <report focus="yes" hover="yes" /> - <domain name="" layer="3" content="client" label="no" focus="click" hover="always"/> - <default-policy domain=""/> - </config> - <route> - <service name="Report"> <child name="report_rom"/> </service> - <any-service> <parent/> <any-child /> </any-service> - </route> - </start> - - <start name="test_config" priority="-1"> - <binary name="dynamic_rom"/> - <resource name="RAM" quantum="1M"/> - <provides> <service name="ROM"/> </provides> - <config verbose="yes"> - <rom name="config"> - <inline> - <config verbose="no"> - <parent-provides> - <service name="ROM"/> - <service name="PD"/> - <service name="CPU"/> - <service name="LOG"/> - <service name="Timer"/> - <service name="Gui"/> - <service name="Capture"/> - </parent-provides> - <start name="} $test_binary {" caps="100"> - <resource name="RAM" quantum="15M"/> - <config period_ms="20" width="640" height="480"> } -append config $test_vfs_config -append config { - <view xpos="100" ypos="100"/> <!--view xpos="800" ypos="600"/--> - </config> - <route> - <any-service> <parent/> </any-service> - </route> - </start> - </config> - </inline> - <sleep milliseconds="7000"/> - <inline/> - <sleep milliseconds="3000"/> - </rom> - </config> - <route> - <service name="Timer"> <child name="timer"/> </service> - <any-service> <parent/> </any-service> - </route> - </start> - - <start name="test-capture" priority="-1" caps="200"> - <binary name="init"/> - <resource name="RAM" quantum="16M"/> - <route> - <service name="ROM" label="config"> - <child name="test_config" label="config"/> - </service> - <service name="Timer"> <child name="timer"/> </service> - <service name="Gui"> <child name="nitpicker"/> </service> - <service name="Capture"> <child name="webcam"/> </service> - <any-service> <parent/> </any-service> - </route> - </start> - - <start name="webcam" priority="-1" caps="800"> - <binary name="init"/> - <resource name="RAM" quantum="64M"/> - <route> - <service name="ROM" label="config"> <parent label="usb_webcam.config"/> </service> - <service name="Timer"> <child name="timer"/> </service> - <service name="Usb"> <child name="usb"/> </service> - <any-service> <parent /> </any-service> - </route> - <provides> <service name="Capture"/> <service name="Report"/> </provides> - </start> -</config>} - -install_config $config - -build_boot_image { } - -append qemu_args { -usb -device usb-host,vendorid=[libuvc_vendor_id],productid=[libuvc_product_id] } - -run_genode_until forever diff --git a/repos/libports/run/webcam.run b/repos/libports/run/webcam.run deleted file mode 100644 index 0dc358af92..0000000000 --- a/repos/libports/run/webcam.run +++ /dev/null @@ -1,7 +0,0 @@ -set test_imports "[depot_user]/src/test-capture" - -set test_binary "test-capture" - -set test_vfs_config { } - -source ${genode_dir}/repos/libports/run/webcam.inc diff --git a/repos/libports/run/webcam_vfs.run b/repos/libports/run/webcam_vfs.run deleted file mode 100644 index 2fc6ff0032..0000000000 --- a/repos/libports/run/webcam_vfs.run +++ /dev/null @@ -1,8 +0,0 @@ -set test_imports "[depot_user]/src/test-vfs_capture \ - [depot_user]/src/vfs_capture" - -set test_binary "test-vfs_capture" - -set test_vfs_config { <vfs><dir name="dev"><capture/></dir></vfs> } - -source ${genode_dir}/repos/libports/run/webcam.inc diff --git a/repos/libports/src/app/acpi_event/main.cc b/repos/libports/src/app/acpi_event/main.cc index 594ee95777..b85bd7fc54 100644 --- a/repos/libports/src/app/acpi_event/main.cc +++ b/repos/libports/src/app/acpi_event/main.cc @@ -140,8 +140,9 @@ struct Transform::Main auto press_release = [&] () -> Keys::Type { - if (key_type == "PRESS") return Keys::Type::PRESS; - if (key_type == "RELEASE") return Keys::Type::RELEASE; + if (key_type == "PRESS") return Keys::Type::PRESS; + if (key_type == "RELEASE") return Keys::Type::RELEASE; + if (key_type == "PRESS_RELEASE") return Keys::Type::PRESS_RELEASE; warning("unsupported 'as' attribute value \"", key_type, "\""); return Keys::Type::PRESS_RELEASE; }; diff --git a/repos/libports/src/app/pdf_view/main.cc b/repos/libports/src/app/pdf_view/main.cc index 904a47183d..f9a456474a 100644 --- a/repos/libports/src/app/pdf_view/main.cc +++ b/repos/libports/src/app/pdf_view/main.cc @@ -87,22 +87,25 @@ class Pdf_view private: - enum { NO_ALPHA = false }; - Genode::Env &_env; Gui::Connection _gui { _env }; - Framebuffer::Mode _nit_mode = _gui.mode(); - Framebuffer::Mode _fb_mode {}; + Gui::Rect _gui_window() + { + return _gui.window().convert<Gui::Rect>( + [&] (Gui::Rect rect) { return rect; }, + [&] (Gui::Undefined) { return Gui::Rect { { }, { 512, 512 } }; }); + } + + Gui::Rect _win_rect = _gui_window(); + + Framebuffer::Mode _fb_mode {}; Genode::Constructible<Genode::Attached_dataspace> _fb_ds { }; - Genode::Signal_handler<Pdf_view> _nit_mode_handler { - _env.ep(), *this, &Pdf_view::_handle_nit_mode }; - - Genode::Signal_handler<Pdf_view> _sync_handler { - _env.ep(), *this, &Pdf_view::_refresh }; + Genode::Signal_handler<Pdf_view> _gui_mode_handler { + _env.ep(), *this, &Pdf_view::_handle_gui_mode }; Genode::Signal_handler<Pdf_view> _input_handler { _env.ep(), *this, &Pdf_view::_handle_input_events }; @@ -115,21 +118,21 @@ class Pdf_view { using namespace Gui; - _nit_mode = _gui.mode(); + _win_rect = _gui_window(); - unsigned max_x = Genode::max(_nit_mode.area.w, _fb_mode.area.w); - unsigned max_y = Genode::max(_nit_mode.area.h, _fb_mode.area.h); + unsigned max_x = Genode::max(_win_rect.area.w, _fb_mode.area.w); + unsigned max_y = Genode::max(_win_rect.area.h, _fb_mode.area.h); if (max_x > _fb_mode.area.w || max_y > _fb_mode.area.h) { - _fb_mode = Mode { .area = { max_x, max_y } }; - _gui.buffer(_fb_mode, NO_ALPHA); + _fb_mode = Mode { .area = { max_x, max_y }, .alpha = false }; + _gui.buffer(_fb_mode); if (_fb_ds.constructed()) _fb_ds.destruct(); _fb_ds.construct(_env.rm(), _gui.framebuffer.dataspace()); } - _pdfapp.scrw = _nit_mode.area.w; - _pdfapp.scrh = _nit_mode.area.h; + _pdfapp.scrw = _win_rect.area.w; + _pdfapp.scrh = _win_rect.area.h; /* * XXX replace heuristics with a meaningful computation @@ -137,17 +140,17 @@ class Pdf_view * The magic values are hand-tweaked manually to accommodating the * use case of showing slides. */ - _pdfapp.resolution = Genode::min(_nit_mode.area.w/5, - _nit_mode.area.h/4); + _pdfapp.resolution = Genode::min(_win_rect.area.w/5, + _win_rect.area.h/4); - _view.area(_nit_mode.area); + _view.area(_win_rect.area); _view.front(); } - void _handle_nit_mode() + void _handle_gui_mode() { _rebuffer(); - pdfapp_onresize(&_pdfapp, _nit_mode.area.w, _nit_mode.area.h); + pdfapp_onresize(&_pdfapp, _win_rect.area.w, _win_rect.area.h); } pdfapp_t _pdfapp { }; @@ -213,14 +216,6 @@ class Pdf_view _handle_input_event(ev); }); }); } - void _refresh() - { - _gui.framebuffer.refresh(0, 0, _nit_mode.area.w, _nit_mode.area.h); - - /* handle one sync signal only */ - _gui.framebuffer.sync_sigh(Genode::Signal_context_capability()); - } - public: /** @@ -231,7 +226,7 @@ class Pdf_view */ Pdf_view(Genode::Env &env) : _env(env) { - _gui.mode_sigh(_nit_mode_handler); + _gui.info_sigh(_gui_mode_handler); _gui.input.sigh(_input_handler); pdfapp_init(&_pdfapp); @@ -304,12 +299,12 @@ void Pdf_view::show() int const tweaked_y_max = y_max - 2; /* center vertically if the dst buffer is higher than the image */ - if ((unsigned)_pdfapp.image->h < _nit_mode.area.h) - dst_line += dst_line_width*((_nit_mode.area.h - _pdfapp.image->h)/2); + if ((unsigned)_pdfapp.image->h < _win_rect.area.h) + dst_line += dst_line_width*((_win_rect.area.h - _pdfapp.image->h)/2); /* center horizontally if the dst buffer is wider than the image */ - if ((unsigned)_pdfapp.image->w < _nit_mode.area.w) - dst_line += (_nit_mode.area.w - _pdfapp.image->w)/2; + if ((unsigned)_pdfapp.image->w < _win_rect.area.w) + dst_line += (_win_rect.area.w - _pdfapp.image->w)/2; for (int y = 0; y < tweaked_y_max; y++) { copy_line_rgba(src_line, dst_line, x_max); @@ -317,8 +312,7 @@ void Pdf_view::show() dst_line += dst_line_width; } - /* refresh after the next sync signal */ - _gui.framebuffer.sync_sigh(_sync_handler); + _gui.framebuffer.refresh({ { 0, 0 }, _win_rect.area }); } diff --git a/repos/libports/src/app/qt6/examples/calculatorform/target.mk b/repos/libports/src/app/qt6/examples/calculatorform/target.mk index 0e373cec06..a502ce7bb6 100644 --- a/repos/libports/src/app/qt6/examples/calculatorform/target.mk +++ b/repos/libports/src/app/qt6/examples/calculatorform/target.mk @@ -1,4 +1,11 @@ -QMAKE_PROJECT_FILE = $(QT_DIR)/qttools/examples/designer/calculatorform/calculatorform.pro +ifeq ($(CONTRIB_DIR),) +QT6_TOOLS_DIR = $(call select_from_repositories,src/lib/qt6_tools) +else +QT6_TOOLS_PORT_DIR := $(call select_from_ports,qt6_tools) +QT6_TOOLS_DIR = $(QT6_TOOLS_PORT_DIR)/src/lib/qt6_tools +endif + +QMAKE_PROJECT_FILE = $(QT6_TOOLS_DIR)/examples/designer/calculatorform/calculatorform.pro QMAKE_TARGET_BINARIES = calculatorform diff --git a/repos/libports/src/app/qt6/examples/i18n_cmake/target.mk b/repos/libports/src/app/qt6/examples/i18n_cmake/target.mk new file mode 100644 index 0000000000..ccdde4bf97 --- /dev/null +++ b/repos/libports/src/app/qt6/examples/i18n_cmake/target.mk @@ -0,0 +1,16 @@ +ifeq ($(CONTRIB_DIR),) +QT6_TOOLS_DIR = $(call select_from_repositories,src/lib/qt6_tools) +else +QT6_TOOLS_PORT_DIR := $(call select_from_ports,qt6_tools) +QT6_TOOLS_DIR = $(QT6_TOOLS_PORT_DIR)/src/lib/qt6_tools +endif + +CMAKE_LISTS_DIR = $(QT6_TOOLS_DIR)/examples/linguist/i18n + +CMAKE_TARGET_BINARIES = i18n + +QT6_PORT_LIBS = libQt6Core \ + libQt6Gui \ + libQt6Widgets + +LIBS = qt6_cmake libc libm qt6_component stdcxx mesa egl diff --git a/repos/libports/src/app/qt6/examples/i18n_qmake/target.mk b/repos/libports/src/app/qt6/examples/i18n_qmake/target.mk new file mode 100644 index 0000000000..e6c55e96a9 --- /dev/null +++ b/repos/libports/src/app/qt6/examples/i18n_qmake/target.mk @@ -0,0 +1,16 @@ +ifeq ($(CONTRIB_DIR),) +QT6_TOOLS_DIR = $(call select_from_repositories,src/lib/qt6_tools) +else +QT6_TOOLS_PORT_DIR := $(call select_from_ports,qt6_tools) +QT6_TOOLS_DIR = $(QT6_TOOLS_PORT_DIR)/src/lib/qt6_tools +endif + +QMAKE_PROJECT_FILE = $(QT6_TOOLS_DIR)/examples/linguist/i18n/i18n.pro + +QMAKE_TARGET_BINARIES = i18n + +QT6_PORT_LIBS = libQt6Core \ + libQt6Gui \ + libQt6Widgets + +LIBS = qt6_qmake libc libm qt6_component stdcxx mesa egl diff --git a/repos/libports/src/app/qt6/examples/openglwindow/target.mk b/repos/libports/src/app/qt6/examples/openglwindow/target.mk index 83b8167309..424eb51ecb 100644 --- a/repos/libports/src/app/qt6/examples/openglwindow/target.mk +++ b/repos/libports/src/app/qt6/examples/openglwindow/target.mk @@ -1,4 +1,11 @@ -QMAKE_PROJECT_FILE = $(QT_DIR)/qtbase/examples/opengl/openglwindow/openglwindow.pro +ifeq ($(CONTRIB_DIR),) +QT6_BASE_DIR = $(call select_from_repositories,src/lib/qt6_base) +else +QT6_BASE_PORT_DIR := $(call select_from_ports,qt6_base) +QT6_BASE_DIR = $(QT6_BASE_PORT_DIR)/src/lib/qt6_base +endif + +QMAKE_PROJECT_FILE = $(QT6_BASE_DIR)/examples/opengl/openglwindow/openglwindow.pro QMAKE_TARGET_BINARIES = openglwindow diff --git a/repos/libports/src/app/qt6/examples/testqstring/target.mk b/repos/libports/src/app/qt6/examples/testqstring/target.mk index 85e1b6ab92..f3c32a5af0 100644 --- a/repos/libports/src/app/qt6/examples/testqstring/target.mk +++ b/repos/libports/src/app/qt6/examples/testqstring/target.mk @@ -1,4 +1,11 @@ -QMAKE_PROJECT_FILE = $(QT_DIR)/qtbase/examples/qtestlib/tutorial1 +ifeq ($(CONTRIB_DIR),) +QT6_BASE_DIR = $(call select_from_repositories,src/lib/qt6_base) +else +QT6_BASE_PORT_DIR := $(call select_from_ports,qt6_base) +QT6_BASE_DIR = $(QT6_BASE_PORT_DIR)/src/lib/qt6_base +endif + +QMAKE_PROJECT_FILE = $(QT6_BASE_DIR)/examples/qtestlib/tutorial1 QMAKE_TARGET_BINARIES = tutorial1 diff --git a/repos/libports/src/app/qt6/examples/tetrix/target.mk b/repos/libports/src/app/qt6/examples/tetrix/target.mk index f74cf04f40..6e16b25a7b 100644 --- a/repos/libports/src/app/qt6/examples/tetrix/target.mk +++ b/repos/libports/src/app/qt6/examples/tetrix/target.mk @@ -1,4 +1,11 @@ -QMAKE_PROJECT_FILE = $(QT_DIR)/qtbase/tests/manual/examples/widgets/widgets/tetrix/tetrix.pro +ifeq ($(CONTRIB_DIR),) +QT6_BASE_DIR = $(call select_from_repositories,src/lib/qt6_base) +else +QT6_BASE_PORT_DIR := $(call select_from_ports,qt6_base) +QT6_BASE_DIR = $(QT6_BASE_PORT_DIR)/src/lib/qt6_base +endif + +QMAKE_PROJECT_FILE = $(QT6_BASE_DIR)/tests/manual/examples/widgets/widgets/tetrix/tetrix.pro QMAKE_TARGET_BINARIES = tetrix diff --git a/repos/libports/src/app/qt6/examples/textedit/target.mk b/repos/libports/src/app/qt6/examples/textedit/target.mk index 603a5b94e3..ed0f34620c 100644 --- a/repos/libports/src/app/qt6/examples/textedit/target.mk +++ b/repos/libports/src/app/qt6/examples/textedit/target.mk @@ -1,4 +1,11 @@ -QMAKE_PROJECT_FILE = $(QT_DIR)/qtbase/tests/manual/examples/widgets/richtext/textedit/textedit.pro +ifeq ($(CONTRIB_DIR),) +QT6_BASE_DIR = $(call select_from_repositories,src/lib/qt6_base) +else +QT6_BASE_PORT_DIR := $(call select_from_ports,qt6_base) +QT6_BASE_DIR = $(QT6_BASE_PORT_DIR)/src/lib/qt6_base +endif + +QMAKE_PROJECT_FILE = $(QT6_BASE_DIR)/tests/manual/examples/widgets/richtext/textedit/textedit.pro QMAKE_TARGET_BINARIES = textedit diff --git a/repos/libports/src/app/usb_webcam/main.cc b/repos/libports/src/app/usb_webcam/main.cc index 97ea891001..19e15050a2 100644 --- a/repos/libports/src/app/usb_webcam/main.cc +++ b/repos/libports/src/app/usb_webcam/main.cc @@ -19,6 +19,7 @@ #include <base/log.h> #include <gui_session/connection.h> #include <libc/component.h> +#include <libc/args.h> #include <os/pixel_rgb888.h> #pragma GCC diagnostic push @@ -61,7 +62,7 @@ class Viewer _env { env }, _mode { mode } { - _gui.buffer(mode, false); + _gui.buffer(mode); _fb_ds.construct(_env.rm(), _gui.framebuffer.dataspace()); _framebuffer = _fb_ds->local_addr<uint8_t>(); @@ -69,9 +70,7 @@ class Viewer uint8_t *framebuffer() { return _framebuffer; } - void refresh() { - _gui.framebuffer.refresh(0, 0, _mode.area.w, _mode.area.h); - } + void refresh() { _gui.framebuffer.refresh({ { 0, 0 }, _mode.area }); } Framebuffer::Mode const &mode() { return _mode; } }; @@ -277,10 +276,10 @@ class Main if (_webcam.constructed()) _webcam.destruct(); + Framebuffer::Mode mode { .area = { width, height }, .alpha = false }; if (enabled) { try { - _webcam.construct(_env, Framebuffer::Mode { - .area = { width, height } }, frame_format, fps); + _webcam.construct(_env, mode, frame_format, fps); } catch (...) { } } } @@ -297,7 +296,17 @@ class Main }; +extern char **environ; + void Libc::Component::construct(Libc::Env &env) { + int argc = 0; + char **argv = nullptr; + char **envp = nullptr; + + populate_args_and_env(env, argc, argv, envp); + + environ = envp; + static Main main(env); } diff --git a/repos/libports/src/driver/framebuffer/vesa/main.cc b/repos/libports/src/driver/framebuffer/vesa/main.cc index e4dabc3f1a..cc6bf700f0 100644 --- a/repos/libports/src/driver/framebuffer/vesa/main.cc +++ b/repos/libports/src/driver/framebuffer/vesa/main.cc @@ -150,7 +150,11 @@ void Vesa_driver::Main::_handle_config() /* enable pixel capturing */ _fb_ds.construct(_env.rm(), Framebuffer::hw_framebuffer()); - _captured_screen.construct(_capture, _env.rm(), _size); + + using Attr = Capture::Connection::Screen::Attr; + _captured_screen.construct(_capture, _env.rm(), Attr { + .px = _size, + .mm = { } }); unsigned long const period_ms = config.attribute_value("period_ms", 20U); _timer.trigger_periodic(period_ms*1000); diff --git a/repos/libports/src/lib/libc/alarm.cc b/repos/libports/src/lib/libc/alarm.cc new file mode 100644 index 0000000000..250de9a3d6 --- /dev/null +++ b/repos/libports/src/lib/libc/alarm.cc @@ -0,0 +1,118 @@ +/* + * \brief Libc interval timer + * \author Norman Feske + * \date 2024-08-00 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* libc includes */ +#include <sys/time.h> + +/* libc-internal includes */ +#include <internal/signal.h> +#include <internal/timer.h> +#include <internal/init.h> +#include <internal/errno.h> + + +static Libc::Timer_accessor *_timer_accessor_ptr; +static Libc::Signal *_signal_ptr; + +void Libc::init_alarm(Timer_accessor &timer_accessor, Signal &signal) +{ + _timer_accessor_ptr = &timer_accessor; + _signal_ptr = &signal; +} + + +namespace Libc { struct Itimer_real; } + + +struct Libc::Itimer_real : Noncopyable +{ + struct Handler : Timeout_handler + { + Signal &_signal; + + virtual void handle_timeout() override { _signal.charge(SIGALRM); } + + Handler(Signal &signal) : _signal(signal) { } + + } _handler; + + Timer_accessor &_timer_accessor; + + Constructible<Timeout> _timeout { }; + + void arm_or_disarm(timeval tv) + { + Libc::uint64_t const ms = tv.tv_sec*1000 + tv.tv_usec/1000; + + if (ms) { + _timeout.construct(_timer_accessor, _handler); + _timeout->start(ms); + } else { + _timeout.destruct(); + } + } + + timeval current() + { + if (!_timeout.constructed()) + return { }; + + Libc::uint64_t const ms = _timeout->duration_left(); + + return { .tv_sec = long(ms/1000), + .tv_usec = long((ms % 1000)*1000) }; + } + + Itimer_real(Timer_accessor &timer_accessor, Signal &signal) + : + _handler(signal), _timer_accessor(timer_accessor) + { } +}; + + +using namespace Libc; + + +static Itimer_real &itimer_real() +{ + struct Missing_call_of_init_alarm : Exception { }; + if (!_timer_accessor_ptr || !_signal_ptr) + throw Missing_call_of_init_alarm(); + + static Itimer_real itimer { *_timer_accessor_ptr, *_signal_ptr }; + return itimer; +} + + +extern "C" int setitimer(int which, const itimerval *new_value, itimerval *old_value) +{ + if (which != ITIMER_REAL) { + warning("setitimer: timer %d unsupported"); + return Errno(EINVAL); + } + + if (!new_value) + return Errno(EFAULT); + + if (new_value->it_interval.tv_sec || new_value->it_interval.tv_usec) + warning("setitimer: argument 'new_value->it_interval' not handled"); + + if (old_value) { + old_value->it_interval = { }; + old_value->it_value = itimer_real().current(); + } + + itimer_real().arm_or_disarm(new_value->it_value); + + return 0; +} diff --git a/repos/libports/src/lib/libc/component.cc b/repos/libports/src/lib/libc/component.cc index 237ec974dc..0f565b8b37 100644 --- a/repos/libports/src/lib/libc/component.cc +++ b/repos/libports/src/lib/libc/component.cc @@ -15,9 +15,6 @@ /* Genode includes */ #include <base/component.h> -/* base-internal includes */ -#include <base/internal/unmanaged_singleton.h> - /* libc-internal includes */ #include <internal/plugin_registry.h> #include <internal/kernel.h> @@ -35,8 +32,8 @@ void Component::construct(Genode::Env &env) static char *null_env = nullptr; if (!environ) environ = &null_env; - Genode::Allocator &heap = - *unmanaged_singleton<Genode::Heap>(env.ram(), env.rm()); + /* call of '__cxa_atexit' is ignored prior 'init_atexit' */ + static Genode::Heap heap { env.ram(), env.rm() }; /* pass Genode::Env to libc subsystems that depend on it */ Libc::init_fd_alloc(heap); @@ -44,7 +41,9 @@ void Component::construct(Genode::Env &env) Libc::init_dl(env); Libc::sysctl_init(env); - Libc::Kernel &kernel = *unmanaged_singleton<Libc::Kernel>(env, heap); + /* prevent call of '__cxa_atexit' for the 'Kernel' object */ + static long _kernel_obj[(sizeof(Libc::Kernel) + sizeof(long))/sizeof(long)]; + Libc::Kernel &kernel = *new (_kernel_obj) Libc::Kernel(env, heap); Libc::libc_config_init(kernel.libc_env().libc_config()); diff --git a/repos/libports/src/lib/libc/dummies.cc b/repos/libports/src/lib/libc/dummies.cc index 8d3606d5ac..1f55acbd58 100644 --- a/repos/libports/src/lib/libc/dummies.cc +++ b/repos/libports/src/lib/libc/dummies.cc @@ -141,7 +141,6 @@ DUMMY(int , -1, seteuid, (uid_t)) DUMMY(int , -1, setgid, (gid_t)) DUMMY(int , -1, setuid, (uid_t)) DUMMY(int , -1, setgroups, (int, const gid_t *)) -DUMMY(int , -1, setitimer, (int, const itimerval *, itimerval *)) DUMMY(int , -1, setpgid, (pid_t, pid_t)) DUMMY(int , -1, setpriority, (int, int, int)) DUMMY(int , -1, setregid, (gid_t, gid_t)) diff --git a/repos/libports/src/lib/libc/fd_alloc.cc b/repos/libports/src/lib/libc/fd_alloc.cc index 3eff157911..be1a2d1362 100644 --- a/repos/libports/src/lib/libc/fd_alloc.cc +++ b/repos/libports/src/lib/libc/fd_alloc.cc @@ -17,9 +17,6 @@ #include <base/env.h> #include <base/log.h> -/* Genode-internal includes */ -#include <base/internal/unmanaged_singleton.h> - /* libc includes */ #include <fcntl.h> #include <unistd.h> @@ -37,16 +34,6 @@ static Allocator *_alloc_ptr; void Libc::init_fd_alloc(Allocator &alloc) { _alloc_ptr = &alloc; } -File_descriptor_allocator *Libc::file_descriptor_allocator() -{ - if (_alloc_ptr) - return unmanaged_singleton<File_descriptor_allocator>(*_alloc_ptr); - - error("missing call of 'init_fd_alloc'"); - return nullptr; -} - - File_descriptor_allocator::File_descriptor_allocator(Allocator &alloc) : _alloc(alloc) { } diff --git a/repos/libports/src/lib/libc/file_operations.cc b/repos/libports/src/lib/libc/file_operations.cc index 246dd2dad7..e0e19dd8e7 100644 --- a/repos/libports/src/lib/libc/file_operations.cc +++ b/repos/libports/src/lib/libc/file_operations.cc @@ -68,10 +68,11 @@ Libc::Mmap_registry *Libc::mmap_registry() static Cwd *_cwd_ptr; static unsigned int _mmap_align_log2 { PAGE_SHIFT }; -void Libc::init_file_operations(Cwd &cwd, +void Libc::init_file_operations(Cwd &cwd, File_descriptor_allocator &fd_alloc, Config_accessor const &config_accessor) { - _cwd_ptr = &cwd; + _fd_alloc_ptr = &fd_alloc; + _cwd_ptr = &cwd; config_accessor.config().with_optional_sub_node("libc", [&] (Xml_node libc) { libc.with_optional_sub_node("mmap", [&] (Xml_node mmap) { diff --git a/repos/libports/src/lib/libc/fork.cc b/repos/libports/src/lib/libc/fork.cc index ea01e6bf24..4c9c0c98b8 100644 --- a/repos/libports/src/lib/libc/fork.cc +++ b/repos/libports/src/lib/libc/fork.cc @@ -60,18 +60,19 @@ namespace { using Fn = Monitor::Function_result; } static pid_t fork_result; -static Env *_env_ptr; -static Allocator *_alloc_ptr; -static Monitor *_monitor_ptr; -static Libc::Signal *_signal_ptr; -static Heap *_malloc_heap_ptr; -static void *_user_stack_base_ptr; -static size_t _user_stack_size; -static int _pid; -static int _pid_cnt; -static Config_accessor const *_config_accessor_ptr; -static Binary_name const *_binary_name_ptr; -static Forked_children *_forked_children_ptr; +static Env *_env_ptr; +static File_descriptor_allocator *_fd_alloc_ptr; +static Allocator *_alloc_ptr; +static Monitor *_monitor_ptr; +static Libc::Signal *_signal_ptr; +static Heap *_malloc_heap_ptr; +static void *_user_stack_base_ptr; +static size_t _user_stack_size; +static int _pid; +static int _pid_cnt; +static Config_accessor const *_config_accessor_ptr; +static Binary_name const *_binary_name_ptr; +static Forked_children *_forked_children_ptr; static Libc::Monitor & monitor() @@ -91,9 +92,11 @@ struct Libc::Child_config pid_t const _pid; - void _generate(Xml_generator &xml, Xml_node config); + void _generate(Xml_generator &xml, Xml_node const &config, + File_descriptor_allocator &); - Child_config(Env &env, Config_accessor const &config_accessor, pid_t pid) + Child_config(Env &env, Config_accessor const &config_accessor, + File_descriptor_allocator &fd_alloc, pid_t pid) : _env(env), _pid(pid) { @@ -108,7 +111,7 @@ struct Libc::Child_config Xml_generator xml(_ds->local_addr<char>(), buffer_size, "config", [&] () { - _generate(xml, config); }); + _generate(xml, config, fd_alloc); }); }, [&] () { buffer_size += 4096; } @@ -123,7 +126,8 @@ struct Libc::Child_config }; -void Libc::Child_config::_generate(Xml_generator &xml, Xml_node config) +void Libc::Child_config::_generate(Xml_generator &xml, Xml_node const &config, + File_descriptor_allocator &fd_alloc) { using Addr = String<30>; @@ -155,7 +159,7 @@ void Libc::Child_config::_generate(Xml_generator &xml, Xml_node config) xml.attribute("cwd", Path(Cstring(buf))); } - file_descriptor_allocator()->generate_info(xml); + fd_alloc.generate_info(xml); auto gen_range_attr = [&] (auto at, auto size) { @@ -464,8 +468,10 @@ struct Libc::Forked_child : Child_policy, Child_ready Binary_name binary_name() const override { return _binary_name; } - Pd_session &ref_pd() override { return _env.pd(); } - Pd_session_capability ref_pd_cap() const override { return _env.pd_session_cap(); } + Ram_allocator &session_md_ram() override { return _env.ram(); } + + Pd_account &ref_account() override { return _env.pd(); } + Capability<Pd_account> ref_account_cap() const override { return _env.pd_session_cap(); } void init(Pd_session &session, Pd_session_capability cap) override { @@ -545,19 +551,20 @@ struct Libc::Forked_child : Child_policy, Child_ready Child _child; - Forked_child(Env &env, - Entrypoint &fork_ep, - Allocator &alloc, - Binary_name const &binary_name, - Signal &signal, - pid_t pid, - Config_accessor const &config_accessor, - Parent_services &parent_services, - Local_rom_services &local_rom_services) + Forked_child(Env &env, + File_descriptor_allocator &fd_alloc, + Entrypoint &fork_ep, + Allocator &alloc, + Binary_name const &binary_name, + Signal &signal, + pid_t pid, + Config_accessor const &config_accessor, + Parent_services &parent_services, + Local_rom_services &local_rom_services) : _env(env), _binary_name(binary_name), _signal(signal), _pid(pid), - _child_config(env, config_accessor, pid), + _child_config(env, config_accessor, fd_alloc, pid), _parent_services(parent_services), _local_rom_services(local_rom_services), _local_clone_service(env, fork_ep, *this), @@ -592,8 +599,8 @@ static Forked_child * fork_kernel_routine() static Local_rom_services local_rom_services(env, fork_ep, alloc); Registered<Forked_child> *child = new (alloc) - Registered<Forked_child>(*_forked_children_ptr, env, fork_ep, alloc, - *_binary_name_ptr, + Registered<Forked_child>(*_forked_children_ptr, env, *_fd_alloc_ptr, + fork_ep, alloc, *_binary_name_ptr, signal, child_pid, *_config_accessor_ptr, parent_services, local_rom_services); @@ -725,7 +732,10 @@ extern "C" pid_t __sys_wait4(pid_t pid, int *status, int options, rusage *rusage return Fn::INCOMPLETE; }); - file_descriptor_allocator()->update_append_libc_fds(); + if (_fd_alloc_ptr) + _fd_alloc_ptr->update_append_libc_fds(); + else + error("__sys_wait4: missing call of 'init_fork'"); /* * The libc expects status information in bits 0..6 and the exit value @@ -742,12 +752,14 @@ extern "C" pid_t __sys_wait4(pid_t pid, int *status, int options, rusage *rusage extern "C" pid_t wait4(pid_t, int *, int, rusage *) __attribute__((weak, alias("__sys_wait4"))); -void Libc::init_fork(Env &env, Config_accessor const &config_accessor, +void Libc::init_fork(Env &env, File_descriptor_allocator &fd_alloc, + Config_accessor const &config_accessor, Allocator &alloc, Heap &malloc_heap, pid_t pid, Monitor &monitor, Signal &signal, Binary_name const &binary_name) { _env_ptr = &env; + _fd_alloc_ptr = &fd_alloc; _alloc_ptr = &alloc; _monitor_ptr = &monitor; _signal_ptr = &signal; diff --git a/repos/libports/src/lib/libc/internal/fd_alloc.h b/repos/libports/src/lib/libc/internal/fd_alloc.h index fe9c3b2ed9..5fdf9c451a 100644 --- a/repos/libports/src/lib/libc/internal/fd_alloc.h +++ b/repos/libports/src/lib/libc/internal/fd_alloc.h @@ -41,97 +41,96 @@ namespace Libc { enum { ANY_FD = -1 }; - struct File_descriptor - { - Genode::Mutex mutex { }; + struct File_descriptor; - using Id_space = Genode::Id_space<File_descriptor>; - Id_space::Element _elem; - - int const libc_fd = _elem.id().value; - - char const *fd_path = nullptr; /* for 'fchdir', 'fstat' */ - - Plugin *plugin; - Plugin_context *context; - - int flags = 0; /* for 'fcntl' */ - bool cloexec = 0; /* for 'fcntl' */ - bool modified = false; - - File_descriptor(Id_space &id_space, Plugin &plugin, Plugin_context &context, - Id_space::Id id) - : _elem(*this, id_space, id), plugin(&plugin), context(&context) { } - - void path(char const *newpath); - }; - - - class File_descriptor_allocator - { - private: - - Genode::Mutex _mutex; - - Genode::Allocator &_alloc; - - using Id_space = File_descriptor::Id_space; - - Id_space _id_space; - - Genode::Bit_allocator<MAX_NUM_FDS> _id_allocator; - - public: - - /** - * Constructor - */ - File_descriptor_allocator(Genode::Allocator &_alloc); - - /** - * Allocate file descriptor - */ - File_descriptor *alloc(Plugin *plugin, Plugin_context *context, int libc_fd = -1); - - /** - * Release file descriptor - */ - void free(File_descriptor *fdo); - - /** - * Prevent the use of the specified file descriptor - */ - void preserve(int libc_fd); - - File_descriptor *find_by_libc_fd(int libc_fd); - - /** - * Return any file descriptor with close-on-execve flag set - * - * \return pointer to file descriptor, or - * nullptr is no such file descriptor exists - */ - File_descriptor *any_cloexec_libc_fd(); - - /** - * Update seek state of file descriptor with append flag set. - */ - void update_append_libc_fds(); - - /** - * Return file-descriptor ID of any open file, or -1 if no file is - * open - */ - int any_open_fd(); - - void generate_info(Genode::Xml_generator &); - }; - - - /** - * Return singleton instance of file-descriptor allocator - */ - extern File_descriptor_allocator *file_descriptor_allocator(); + class File_descriptor_allocator; } + +struct Libc::File_descriptor +{ + Genode::Mutex mutex { }; + + using Id_space = Genode::Id_space<File_descriptor>; + Id_space::Element _elem; + + int const libc_fd = _elem.id().value; + + char const *fd_path = nullptr; /* for 'fchdir', 'fstat' */ + + Plugin *plugin; + Plugin_context *context; + + int flags = 0; /* for 'fcntl' */ + bool cloexec = 0; /* for 'fcntl' */ + bool modified = false; + + File_descriptor(Id_space &id_space, Plugin &plugin, Plugin_context &context, + Id_space::Id id) + : _elem(*this, id_space, id), plugin(&plugin), context(&context) { } + + void path(char const *newpath); +}; + + +class Libc::File_descriptor_allocator +{ + private: + + Genode::Mutex _mutex; + + Genode::Allocator &_alloc; + + using Id_space = File_descriptor::Id_space; + + Id_space _id_space; + + Genode::Bit_allocator<MAX_NUM_FDS> _id_allocator; + + public: + + /** + * Constructor + */ + File_descriptor_allocator(Genode::Allocator &_alloc); + + /** + * Allocate file descriptor + */ + File_descriptor *alloc(Plugin *plugin, Plugin_context *context, int libc_fd = -1); + + /** + * Release file descriptor + */ + void free(File_descriptor *fdo); + + /** + * Prevent the use of the specified file descriptor + */ + void preserve(int libc_fd); + + File_descriptor *find_by_libc_fd(int libc_fd); + + /** + * Return any file descriptor with close-on-execve flag set + * + * \return pointer to file descriptor, or + * nullptr is no such file descriptor exists + */ + File_descriptor *any_cloexec_libc_fd(); + + /** + * Update seek state of file descriptor with append flag set. + */ + void update_append_libc_fds(); + + /** + * Return file-descriptor ID of any open file, or -1 if no file is + * open + */ + int any_open_fd(); + + void generate_info(Genode::Xml_generator &); +}; + #endif /* _LIBC_PLUGIN__FD_ALLOC_H_ */ diff --git a/repos/libports/src/lib/libc/internal/file.h b/repos/libports/src/lib/libc/internal/file.h index 4f336ee875..1d24ac17b1 100644 --- a/repos/libports/src/lib/libc/internal/file.h +++ b/repos/libports/src/lib/libc/internal/file.h @@ -25,6 +25,20 @@ enum { INVALID_FD = -1 }; + +static Libc::File_descriptor_allocator *_fd_alloc_ptr; + + +static Libc::File_descriptor_allocator *file_descriptor_allocator() +{ + if (!_fd_alloc_ptr) { + Genode::error("missing initialization of _fd_alloc_ptr"); + for (;;); + } + return _fd_alloc_ptr; +} + + /** * Find plugin responsible for the specified libc file descriptor * @@ -32,8 +46,7 @@ enum { INVALID_FD = -1 }; */ static inline Libc::File_descriptor *libc_fd_to_fd(int libc_fd, const char *func_name) { - Libc::File_descriptor *fd = - Libc::file_descriptor_allocator()->find_by_libc_fd(libc_fd); + Libc::File_descriptor *fd = file_descriptor_allocator()->find_by_libc_fd(libc_fd); if (!fd) Genode::error("no plugin found for ", func_name, "(", libc_fd, ")"); return fd; diff --git a/repos/libports/src/lib/libc/internal/init.h b/repos/libports/src/lib/libc/internal/init.h index 433ff7136c..e2ad25097b 100644 --- a/repos/libports/src/lib/libc/internal/init.h +++ b/repos/libports/src/lib/libc/internal/init.h @@ -67,12 +67,13 @@ namespace Libc { * Virtual file system */ void init_vfs_plugin(Monitor &, Genode::Region_map &); - void init_file_operations(Cwd &, Config_accessor const &); + void init_file_operations(Cwd &, File_descriptor_allocator &, Config_accessor const &); + void init_pread_pwrite(File_descriptor_allocator &); /** * Poll support */ - void init_poll(Signal &, Monitor &); + void init_poll(Signal &, Monitor &, File_descriptor_allocator &); /** * Select support @@ -108,11 +109,13 @@ namespace Libc { */ void init_sleep(Monitor &); void init_time(Current_time &, Current_real_time &); + void init_alarm(Timer_accessor &, Signal &); /** * Socket fs */ - void init_socket_fs(Suspend &, Monitor &); + void init_socket_fs(Suspend &, Monitor &, File_descriptor_allocator &); + void init_socket_operations(File_descriptor_allocator &); /** * Pthread/semaphore support @@ -130,9 +133,10 @@ namespace Libc { /** * Fork mechanism */ - void init_fork(Genode::Env &, Config_accessor const &, - Genode::Allocator &heap, Heap &malloc_heap, int pid, - Monitor &, Signal &, Binary_name const &); + void init_fork(Genode::Env &, File_descriptor_allocator &, + Config_accessor const &, Genode::Allocator &heap, + Heap &malloc_heap, int pid, Monitor &, Signal &, + Binary_name const &); struct Reset_malloc_heap : Interface { @@ -155,6 +159,11 @@ namespace Libc { * Atexit handling */ void init_atexit(Atexit &); + + /** + * Kqueue support + */ + void init_kqueue(Genode::Allocator &, Monitor &, File_descriptor_allocator &); } #endif /* _LIBC__INTERNAL__INIT_H_ */ diff --git a/repos/libports/src/lib/libc/internal/kernel.h b/repos/libports/src/lib/libc/internal/kernel.h index 2b632a93c7..069ae77ef9 100644 --- a/repos/libports/src/lib/libc/internal/kernel.h +++ b/repos/libports/src/lib/libc/internal/kernel.h @@ -17,6 +17,7 @@ #define _LIBC__INTERNAL__KERNEL_H_ /* base-internal includes */ +#include <util/reconstructible.h> #include <internal/call_func.h> /* libc includes */ @@ -135,6 +136,8 @@ struct Libc::Kernel final : Vfs::Read_ready_response_handler, */ Binary_name _binary_name { "binary" }; + File_descriptor_allocator _fd_alloc { _heap }; + /** * Allocator for application-owned data * @@ -172,7 +175,7 @@ struct Libc::Kernel final : Vfs::Read_ready_response_handler, bool const _update_mtime = _libc_env.libc_config().attribute_value("update_mtime", true); - Vfs_plugin _vfs { _libc_env, _libc_env.vfs_env(), _heap, *this, + Vfs_plugin _vfs { _libc_env, _fd_alloc, _libc_env.vfs_env(), _heap, *this, _update_mtime ? Vfs_plugin::Update_mtime::YES : Vfs_plugin::Update_mtime::NO, *this /* current_real_time */, @@ -409,6 +412,9 @@ struct Libc::Kernel final : Vfs::Read_ready_response_handler, ~Kernel() { error(__PRETTY_FUNCTION__, " should not be executed!"); } + /* use placement new instead of 'construct_at' because 'Kernel' is final */ + void *operator new (size_t, void *ptr) { return ptr; } + Libc::Env & libc_env() { return _libc_env; } /** @@ -584,6 +590,14 @@ struct Libc::Kernel final : Vfs::Read_ready_response_handler, } } + /** + * Monitor interface + */ + void monitor_async(Job &job) override + { + _monitors.monitor_async(job); + } + void _trigger_monitor_examination() override { if (_main_context()) diff --git a/repos/libports/src/lib/libc/internal/kqueue.h b/repos/libports/src/lib/libc/internal/kqueue.h new file mode 100644 index 0000000000..715cc22dd7 --- /dev/null +++ b/repos/libports/src/lib/libc/internal/kqueue.h @@ -0,0 +1,40 @@ +/* + * \brief kqueue plugin interface + * \author Benjamin Lamowski + * \date 2024-08-07 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _LIBC__INTERNAL__KQUEUE_H_ +#define _LIBC__INTERNAL__KQUEUE_H_ + +/* Libc includes */ +#include <sys/event.h> + +#include <base/allocator.h> +#include <internal/plugin.h> + +namespace Libc { class Kqueue_plugin; } + + +class Libc::Kqueue_plugin : public Libc::Plugin +{ + private: + + Genode::Allocator & _alloc; + + public: + + Kqueue_plugin(Genode::Allocator & alloc) : _alloc(alloc) { } + + int create_kqueue(); + int close(File_descriptor *) override; +}; + +#endif /* _LIBC__INTERNAL__KQUEUE_H_ */ diff --git a/repos/libports/src/lib/libc/internal/monitor.h b/repos/libports/src/lib/libc/internal/monitor.h index 228ea0f8cf..ac6cef1207 100644 --- a/repos/libports/src/lib/libc/internal/monitor.h +++ b/repos/libports/src/lib/libc/internal/monitor.h @@ -17,6 +17,7 @@ /* Genode includes */ #include <base/registry.h> +#include <util/reconstructible.h> /* libc-internal includes */ #include <internal/types.h> @@ -82,6 +83,13 @@ class Libc::Monitor : Interface return _monitor(function, timeout_ms); } + /** + * Monitor asynchronous job execution + * + * Returns immediately after the job is registered for execution. + */ + virtual void monitor_async(Job &job) = 0; + /** * Trigger examination of monitored functions */ @@ -89,19 +97,32 @@ class Libc::Monitor : Interface }; -struct Libc::Monitor::Job +class Libc::Monitor::Job { private: + friend class Pool; + Monitor::Function &_fn; Blockade &_blockade; + Constructible<Registry<Job>::Element> _async_element; + + void _register_async(Registry<Job> ®istry) + { + _async_element.construct(registry, *this); + } + public: Job(Monitor::Function &fn, Blockade &blockade) : _fn(fn), _blockade(blockade) { } - virtual ~Job() { } + virtual ~Job() + { + if (_async_element.constructed()) + _async_element.destruct(); + } bool execute() { return _fn.execute() == Function_result::COMPLETE; } @@ -124,7 +145,12 @@ struct Libc::Monitor::Pool Pool(Monitor &monitor) : _monitor(monitor) { } - /* called by monitor-user context */ + /** + * Monitor synchronous job execution + * + * The function is called by the monitor-user context and returns after + * job completion. + */ void monitor(Job &job) { Registry<Job>::Element element { _jobs, job }; @@ -134,6 +160,18 @@ struct Libc::Monitor::Pool job.wait_for_completion(); } + /** + * Monitor asynchronous job execution + * + * The function is called by the monitor-user context and returns after + * job is registered for execution. Jobs are removed from the pool on + * destruction. + */ + void monitor_async(Job &job) + { + job._register_async(_jobs); + } + enum class State { JOBS_PENDING, ALL_COMPLETE }; /* called by the monitor context itself */ diff --git a/repos/libports/src/lib/libc/internal/signal.h b/repos/libports/src/lib/libc/internal/signal.h index e3675f9259..823c352f83 100644 --- a/repos/libports/src/lib/libc/internal/signal.h +++ b/repos/libports/src/lib/libc/internal/signal.h @@ -16,10 +16,13 @@ /* Genode includes */ #include <util/noncopyable.h> +#include <util/reconstructible.h> #include <base/registry.h> +#include <base/thread.h> /* libc includes */ #include <signal.h> +#include <stdlib.h> /* libc-internal includes */ #include <internal/call_func.h> diff --git a/repos/libports/src/lib/libc/internal/vfs_plugin.h b/repos/libports/src/lib/libc/internal/vfs_plugin.h index 17f314b29b..1837a06eda 100644 --- a/repos/libports/src/lib/libc/internal/vfs_plugin.h +++ b/repos/libports/src/lib/libc/internal/vfs_plugin.h @@ -81,6 +81,7 @@ class Libc::Vfs_plugin final : public Plugin reference_handle(reference_handle) { } }; + File_descriptor_allocator &_fd_alloc; Genode::Allocator &_alloc; Vfs::File_system &_root_fs; Constructible<Genode::Directory> _root_dir { }; @@ -181,6 +182,7 @@ class Libc::Vfs_plugin final : public Plugin public: Vfs_plugin(Libc::Env &env, + Libc::File_descriptor_allocator &fd_alloc, Vfs::Env &vfs_env, Genode::Allocator &alloc, Vfs::Read_ready_response_handler &handler, @@ -188,6 +190,7 @@ class Libc::Vfs_plugin final : public Plugin Current_real_time ¤t_real_time, Xml_node config) : + _fd_alloc(fd_alloc), _alloc(alloc), _root_fs(env.vfs_env().root_dir()), _response_handler(handler), diff --git a/repos/libports/src/lib/libc/kernel.cc b/repos/libports/src/lib/libc/kernel.cc index e37fee0a93..25870f1ee1 100644 --- a/repos/libports/src/lib/libc/kernel.cc +++ b/repos/libports/src/lib/libc/kernel.cc @@ -282,7 +282,7 @@ void Libc::Kernel::_init_file_descriptors() /* prevent use of IDs of stdin, stdout, and stderr for other files */ for (unsigned fd = 0; fd <= 2; fd++) - file_descriptor_allocator()->preserve(fd); + _fd_alloc.preserve(fd); } /** @@ -308,7 +308,7 @@ void Libc::Kernel::_init_file_descriptors() * Watch stdout's 'info' pseudo file to detect terminal-resize events */ File_descriptor const * const stdout_fd = - file_descriptor_allocator()->find_by_libc_fd(STDOUT_FILENO); + _fd_alloc.find_by_libc_fd(STDOUT_FILENO); with_ioctl_path(stdout_fd, "info", [&] (Directory &root_dir, char const *path) { _terminal_resize_handler.construct(root_dir, path, *this, @@ -318,7 +318,7 @@ void Libc::Kernel::_init_file_descriptors() * Watch stdin's 'interrupts' pseudo file to detect control-c events */ File_descriptor const * const stdin_fd = - file_descriptor_allocator()->find_by_libc_fd(STDIN_FILENO); + _fd_alloc.find_by_libc_fd(STDIN_FILENO); with_ioctl_path(stdin_fd, "interrupts", [&] (Directory &root_dir, char const *path) { _user_interrupt_handler.construct(root_dir, path, @@ -466,10 +466,13 @@ void Libc::execute_in_application_context(Application_code &app_code) } +static Libc::File_descriptor_allocator *_atexit_fd_alloc_ptr; + + static void close_file_descriptors_on_exit() { for (;;) { - int const fd = Libc::file_descriptor_allocator()->any_open_fd(); + int const fd = _atexit_fd_alloc_ptr->any_open_fd(); if (fd == -1) break; close(fd); @@ -483,6 +486,7 @@ Libc::Kernel::Kernel(Genode::Env &env, Genode::Allocator &heap) { init_atexit(_atexit); + _atexit_fd_alloc_ptr = &_fd_alloc; atexit(close_file_descriptors_on_exit); init_semaphore_support(_timer_accessor); @@ -499,20 +503,23 @@ Libc::Kernel::Kernel(Genode::Env &env, Genode::Allocator &heap) init_malloc(*_malloc_heap); } - init_fork(_env, _libc_env, _heap, *_malloc_heap, _pid, *this, _signal, - _binary_name); - init_execve(_env, _heap, _user_stack, *this, _binary_name, - *file_descriptor_allocator()); + init_fork(_env, _fd_alloc, _libc_env, _heap, *_malloc_heap, _pid, *this, + _signal, _binary_name); + init_execve(_env, _heap, _user_stack, *this, _binary_name, _fd_alloc); init_plugin(*this); init_sleep(*this); init_vfs_plugin(*this, _env.rm()); - init_file_operations(*this, _libc_env); + init_file_operations(*this, _fd_alloc, _libc_env); + init_pread_pwrite(_fd_alloc); init_time(*this, *this); - init_poll(_signal, *this); + init_alarm(_timer_accessor, _signal); + init_poll(_signal, *this, _fd_alloc); init_select(*this); - init_socket_fs(*this, *this); + init_socket_fs(*this, *this, _fd_alloc); + init_socket_operations(_fd_alloc); init_passwd(_passwd_config()); init_signal(_signal); + init_kqueue(_heap, *this, _fd_alloc); _init_file_descriptors(); diff --git a/repos/libports/src/lib/libc/kqueue.cc b/repos/libports/src/lib/libc/kqueue.cc new file mode 100644 index 0000000000..9712166419 --- /dev/null +++ b/repos/libports/src/lib/libc/kqueue.cc @@ -0,0 +1,565 @@ +/* + * \brief kqueue/kevent implementation + * \author Benjamin Lamowski + * \date 2024-06-12 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* Libc includes */ +#include <sys/event.h> +#include <errno.h> +#include <assert.h> + +/* internal includes */ +#include <internal/fd_alloc.h> +#include <internal/file.h> +#include <internal/kernel.h> +#include <internal/monitor.h> +#include <internal/kqueue.h> +#include <sys/poll.h> + +/* Genode includes */ +#include <base/mutex.h> +#include <util/avl_tree.h> +#include <util/register.h> + +using namespace Libc; + +namespace Libc { + class Kqueue; + + bool read_ready_from_kernel(File_descriptor *); + void notify_read_ready_from_kernel(File_descriptor *); + bool write_ready_from_kernel(File_descriptor *); +} + +namespace { using Fn = Libc::Monitor::Function_result; } + + +static Monitor *_monitor_ptr; +static Libc::Kqueue_plugin *_kqueue_plugin_ptr; + + +static Libc::Monitor & monitor() +{ + struct Missing_call_of_init_kqueue_support : Genode::Exception { }; + if (!_monitor_ptr) + throw Missing_call_of_init_kqueue_support(); + return *_monitor_ptr; +} + + +/* + * kqueue(2): "A kevent is identified by the (ident, filter) pair; + * there may only be one unique kevent per kqueue. + */ +bool operator==(struct kevent a, struct kevent b) +{ + return ((a.ident == b.ident) && (a.filter == b.filter)); +} + + +bool operator>(struct kevent a, struct kevent b) +{ + if (a.ident > b.ident) + return true; + if ((a.ident == b.ident) && (a.filter > b.filter)) + return true; + + return false; +} + + +static consteval int pos(int flag) +{ + for (size_t i = 0; i < sizeof(flag) * 8; i++) + if ((1 << i) & flag) + return i; +} + + +/* + * Kqueue backend implementation + */ + +struct Libc::Kqueue +{ + const unsigned short flags_whitelist = + EV_ADD | + EV_DELETE | + EV_CLEAR | + EV_ONESHOT | + EV_ENABLE | + EV_DISABLE; + + const int filter_whitelist = + EVFILT_READ | + EVFILT_WRITE; + + struct Kqueue_flags : Genode::Register<32> { + struct Add : Bitfield< pos(EV_ADD), 1> { }; + struct Delete : Bitfield< pos(EV_DELETE), 1> { }; + struct Enable : Bitfield< pos(EV_ENABLE), 1> { }; + struct Disable : Bitfield<pos(EV_DISABLE), 1> { }; + struct Clear : Bitfield< pos(EV_CLEAR), 1> { }; + struct Oneshot : Bitfield<pos(EV_ONESHOT), 1> { }; + }; + + struct Kqueue_elements; + + struct Kqueue_element : kevent, public Avl_node<Kqueue_element> + { + Kqueue_element *find_by_kevent(struct kevent const & k) + { + if (*this == k) return this; + Kqueue_element *ele = this->child(k > *this); + return ele ? ele->find_by_kevent(k) : nullptr; + } + + bool higher(Kqueue_element *e) + { + return *e > *this; + } + + /* + * Run fn arcoss the element's subtree until fn returns false. + */ + bool with_all_elements(auto const &fn) + { + if (!fn(*this)) + return false; + + if (Kqueue_element * l = child(Avl_node<Kqueue_element>::LEFT)) + if (!l->with_all_elements(fn)) + return false; + + if (Kqueue_element * r = child(Avl_node<Kqueue_element>::RIGHT)) + if (!r->with_all_elements(fn)) + return false; + + return true; + } + }; + + struct Kqueue_elements : Avl_tree<Kqueue_element> + { + bool with_any_element(auto const &fn) + { + Kqueue_element *curr_ptr = first(); + if (!curr_ptr) + return false; + + fn(*curr_ptr); + return true; + } + + template <typename FN> + auto with_element(struct kevent const & k, FN const &match_fn, auto const &no_match_fn) + -> typename Trait::Functor<decltype(&FN::operator())>::Return_type + { + Kqueue_element *ele = (this->first()) ? + this->first()->find_by_kevent(k) : + nullptr; + if (ele) + return match_fn(*ele); + else + return no_match_fn(); + } + + /* + * Run fn arcoss the tree until fn returns false. + */ + void with_all_elements(auto const &fn) const + { + if (first()) first()->with_all_elements(fn); + } + }; + + + Genode::Allocator &_alloc; + Mutex _requests_mutex; + Kqueue_elements _requests; + + /* + * Collect invalid elements for deletion. + * This needs to be done out of band because otherwise the reshuffling of the AVL tree + * might lead to missed valid events. + */ + struct Kqueue_element_container : Fifo<Kqueue_element_container>::Element + { + Kqueue_element const & ele; + Kqueue_element_container(Kqueue_element const & e) : ele(e) + { } + }; + + Fifo<Kqueue_element_container> _delete_queue; + + void _queue_for_deletion(Kqueue_element &ele) + { + Kqueue_element_container &c = *new (_alloc) Kqueue_element_container(ele); + _delete_queue.enqueue(c); + } + + /* + * This may be called only when we can safely reshuffle the AVL tree + */ + void _delete_elements() + { + auto cancel_fn = [&](Kqueue_element_container& c) { + /* At this point we are sure that we can reshuffle the AVL tree. */ + Kqueue_element * non_const_ptr = &(const_cast<Kqueue_element &>(c.ele)); + _requests.remove(non_const_ptr); + destroy(_alloc, non_const_ptr); + destroy(_alloc, &c); + }; + + { + Mutex::Guard guard(_requests_mutex); + _delete_queue.dequeue_all(cancel_fn); + } + } + + int _add_event(struct kevent const& k) + { + if (k.filter & ~filter_whitelist) { + warning("kqueue: filter not implemented: ", k.filter); + return EINVAL; + } + + Kqueue_element *ele = new (_alloc) Kqueue_element(k); + { + Mutex::Guard guard(_requests_mutex); + _requests.insert(ele); + } + + return 0; + } + + int _delete_event(struct kevent const& k) + { + Mutex::Guard guard(_requests_mutex); + + auto match_fn = [&](Kqueue_element & ele) { + /* Since we know we won't match another element, we can safely remove the element here. */ + _requests.remove(&ele); + destroy(_alloc, &ele); + + return 0; + }; + + auto no_match_fn = [&]() { + error("kqueue: did not find kevent to delete: ident: ", k.ident, " filter: ", k.filter); + return EINVAL; + }; + + return _requests.with_element(k, match_fn, no_match_fn); + } + + int _enable_event(struct kevent const& k) + { + auto match_fn = [&](Kqueue_element & ele) { + Kqueue_flags::Disable::clear((Kqueue_flags::access_t &)ele.flags); + Kqueue_flags::Enable::set((Kqueue_flags::access_t &)ele.flags); + return 0; + }; + + auto no_match_fn = [&]() { + error("kqueue: did not find kevent to enable: ident: ", k.ident, " filter: ", k.filter); + return EINVAL; + }; + + return _requests.with_element(k, match_fn, no_match_fn); + } + + int _disable_event(struct kevent const& k) + { + auto match_fn = [&](Kqueue_element & ele) { + Kqueue_flags::Enable::clear((Kqueue_flags::access_t &)ele.flags); + Kqueue_flags::Disable::set((Kqueue_flags::access_t &)ele.flags); + return 0; + }; + + auto no_match_fn = [&]() { + error("kqueue: did not find kevent to disable: ident: ", k.ident, " filter: ", k.filter); + return EINVAL; + }; + + return _requests.with_element(k, match_fn, no_match_fn); + } + + Kqueue(Genode::Allocator & alloc) : _alloc(alloc) + { } + + ~Kqueue() + { + auto destroy_fn = [&] (Kqueue_element &e) { + _requests.remove(&e); + destroy(_alloc, &e); }; + while (_requests.with_any_element(destroy_fn)); + } + + int process_events(const struct kevent * changelist, int nchanges, + struct kevent * eventlist, int nevents) + { + int num_errors { 0 }; + + for (int i = 0; i < nchanges; i++) { + const int flags = changelist[i].flags; + int err { 0 }; + + if (flags & ~flags_whitelist) { + error("kqueue: unsupported flags detected: ", flags & ~flags_whitelist); + return Errno(EINVAL); + } + + if (Kqueue_flags::Add::get(flags)) + err = _add_event(changelist[i]); + else if (Kqueue_flags::Delete::get(flags)) + err = _delete_event(changelist[i]); + else if (Kqueue_flags::Enable::get(flags)) + err = _enable_event(changelist[i]); + else if (Kqueue_flags::Disable::get(flags)) + err = _disable_event(changelist[i]); + /* We ignore setting EV_CLEAR for now. */ + + if (err) { + if (num_errors < nevents) { + eventlist[num_errors] = changelist[i]; + eventlist[num_errors].flags = EV_ERROR; + eventlist[num_errors].data = err; + num_errors++; + } else { + return Errno(err); + } + } + } + + return num_errors; + } + + int collect_completed_events(struct kevent * eventlist, int nevents, const struct timespec *timeout) + { + if (nevents == 0) + return 0; + + /* + * event collection mode depending ont 'timeout' + * + * - timeout pointer == nullptr ... block infinitely for events + * - timeout value == 0 ... poll for events and return + * immediately + * - timeout value != 0 ... block for events but don't return + * later than timeout + */ + enum class Mode { INFINITE, POLL, TIMEOUT }; + + Mode mode = Mode::INFINITE; + uint64_t timeout_ms = 0; + + if (timeout) { + timeout_ms = timeout->tv_sec * 1000 + timeout->tv_nsec / 1000000; + mode = (timeout_ms == 0) ? Mode::POLL : Mode::TIMEOUT; + } + + int num_events { 0 }; + + auto monitor_fn = [&] () + { + /* + * kqueue(2): + * "The filter is also run when the user attempts to retrieve the kevent + * from the kqueue. If the filter indicates that the condition that triggered + * the event no longer holds, the kevent is removed from the kqueue and is + * not returned." + * + * Since we need to check the condition on retrieval anyway, we *only* check + * the condition on retrieval and not asynchronously. + */ + auto check_fn = [&](Kqueue_element &ele) { + File_descriptor *fd = libc_fd_to_fd(ele.ident, "kevent_collect"); + + /* + * kqueue(2): "Calling close() on a file descriptor will remove any + * kevents that reference the descriptor." + * + * Instead of removing the kqueue entry from close(), we collect + * invalid entries for deletion here. + */ + if (!fd || !fd->plugin || !fd->context) { + _queue_for_deletion(ele); + return true; + } + + /* + * If an event is disabled, ignore it. + */ + if (Kqueue_flags::Disable::get(ele.flags)) + return true; + + /* + * Right now we do not support tracking newly available read data via + * the clear flag, as that would entail tracking the availability of new + * data across file system implementations. For the case that a kqueue + * client sets EV_CLEAR and does not read the available data after receiving + * a kevent, this will lead to extraneous kevents for the already existing data. + */ + switch (ele.filter) { + case EVFILT_READ: + if (Libc::read_ready_from_kernel(fd)) { + eventlist[num_events] = ele; + eventlist[num_events].flags = 0; + num_events++; + } else { + Libc::notify_read_ready_from_kernel(fd); + } + break; + case EVFILT_WRITE: + if (Libc::write_ready_from_kernel(fd)) { + eventlist[num_events] = ele; + eventlist[num_events].flags = 0; + num_events++; + } + break; + default: + assert(false && "Element with unknown filter inserted"); + } + + /* Delete oneshot event */ + if (Kqueue_flags::Oneshot::get(ele.flags)) + _queue_for_deletion(ele); + + return num_events < nevents; + }; + + { + Mutex::Guard guard(_requests_mutex); + _requests.with_all_elements(check_fn); + + } + + _delete_elements(); + + if (mode != Mode::POLL && num_events == 0) + return Monitor::Function_result::INCOMPLETE; + + return Monitor::Function_result::COMPLETE; + }; + + Monitor::Result const monitor_result = + monitor().monitor(monitor_fn, timeout_ms); + + if (monitor_result == Monitor::Result::TIMEOUT) + return 0; + + return num_events; + } +}; + + +void Libc::init_kqueue(Genode::Allocator &alloc, Monitor &monitor, + File_descriptor_allocator &fd_alloc) +{ + _kqueue_plugin_ptr = new (alloc) Kqueue_plugin(alloc); + _monitor_ptr = &monitor; + _fd_alloc_ptr = &fd_alloc; +} + + +static Kqueue_plugin *kqueue_plugin() +{ + if (!_kqueue_plugin_ptr) { + error("libc kqueue not initialized - aborting"); + exit(1); + } + + return _kqueue_plugin_ptr; +} + + + +int Libc::Kqueue_plugin::create_kqueue() +{ + Kqueue *kq = new (_alloc) Kqueue(_alloc); + + Plugin_context *context = reinterpret_cast<Libc::Plugin_context *>(kq); + File_descriptor *fd = + file_descriptor_allocator()->alloc(this, context, Libc::ANY_FD); + + return fd->libc_fd; +} + + +int Libc::Kqueue_plugin::close(File_descriptor *fd) +{ + if (fd->plugin != this) + return -1; + + if (fd->context) + _alloc.free(fd->context, sizeof(Kqueue)); + + + file_descriptor_allocator()->free(fd); + + return 0; +} + + +extern "C" int +kevent(int libc_fd, const struct kevent *changelist, int nchanges, + struct kevent *eventlist, int nevents, const struct timespec *timeout) +{ + File_descriptor *fd = libc_fd_to_fd(libc_fd, "kevent"); + + if (fd->plugin != kqueue_plugin()) { + error("File descriptor not reqistered to kqueue plugin"); + return Errno(EBADF); + } + + Kqueue *kq = reinterpret_cast<Libc::Kqueue *>(fd->context); + assert(kq && "Kqueue not set in kqueue file descriptor"); + + if (nchanges < 0 || nevents < 0) + return Errno(EINVAL); + + int err { 0 }; + + if (changelist && nchanges) { + int num_errors = kq->process_events(changelist, nchanges, eventlist, nevents); + + /* + * kqueue(2): + * If an error occurs while processing an element of the + * changelist and there is enough roomin the eventlist, then the + * event will be placed in the eventlist with EV_ERROR set in + * flags and the system error in data. Otherwise, -1 will be + * returned, and errno will be set to indicate the error + * condition. + */ + if (num_errors < 0) + return -1; + + /* reduce space available in the eventlist */ + if (num_errors) { + nevents -= num_errors; + eventlist = &eventlist[num_errors]; + } + } + + if (eventlist && nevents) + err = kq->collect_completed_events(eventlist, nevents, timeout); + + return err; +} + + +extern "C" +int kqueue(void) +{ + return kqueue_plugin()->create_kqueue(); +} diff --git a/repos/libports/src/lib/libc/malloc.cc b/repos/libports/src/lib/libc/malloc.cc index 1a9e67b3b7..2998070d42 100644 --- a/repos/libports/src/lib/libc/malloc.cc +++ b/repos/libports/src/lib/libc/malloc.cc @@ -26,9 +26,6 @@ extern "C" { #include <stdlib.h> } -/* Genode-internal includes */ -#include <base/internal/unmanaged_singleton.h> - /* libc-internal includes */ #include <internal/init.h> #include <internal/clone_session.h> @@ -285,34 +282,24 @@ int posix_memalign(void **memptr, size_t alignment, size_t size) } -static Genode::Constructible<Malloc> &constructible_malloc() -{ - return *unmanaged_singleton<Genode::Constructible<Malloc> >(); -} +/* space for singleton object w/o destructor */ +static long _malloc_obj[(sizeof(Malloc) + sizeof(long))/sizeof(long)]; void Libc::init_malloc(Genode::Allocator &heap) { - - Constructible<Malloc> &_malloc = constructible_malloc(); - - _malloc.construct(heap); - - mallocator = _malloc.operator->(); + mallocator = construct_at<Malloc>(_malloc_obj, heap); } void Libc::init_malloc_cloned(Clone_connection &clone_connection) { - clone_connection.object_content(constructible_malloc()); - - mallocator = constructible_malloc().operator->(); + clone_connection.object_content(_malloc_obj); + mallocator = (Malloc *)_malloc_obj; } void Libc::reinit_malloc(Genode::Allocator &heap) { - Malloc &malloc = *constructible_malloc(); - - construct_at<Malloc>(&malloc, heap); + construct_at<Libc::Malloc>(_malloc_obj, heap); } diff --git a/repos/libports/src/lib/libc/patches/types.patch b/repos/libports/src/lib/libc/patches/types.patch index e401f6e643..d41e03e8c0 100644 --- a/repos/libports/src/lib/libc/patches/types.patch +++ b/repos/libports/src/lib/libc/patches/types.patch @@ -50,3 +50,55 @@ index 07893c6..abd2ea4 100644 typedef __int32_t __time_t; typedef __uint32_t __uintfptr_t; typedef __uint32_t __uintptr_t; +--- src/lib/libc/sys/arm64/include/_types.h ++++ src/lib/libc/sys/arm64/include/_types.h +@@ -49,7 +49,7 @@ + typedef int __int32_t; + typedef unsigned int __uint32_t; + typedef long __int64_t; +-typedef unsigned long __uint64_t; ++typedef unsigned long long __uint64_t; + + /* + * Standard type definitions. +@@ -71,11 +71,11 @@ + typedef __int16_t __int_least16_t; + typedef __int32_t __int_least32_t; + typedef __int64_t __int_least64_t; +-typedef __int64_t __ptrdiff_t; /* ptr1 - ptr2 */ ++typedef __PTRDIFF_TYPE__ __ptrdiff_t; /* ptr1 - ptr2 */ + typedef __int64_t __register_t; + typedef __int64_t __segsz_t; /* segment size (in pages) */ +-typedef __uint64_t __size_t; /* sizeof() */ +-typedef __int64_t __ssize_t; /* byte count or error */ ++typedef __SIZE_TYPE__ __size_t; /* sizeof() */ ++typedef __PTRDIFF_TYPE__ __ssize_t; /* byte count or error */ + typedef __int64_t __time_t; /* time()... */ + typedef __uint64_t __uintfptr_t; + typedef __uint64_t __uintmax_t; +--- src/lib/libc/sys/riscv/include/_types.h ++++ src/lib/libc/sys/riscv/include/_types.h +@@ -49,7 +49,7 @@ + typedef int __int32_t; + typedef unsigned int __uint32_t; + typedef long __int64_t; +-typedef unsigned long __uint64_t; ++typedef unsigned long long __uint64_t; + + /* + * Standard type definitions. +@@ -71,11 +71,11 @@ + typedef __int16_t __int_least16_t; + typedef __int32_t __int_least32_t; + typedef __int64_t __int_least64_t; +-typedef __int64_t __ptrdiff_t; /* ptr1 - ptr2 */ ++typedef __PTRDIFF_TYPE__ __ptrdiff_t; /* ptr1 - ptr2 */ + typedef __int64_t __register_t; + typedef __int64_t __segsz_t; /* segment size (in pages) */ +-typedef __uint64_t __size_t; /* sizeof() */ +-typedef __int64_t __ssize_t; /* byte count or error */ ++typedef __SIZE_TYPE__ __size_t; /* sizeof() */ ++typedef __PTRDIFF_TYPE__ __ssize_t; /* byte count or error */ + typedef __int64_t __time_t; /* time()... */ + typedef __uint64_t __uintfptr_t; + typedef __uint64_t __uintmax_t; diff --git a/repos/libports/src/lib/libc/poll.cc b/repos/libports/src/lib/libc/poll.cc index 0e526559e7..1bd838cc6b 100644 --- a/repos/libports/src/lib/libc/poll.cc +++ b/repos/libports/src/lib/libc/poll.cc @@ -31,10 +31,12 @@ using namespace Libc; static Monitor *_monitor_ptr; static Libc::Signal *_signal_ptr; -void Libc::init_poll(Signal &signal, Monitor &monitor) +void Libc::init_poll(Signal &signal, Monitor &monitor, + File_descriptor_allocator &fd_alloc) { - _signal_ptr = &signal; - _monitor_ptr = &monitor; + _signal_ptr = &signal; + _monitor_ptr = &monitor; + _fd_alloc_ptr = &fd_alloc; } diff --git a/repos/libports/src/lib/libc/pread_pwrite.cc b/repos/libports/src/lib/libc/pread_pwrite.cc index 758fd540fe..0a23cc49f4 100644 --- a/repos/libports/src/lib/libc/pread_pwrite.cc +++ b/repos/libports/src/lib/libc/pread_pwrite.cc @@ -20,8 +20,9 @@ #include <unistd.h> /* libc-internal includes */ -#include <internal/fd_alloc.h> +#include <internal/init.h> #include <internal/types.h> +#include <internal/fd_alloc.h> struct Read @@ -42,13 +43,27 @@ struct Write }; +static Libc::File_descriptor_allocator *_fd_alloc_ptr; + + +void Libc::init_pread_pwrite(Libc::File_descriptor_allocator &fd_alloc) +{ + _fd_alloc_ptr = &fd_alloc; +} + + using namespace Libc; template <typename Rw_func, typename Buf_type> static ssize_t pread_pwrite_impl(Rw_func rw_func, int fd, Buf_type buf, ::size_t count, ::off_t offset) { - File_descriptor *fdesc = file_descriptor_allocator()->find_by_libc_fd(fd); + if (!_fd_alloc_ptr) { + error("missing call of init_pread_pwrite"); + return -1; + } + + File_descriptor *fdesc = _fd_alloc_ptr->find_by_libc_fd(fd); if (fdesc == 0) return -1; diff --git a/repos/libports/src/lib/libc/pthread.cc b/repos/libports/src/lib/libc/pthread.cc index 6e3c5128c7..830611f2fc 100644 --- a/repos/libports/src/lib/libc/pthread.cc +++ b/repos/libports/src/lib/libc/pthread.cc @@ -18,9 +18,6 @@ #include <util/list.h> #include <libc/allocator.h> -/* Genode-internal includes */ -#include <base/internal/unmanaged_singleton.h> - /* libc includes */ #include <errno.h> #include <pthread.h> @@ -751,11 +748,16 @@ extern "C" { /* * We create a pthread object associated to the main thread's Thread * object. We ensure the pthread object does never get deleted by - * allocating it as unmanaged_singleton. Otherwise, the static + * allocating it as unmanaged singleton '_obj'. Otherwise, the static * destruction of the pthread object would also destruct the 'Thread' * of the main thread. */ - return unmanaged_singleton<pthread>(*Thread::myself(), &pthread_myself); + static pthread_t main_pthread_t = nullptr; + if (!main_pthread_t) { + static long _obj[(sizeof(pthread) + sizeof(long))/sizeof(long)]; + main_pthread_t = construct_at<pthread>(_obj, *Thread::myself(), &pthread_myself); + } + return main_pthread_t; } typeof(pthread_self) _pthread_self @@ -950,12 +952,19 @@ extern "C" { __attribute__((alias("pthread_mutexattr_settype"))); - int pthread_mutex_init(pthread_mutex_t *mutex, - pthread_mutexattr_t const *attr) + int mutex_init(pthread_mutex_t *mutex, + pthread_mutexattr_t const *attr) { - if (!mutex) - return EINVAL; + static Mutex mutex_init_mutex { }; + Mutex::Guard guard(mutex_init_mutex); + + /* + * '*mutex' could have been initialized by a different + * thread which got the init mutex earlier. + */ + if (*mutex != PTHREAD_MUTEX_INITIALIZER) + return 0; Libc::Allocator alloc { }; @@ -966,15 +975,24 @@ extern "C" { case PTHREAD_MUTEX_ADAPTIVE_NP: *mutex = new (alloc) Pthread_mutex_normal; break; case PTHREAD_MUTEX_ERRORCHECK: *mutex = new (alloc) Pthread_mutex_errorcheck; break; case PTHREAD_MUTEX_RECURSIVE: *mutex = new (alloc) Pthread_mutex_recursive; break; - - default: - *mutex = nullptr; - return EINVAL; + default: return EINVAL; } return 0; } + int pthread_mutex_init(pthread_mutex_t *mutex, + pthread_mutexattr_t const *attr) + { + if (!mutex) + return EINVAL; + + /* mark as uninitialized for 'mutex_init()' */ + *mutex = PTHREAD_MUTEX_INITIALIZER; + + return mutex_init(mutex, attr); + } + typeof(pthread_mutex_init) _pthread_mutex_init __attribute__((alias("pthread_mutex_init"))); @@ -1001,7 +1019,7 @@ extern "C" { return EINVAL; if (*mutex == PTHREAD_MUTEX_INITIALIZER) - pthread_mutex_init(mutex, nullptr); + mutex_init(mutex, nullptr); return (*mutex)->lock(); } @@ -1016,7 +1034,7 @@ extern "C" { return EINVAL; if (*mutex == PTHREAD_MUTEX_INITIALIZER) - pthread_mutex_init(mutex, nullptr); + mutex_init(mutex, nullptr); return (*mutex)->trylock(); } @@ -1032,7 +1050,7 @@ extern "C" { return EINVAL; if (*mutex == PTHREAD_MUTEX_INITIALIZER) - pthread_mutex_init(mutex, nullptr); + mutex_init(mutex, nullptr); /* abstime must be non-null according to the spec */ return (*mutex)->timedlock(*abstimeout); @@ -1070,6 +1088,15 @@ extern "C" { sem_t signal_sem; sem_t handshake_sem; + struct Invalid_timedwait_clock { }; + + void _cleanup() + { + sem_destroy(&handshake_sem); + sem_destroy(&signal_sem); + pthread_mutex_destroy(&counter_mutex); + } + pthread_cond(clockid_t clock_id) : num_waiters(0), num_signallers(0) { pthread_mutex_init(&counter_mutex, nullptr); @@ -1077,17 +1104,12 @@ extern "C" { sem_init(&handshake_sem, 0, 0); if (sem_set_clock(&signal_sem, clock_id)) { - struct Invalid_timedwait_clock { }; + _cleanup(); throw Invalid_timedwait_clock(); } } - ~pthread_cond() - { - sem_destroy(&handshake_sem); - sem_destroy(&signal_sem); - pthread_mutex_destroy(&counter_mutex); - } + ~pthread_cond() { _cleanup(); } }; @@ -1099,17 +1121,11 @@ extern "C" { int pthread_condattr_init(pthread_condattr_t *attr) { - static Mutex condattr_init_mutex { }; - if (!attr) return EINVAL; - try { - Mutex::Guard guard(condattr_init_mutex); - Libc::Allocator alloc { }; - *attr = new (alloc) pthread_cond_attr; - return 0; - } catch (...) { return ENOMEM; } + Libc::Allocator alloc { }; + *attr = new (alloc) pthread_cond_attr; return 0; } @@ -1145,22 +1161,35 @@ extern "C" { { static Mutex cond_init_mutex { }; - if (!cond) - return EINVAL; + Mutex::Guard guard(cond_init_mutex); + + /* + * '*cond' could have been initialized by a different + * thread which got the init mutex earlier. + */ + if (*cond != PTHREAD_COND_INITIALIZER) + return 0; + + Libc::Allocator alloc { }; try { - Mutex::Guard guard(cond_init_mutex); - Libc::Allocator alloc { }; *cond = attr && *attr ? new (alloc) pthread_cond((*attr)->clock_id) : new (alloc) pthread_cond(CLOCK_REALTIME); - return 0; - } catch (...) { return ENOMEM; } + } catch (pthread_cond::Invalid_timedwait_clock) { return EINVAL; } + + return 0; } int pthread_cond_init(pthread_cond_t *__restrict cond, const pthread_condattr_t *__restrict attr) { + if (!cond) + return EINVAL; + + /* mark as uninitialized for 'cond_init()' */ + *cond = PTHREAD_COND_INITIALIZER; + return cond_init(cond, attr); } @@ -1307,52 +1336,119 @@ extern "C" { typeof(pthread_cond_broadcast) _pthread_cond_broadcast __attribute__((alias("pthread_cond_broadcast"))); +} - int pthread_once(pthread_once_t *once, void (*init_once)(void)) +/* + * This implementation is inspired by base/src/lib/cxx/guard.cc and uses the + * same terms for IN_INIT and WAITERS. + */ +struct Pthread_once +{ + using Waiters = Registry<Libc::Blockade>; + + template <typename T> + struct Waiter : T { - if (!once || ((once->state != PTHREAD_NEEDS_INIT) && - (once->state != PTHREAD_DONE_INIT))) - return EINVAL; + Waiters::Element _element; - if (!once->mutex) { - pthread_mutex_t p; - pthread_mutex_init(&p, nullptr); - if (!p) return EINVAL; + Waiter(Waiters &waiters, auto &&... args) + : T(args...), _element(waiters, *this) { } + }; - { - static Mutex mutex; - Mutex::Guard guard(mutex); + int volatile _state; /* pthread_once_t: state */ + addr_t volatile _flags; /* pthread_once_t: *mutex */ - if (!once->mutex) { - once->mutex = p; - p = nullptr; - } - } + bool _in_init() const { return _flags & 0b01; } + bool _waiters() const { return _flags & 0b10; } - /* - * If another thread concurrently allocated a mutex and was faster, - * free our mutex since it is not used. - */ - if (p) pthread_mutex_destroy(&p); - } + void _set_in_init() { _flags |= 0b01; } + void _set_waiters() { _flags |= 0b10; } - once->mutex->lock(); + /* mutex should be locked - returns true if init_once() was called */ + bool init(Mutex &mutex, void (*init_once)(void), Waiters &waiters) + { + if (_state == PTHREAD_DONE_INIT || _in_init()) + return false; - if (once->state == PTHREAD_DONE_INIT) { - once->mutex->unlock(); - return 0; - } + _set_in_init(); + mutex.release(); init_once(); + mutex.acquire(); - once->state = PTHREAD_DONE_INIT; + _state = PTHREAD_DONE_INIT; - once->mutex->unlock(); + if (_waiters()) + waiters.for_each([](Libc::Blockade &b) { b.wakeup(); }); - return 0; + return true; } - typeof(pthread_once) _pthread_once - __attribute__((alias("pthread_once"))); + /* mutex should be locked */ + void wait_for_completion(Mutex &mutex, Waiters &waiters) + { + auto block = [&] (Libc::Blockade &waiter) { + _set_waiters(); + + mutex.release(); + while (_state != PTHREAD_DONE_INIT) + waiter.block(); + mutex.acquire(); + }; + + if (Libc::Kernel::kernel().main_context()) { + Waiter<Main_blockade> w { waiters, 0 }; + block(w); + } else { + Waiter<Pthread_blockade> w { waiters, *_timer_accessor_ptr, 0 }; + block(w); + } + } +}; + +static_assert(sizeof(Pthread_once) <= sizeof(pthread_once_t)); + +/* + * Semantic of pthread_once according to the POSIX standard: + * + * - The first call to pthread_once() by any thread in a process, with a given + * 'once', shall call 'init_once' with no arguments. + * + * - Subsequent * calls of pthread_once() with the same 'once' shall not call + * the 'init_once'. + * + * - On return from pthread_once(), 'init_once' shall have completed. + * + * - 'once' shall determine whether the associated initialization routine has + * been called. + * + * - Recursive calls to pthread_once() (from 'init_once' or after longjmp()) + * will not return. + */ +extern "C" int pthread_once(pthread_once_t *once, void (*init_once)(void)) +{ + static Mutex mutex { }; + static Pthread_once::Waiters waiters { }; + + /* + * POSIX states: The [EINVAL] error for an uninitialized pthread_once_t + * object is removed; this condition results in undefined behavior. + */ + if (!once || ((once->state != PTHREAD_NEEDS_INIT) && + (once->state != PTHREAD_DONE_INIT))) + return EINVAL; + + Mutex::Guard guard(mutex); + + if (once->state == PTHREAD_DONE_INIT) + return 0; + + Pthread_once &o = *(Pthread_once *)once; + if (!o.init(mutex, init_once, waiters)) + o.wait_for_completion(mutex, waiters); + + return 0; } + +extern "C" typeof(pthread_once) _pthread_once __attribute__((alias("pthread_once"))); diff --git a/repos/libports/src/lib/libc/rwlock.cc b/repos/libports/src/lib/libc/rwlock.cc index e29626b682..e4b1c87b7d 100644 --- a/repos/libports/src/lib/libc/rwlock.cc +++ b/repos/libports/src/lib/libc/rwlock.cc @@ -104,20 +104,30 @@ extern "C" { { static Mutex rwlock_init_mutex { }; - if (!rwlock) - return EINVAL; + Mutex::Guard g(rwlock_init_mutex); - try { - Mutex::Guard g(rwlock_init_mutex); - Libc::Allocator alloc { }; - *rwlock = new (alloc) struct pthread_rwlock(); + /* + * '*rwlock' could have been initialized by a different + * thread which got the init mutex earlier. + */ + if (*rwlock != PTHREAD_RWLOCK_INITIALIZER) return 0; - } catch (...) { return ENOMEM; } + + Libc::Allocator alloc { }; + *rwlock = new (alloc) struct pthread_rwlock(); + + return 0; } int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr) { + if (!rwlock) + return EINVAL; + + /* mark as uninitialized for 'rwlock_init()' */ + *rwlock = PTHREAD_RWLOCK_INITIALIZER; + return rwlock_init(rwlock, attr); } @@ -142,8 +152,7 @@ extern "C" { return EINVAL; if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) - if (rwlock_init(rwlock, NULL)) - return ENOMEM; + rwlock_init(rwlock, NULL); (*rwlock)->rdlock(); return 0; @@ -159,8 +168,7 @@ extern "C" { return EINVAL; if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) - if (rwlock_init(rwlock, NULL)) - return ENOMEM; + rwlock_init(rwlock, NULL); (*rwlock)->wrlock(); return 0; diff --git a/repos/libports/src/lib/libc/signal.cc b/repos/libports/src/lib/libc/signal.cc index 570c36db3d..76e465d0cc 100644 --- a/repos/libports/src/lib/libc/signal.cc +++ b/repos/libports/src/lib/libc/signal.cc @@ -250,10 +250,7 @@ extern "C" int sigaltstack(stack_t const * const ss, stack_t * const old_ss) warning("leaking secondary stack memory"); } else { - if (ss->ss_sp) - warning(__func__, " using self chosen stack is not" - " supported - stack ptr is ignored !!!"); - + /* ss->ss_sp is ignored, ever use alloc_secondary stack */ void * stack = myself->alloc_secondary_stack("sigaltstack", ss->ss_size); diff --git a/repos/libports/src/lib/libc/socket_fs_plugin.cc b/repos/libports/src/lib/libc/socket_fs_plugin.cc index f5b9b49ed7..a6dbd7e12e 100644 --- a/repos/libports/src/lib/libc/socket_fs_plugin.cc +++ b/repos/libports/src/lib/libc/socket_fs_plugin.cc @@ -56,10 +56,12 @@ static Libc::Suspend *_suspend_ptr; static Libc::Monitor *_monitor_ptr; -void Libc::init_socket_fs(Suspend &suspend, Monitor &monitor) +void Libc::init_socket_fs(Suspend &suspend, Monitor &monitor, + File_descriptor_allocator &fd_alloc) { - _suspend_ptr = &suspend; - _monitor_ptr = &monitor; + _suspend_ptr = &suspend; + _monitor_ptr = &monitor; + _fd_alloc_ptr = &fd_alloc; } diff --git a/repos/libports/src/lib/libc/socket_operations.cc b/repos/libports/src/lib/libc/socket_operations.cc index dcd0467530..34309fdcda 100644 --- a/repos/libports/src/lib/libc/socket_operations.cc +++ b/repos/libports/src/lib/libc/socket_operations.cc @@ -28,6 +28,13 @@ extern "C" { #include <internal/file.h> #include <internal/socket_fs_plugin.h> #include <internal/errno.h> +#include <internal/init.h> + + +void Libc::init_socket_operations(Libc::File_descriptor_allocator &fd_alloc) +{ + _fd_alloc_ptr = &fd_alloc; +} using namespace Libc; diff --git a/repos/libports/src/lib/libc/time.cc b/repos/libports/src/lib/libc/time.cc index 80667ff351..76b88d19dd 100644 --- a/repos/libports/src/lib/libc/time.cc +++ b/repos/libports/src/lib/libc/time.cc @@ -16,9 +16,6 @@ #include <base/log.h> #include <vfs/vfs_handle.h> -/* Genode-internal includes */ -#include <base/internal/unmanaged_singleton.h> - /* libc includes */ #include <sys/time.h> #include <sys/types.h> diff --git a/repos/libports/src/lib/libc/vfs_plugin.cc b/repos/libports/src/lib/libc/vfs_plugin.cc index d12acda2ef..d51db16ec4 100644 --- a/repos/libports/src/lib/libc/vfs_plugin.cc +++ b/repos/libports/src/lib/libc/vfs_plugin.cc @@ -220,6 +220,13 @@ namespace Libc { return handle->fs().read_ready(*handle); } + void notify_read_ready_from_kernel(File_descriptor *fd) + { + Vfs::Vfs_handle *handle = vfs_handle(fd); + if (handle) + handle->fs().notify_read_ready(handle); + } + bool write_ready_from_kernel(File_descriptor *fd) { Vfs::Vfs_handle const *handle = vfs_handle(fd); @@ -297,8 +304,7 @@ Libc::File_descriptor *Libc::Vfs_plugin::open_from_kernel(const char *path, int /* the directory was successfully opened */ - File_descriptor *fd = - file_descriptor_allocator()->alloc(this, vfs_context(handle), libc_fd); + File_descriptor *fd = _fd_alloc.alloc(this, vfs_context(handle), libc_fd); if (!fd) { handle->close(); @@ -376,8 +382,7 @@ Libc::File_descriptor *Libc::Vfs_plugin::open_from_kernel(const char *path, int /* the file was successfully opened */ - File_descriptor *fd = - file_descriptor_allocator()->alloc(this, vfs_context(handle), libc_fd); + File_descriptor *fd = _fd_alloc.alloc(this, vfs_context(handle), libc_fd); if (!fd) { handle->close(); @@ -429,7 +434,7 @@ Libc::File_descriptor *Libc::Vfs_plugin::open(char const *path, int flags) /* the directory was successfully opened */ - fd = file_descriptor_allocator()->alloc(this, vfs_context(handle), Libc::ANY_FD); + fd = _fd_alloc.alloc(this, vfs_context(handle), Libc::ANY_FD); if (!fd) { handle->close(); @@ -508,7 +513,7 @@ Libc::File_descriptor *Libc::Vfs_plugin::open(char const *path, int flags) /* the file was successfully opened */ - fd = file_descriptor_allocator()->alloc(this, vfs_context(handle), Libc::ANY_FD); + fd = _fd_alloc.alloc(this, vfs_context(handle), Libc::ANY_FD); if (!fd) { handle->close(); @@ -598,7 +603,7 @@ int Libc::Vfs_plugin::close_from_kernel(File_descriptor *fd) } handle->close(); - file_descriptor_allocator()->free(fd); + _fd_alloc.free(fd); return 0; } @@ -616,7 +621,7 @@ int Libc::Vfs_plugin::close(File_descriptor *fd) return Fn::INCOMPLETE; handle->close(); - file_descriptor_allocator()->free(fd); + _fd_alloc.free(fd); return Fn::COMPLETE; }); @@ -674,8 +679,7 @@ Libc::File_descriptor *Libc::Vfs_plugin::dup(File_descriptor *fd) handle->seek(vfs_handle(fd)->seek()); handle->handler(&_response_handler); - File_descriptor * const new_fd = - file_descriptor_allocator()->alloc(this, vfs_context(handle)); + File_descriptor * const new_fd = _fd_alloc.alloc(this, vfs_context(handle)); if (!new_fd) { handle->close(); @@ -1127,6 +1131,19 @@ Libc::Vfs_plugin::_ioctl_tio(File_descriptor *fd, unsigned long request, char *a termios->c_ispeed = 0; termios->c_ospeed = 0; + handled = true; + + } else if (request == TIOCSETA) { + + /* + * As TIOCGETA above only returns the for now required + * options ignore any attempt to set them. + */ + + handled = true; + + } else if (request == TIOCFLUSH) { + handled = true; } @@ -1921,7 +1938,9 @@ int Libc::Vfs_plugin::ioctl(File_descriptor *fd, unsigned long request, char *ar switch (request) { case TIOCGWINSZ: + case TIOCFLUSH: case TIOCGETA: + case TIOCSETA: result = _ioctl_tio(fd, request, argp); break; case DIOCGMEDIASIZE: @@ -2037,8 +2056,7 @@ int Libc::Vfs_plugin::fcntl(File_descriptor *fd, int cmd, long arg) /* * Allocate free file descriptor locally. */ - File_descriptor *new_fd = - file_descriptor_allocator()->alloc(this, 0); + File_descriptor *new_fd = _fd_alloc.alloc(this, 0); if (!new_fd) return Errno(EMFILE); /* diff --git a/repos/libports/src/lib/libdrm/ioctl_etnaviv.cc b/repos/libports/src/lib/libdrm/ioctl_etnaviv.cc index fe342cfe50..11b2269e38 100644 --- a/repos/libports/src/lib/libdrm/ioctl_etnaviv.cc +++ b/repos/libports/src/lib/libdrm/ioctl_etnaviv.cc @@ -163,7 +163,7 @@ void Etnaviv::serialize(drm_etnaviv_gem_submit *submit, char *content) }; for_each_object((drm_etnaviv_gem_submit_bo*)submit->bos, submit->nr_bos, copy_bos); - submit->bos = reinterpret_cast<__u64>(new_start); + submit->bos = __u64(new_start); } /* next are the relocs */ @@ -177,7 +177,7 @@ void Etnaviv::serialize(drm_etnaviv_gem_submit *submit, char *content) }; for_each_object((drm_etnaviv_gem_submit_reloc*)submit->relocs, submit->nr_relocs, copy_relocs); - submit->relocs = reinterpret_cast<__u64>(new_start); + submit->relocs = __u64(new_start); } /* next are the pmrs */ @@ -190,7 +190,7 @@ void Etnaviv::serialize(drm_etnaviv_gem_submit *submit, char *content) }; for_each_object((drm_etnaviv_gem_submit_pmr*)submit->pmrs, submit->nr_pmrs, copy_pmrs); - submit->pmrs = reinterpret_cast<__u64>(new_start); + submit->pmrs = __u64(new_start); } /* next is the cmd stream */ @@ -200,7 +200,7 @@ void Etnaviv::serialize(drm_etnaviv_gem_submit *submit, char *content) char * const dst = content + offset; Genode::memcpy(dst, reinterpret_cast<void const*>(submit->stream), submit->stream_size); offset += submit->stream_size; - submit->stream = reinterpret_cast<__u64>(new_start); + submit->stream = __u64(new_start); } /* copy submit object last but into the front */ @@ -266,11 +266,15 @@ namespace Etnaviv { using namespace Genode; using namespace Gpu; + struct Vram; struct Call; } /* namespace Etnaviv */ -struct Gpu::Vram +struct Gpu::Vram { }; + +/* use separate namespace for Vram implementation */ +struct Etnaviv::Vram : Gpu::Vram { struct Allocation_failed : Genode::Exception { }; @@ -346,7 +350,7 @@ class Etnaviv::Call Gpu::Vram const &_vram; Buffer(Genode::Id_space<Buffer> &space, - Gpu::Vram const &vram) + Vram const &vram) : _elem { *this, space, Genode::Id_space<Buffer>::Id { .value = vram.id().value } }, @@ -440,7 +444,7 @@ class Etnaviv::Call * required by the Gpu session to pass on the driver specific * command buffer. */ - Gpu::Vram *_exec_buffer; + Vram *_exec_buffer; public: @@ -457,8 +461,8 @@ class Etnaviv::Call _fd { _open_gpu() }, _id { _stat_gpu(_fd) }, _elem { *this, space }, - _exec_buffer { new (alloc) Gpu::Vram(_gpu, _exec_buffer_size, - _vram_space) } + _exec_buffer { new (alloc) Vram(_gpu, _exec_buffer_size, + _vram_space) } { } ~Gpu_context() @@ -486,13 +490,13 @@ class Etnaviv::Call Gpu::Vram_capability export_vram(Gpu::Vram_id id) { Gpu::Vram_capability cap { }; - _try_apply(id, [&] (Gpu::Vram const &b) { + _try_apply(id, [&] (Vram const &b) { cap = _gpu.export_vram(b.id()); }); return cap; } - Buffer *import_vram(Gpu::Vram_capability cap, Gpu::Vram const &v) + Buffer *import_vram(Gpu::Vram_capability cap, Vram const &v) { Buffer *b = nullptr; @@ -675,7 +679,7 @@ class Etnaviv::Call [&] () { _main_ctx->gpu().upgrade_ram(donate); }); - } catch (Gpu::Vram::Allocation_failed) { + } catch (Vram::Allocation_failed) { return; } diff --git a/repos/libports/src/lib/libdrm/ioctl_lima.cc b/repos/libports/src/lib/libdrm/ioctl_lima.cc index 5641676558..b71203d833 100644 --- a/repos/libports/src/lib/libdrm/ioctl_lima.cc +++ b/repos/libports/src/lib/libdrm/ioctl_lima.cc @@ -166,7 +166,7 @@ void Lima::serialize(drm_lima_gem_submit *submit, char *content) }; for_each_object((drm_lima_gem_submit_bo*)submit->bos, submit->nr_bos, copy_bos); - submit->bos = reinterpret_cast<__u64>(new_start); + submit->bos = __u64(new_start); } /* next is the frame */ @@ -176,7 +176,7 @@ void Lima::serialize(drm_lima_gem_submit *submit, char *content) char * const dst = content + offset; Genode::memcpy(dst, reinterpret_cast<void const*>(submit->frame), submit->frame_size); offset += submit->frame_size; - submit->frame = reinterpret_cast<__u64>(new_start); + submit->frame = __u64(new_start); } /* copy submit object last but into the front */ @@ -198,6 +198,7 @@ namespace Lima { using namespace Genode; using namespace Gpu; + struct Vram; struct Call; } /* namespace Lima */ @@ -205,7 +206,11 @@ namespace Lima { /* * Gpu::Vram encapsulates a buffer object allocation */ -struct Gpu::Vram + +struct Gpu::Vram { }; + +/* use separate namespace for Vram implementation */ +struct Lima::Vram : Gpu::Vram { struct Allocation_failed : Genode::Exception { }; @@ -331,10 +336,10 @@ class Lima::Call { Genode::Id_space<Buffer>::Element const _elem; - Gpu::Vram const &_vram; + Vram const &_vram; Buffer(Genode::Id_space<Buffer> &space, - Gpu::Vram const &vram) + Vram const &vram) : _elem { *this, space, Genode::Id_space<Buffer>::Id { .value = vram.id().value } }, @@ -437,7 +442,7 @@ class Lima::Call * required by the Gpu session to pass on driver specific * command buffer. */ - Gpu::Vram *_exec_buffer; + Vram *_exec_buffer; public: @@ -455,9 +460,9 @@ class Lima::Call _id { _stat_gpu(_fd) }, _elem { *this, space }, _va_alloc { va_alloc }, - _exec_buffer { new (alloc) Gpu::Vram(_gpu, _exec_buffer_size, - _va_alloc.alloc(_exec_buffer_size), - _vram_space) } + _exec_buffer { new (alloc) Vram(_gpu, _exec_buffer_size, + _va_alloc.alloc(_exec_buffer_size), + _vram_space) } { } ~Gpu_context() @@ -482,16 +487,16 @@ class Lima::Call return _gpu; } - Gpu::Vram_capability export_vram(Gpu::Vram_id id) + Gpu::Vram_capability export_vram(Vram_id id) { Gpu::Vram_capability cap { }; - _try_apply(id, [&] (Gpu::Vram const &b) { + _try_apply(id, [&] (Vram const &b) { cap = _gpu.export_vram(b.id()); }); return cap; } - Buffer *import_vram(Gpu::Vram_capability cap, Gpu::Vram const &v) + Buffer *import_vram(Gpu::Vram_capability cap, Vram const &v) { Buffer *b = nullptr; @@ -725,7 +730,7 @@ class Lima::Call (void)_apply_handle(arg.handle, [&] (Vram &b) { if (!b.mmap(_env)) return; - arg.offset = reinterpret_cast<::uint64_t>(b.mmap_addr()); + arg.offset = __u64(b.mmap_addr()); Gpu::Virtual_address const va = b.va; if (va.value == (Gpu::addr_t)-1) @@ -764,7 +769,7 @@ class Lima::Call [&] () { _main_ctx->gpu().upgrade_ram(donate); }); - } catch (Gpu::Vram::Allocation_failed) { + } catch (Vram::Allocation_failed) { _va_alloc.free(va); return; } @@ -802,7 +807,7 @@ class Lima::Call Buffer_space::Id const id = { .value = handle }; if (!gc.buffer_space_contains(id)) { - (void)_apply_handle(handle, [&] (Gpu::Vram const &v) { + (void)_apply_handle(handle, [&] (Vram const &v) { Gpu::Vram_capability cap = _main_ctx->export_vram(v.id()); if (gc.import_vram(cap, v) == nullptr) { Genode::error("could force mapping of buffer ", handle); @@ -824,7 +829,7 @@ class Lima::Call if (!gc.buffer_space_contains(id)) { bool imported = false; - (void)_apply_handle(bo.handle, [&] (Gpu::Vram const &v) { + (void)_apply_handle(bo.handle, [&] (Vram const &v) { Gpu::Vram_capability cap = _main_ctx->export_vram(v.id()); if (gc.import_vram(cap, v) == nullptr) return; @@ -986,7 +991,7 @@ class Lima::Call _gpu_context_space.for_each<Gpu_context>(free_buffer); return _apply_handle(gem_close.handle, - [&] (Gpu::Vram &b) { + [&] (Lima::Vram &b) { _va_alloc.free(b.va); destroy(_heap, &b); }) ? 0 : -1; diff --git a/repos/libports/src/lib/libusb/genode_usb_raw.cc b/repos/libports/src/lib/libusb/genode_usb_raw.cc index 57845480dd..cc4a10c05e 100644 --- a/repos/libports/src/lib/libusb/genode_usb_raw.cc +++ b/repos/libports/src/lib/libusb/genode_usb_raw.cc @@ -35,6 +35,8 @@ static int vfs_libusb_fd { -1 }; struct Usb_device { + struct No_device {}; + template <typename URB> struct Urb_tpl : URB { @@ -58,7 +60,7 @@ struct Usb_device Usb_device &_device; - Interface(Usb_device &device, uint8_t idx); + Interface(Usb_device &device, uint8_t idx, uint8_t alt = 0); void handle_events(); }; @@ -108,9 +110,10 @@ struct Usb_device }; -Usb_device::Interface::Interface(Usb_device &device, uint8_t idx) +Usb_device::Interface::Interface(Usb_device &device, uint8_t idx, uint8_t alt) : - Usb::Interface(device._device, Usb::Interface::Index{idx, 0}, (1UL << 20)), + Usb::Interface(device._device, Usb::Interface::Index{idx, alt}, + (1UL << 20)), Registry<Usb_device::Interface>::Element(device._interfaces, *this), _device(device) { @@ -167,6 +170,9 @@ void Usb_device::Interface::handle_events() /* complete USB request */ [this] (Urb &urb, Usb::Tagged_packet::Return_value v) { + if (v == Usb::Tagged_packet::NO_DEVICE) + throw No_device(); + if (v != Usb::Tagged_packet::OK) error("transfer failed, return value ", (int)v); @@ -217,6 +223,9 @@ void Usb_device::handle_events() /* complete USB request */ [this] (Urb &urb, Usb::Tagged_packet::Return_value v) { + if (v == Usb::Tagged_packet::NO_DEVICE) + throw No_device(); + if (v != Usb::Tagged_packet::OK) error("control transfer failed, return value ", (int)v); @@ -354,13 +363,17 @@ static int genode_get_device_descriptor(struct libusb_device *, unsigned char* buffer, int *host_endian) { - Usb_device::Urb urb(buffer, sizeof(libusb_device_descriptor), - device()._device, LIBUSB_REQUEST_GET_DESCRIPTOR, - LIBUSB_ENDPOINT_IN, (LIBUSB_DT_DEVICE << 8) | 0, 0, - LIBUSB_DT_DEVICE_SIZE); - device()._wait_for_urb(urb); - *host_endian = 0; - return LIBUSB_SUCCESS; + try { + Usb_device::Urb urb(buffer, sizeof(libusb_device_descriptor), + device()._device, LIBUSB_REQUEST_GET_DESCRIPTOR, + LIBUSB_ENDPOINT_IN, (LIBUSB_DT_DEVICE << 8) | 0, 0, + LIBUSB_DT_DEVICE_SIZE); + device()._wait_for_urb(urb); + *host_endian = 0; + return LIBUSB_SUCCESS; + } catch(Usb_device::No_device&) { + return LIBUSB_ERROR_NO_DEVICE; + } } @@ -370,22 +383,26 @@ static int genode_get_config_descriptor(struct libusb_device *, size_t len, int *host_endian) { - /* read minimal config descriptor */ - genode_usb_config_descriptor desc; - Usb_device::Urb cfg(&desc, sizeof(desc), device()._device, - LIBUSB_REQUEST_GET_DESCRIPTOR, LIBUSB_ENDPOINT_IN, - (LIBUSB_DT_CONFIG << 8) | idx, 0, sizeof(desc)); - device()._wait_for_urb(cfg); + try { + /* read minimal config descriptor */ + genode_usb_config_descriptor desc; + Usb_device::Urb cfg(&desc, sizeof(desc), device()._device, + LIBUSB_REQUEST_GET_DESCRIPTOR, LIBUSB_ENDPOINT_IN, + (LIBUSB_DT_CONFIG << 8) | idx, 0, sizeof(desc)); + device()._wait_for_urb(cfg); - /* read again whole configuration */ - Usb_device::Urb all(buffer, len, device()._device, - LIBUSB_REQUEST_GET_DESCRIPTOR, LIBUSB_ENDPOINT_IN, - (LIBUSB_DT_CONFIG << 8) | idx, 0, - (size_t)desc.total_length); - device()._wait_for_urb(all); + /* read again whole configuration */ + Usb_device::Urb all(buffer, len, device()._device, + LIBUSB_REQUEST_GET_DESCRIPTOR, LIBUSB_ENDPOINT_IN, + (LIBUSB_DT_CONFIG << 8) | idx, 0, + (size_t)desc.total_length); + device()._wait_for_urb(all); - *host_endian = 0; - return desc.total_length; + *host_endian = 0; + return desc.total_length; + } catch(Usb_device::No_device&) { + return 0; + } } @@ -454,80 +471,98 @@ static int genode_set_interface_altsetting(struct libusb_device_handle* dev_hand int interface_number, int altsetting) { - using P = Usb::Device::Packet_descriptor; - using Rt = P::Request_type; + try { + using P = Usb::Device::Packet_descriptor; + using Rt = P::Request_type; - if (interface_number < 0 || interface_number > 0xff || - altsetting < 0 || altsetting > 0xff) - return LIBUSB_ERROR_INVALID_PARAM; + if (interface_number < 0 || interface_number > 0xff || + altsetting < 0 || altsetting > 0xff) + return LIBUSB_ERROR_INVALID_PARAM; - Usb_device::Urb urb(nullptr, 0, device()._device, P::Request::SET_INTERFACE, - Rt::value(P::Recipient::IFACE, P::Type::STANDARD, - P::Direction::OUT), - (uint8_t)altsetting, (uint8_t)interface_number, 0); - device()._wait_for_urb(urb); - return LIBUSB_SUCCESS; + /* remove already claimed interface with old setting */ + device()._interfaces.for_each([&] (Usb_device::Interface &iface) { + if (iface.index().number == interface_number) + destroy(device()._alloc, &iface); }); + + Usb_device::Urb urb(nullptr, 0, device()._device, P::Request::SET_INTERFACE, + Rt::value(P::Recipient::IFACE, P::Type::STANDARD, + P::Direction::OUT), + (uint8_t)altsetting, (uint8_t)interface_number, 0); + device()._wait_for_urb(urb); + + /* claim interface */ + new (device()._alloc) + Usb_device::Interface(device(), (uint8_t) interface_number, + (uint8_t) altsetting); + return LIBUSB_SUCCESS; + } catch(Usb_device::No_device&) { + return LIBUSB_ERROR_NO_DEVICE; + } } static int genode_submit_transfer(struct usbi_transfer * itransfer) { - struct libusb_transfer *transfer = - USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - Usb::Interface::Packet_descriptor::Type type = - Usb::Interface::Packet_descriptor::FLUSH; + try { + struct libusb_transfer *transfer = + USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + Usb::Interface::Packet_descriptor::Type type = + Usb::Interface::Packet_descriptor::FLUSH; - switch (transfer->type) { + switch (transfer->type) { - case LIBUSB_TRANSFER_TYPE_CONTROL: { + case LIBUSB_TRANSFER_TYPE_CONTROL: { - struct libusb_control_setup *setup = - (struct libusb_control_setup*)transfer->buffer; + struct libusb_control_setup *setup = + (struct libusb_control_setup*)transfer->buffer; - void * addr = transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE; - new (device()._alloc) - Usb_device::Urb(addr, setup->wLength, itransfer, - device()._device, setup->bRequest, - setup->bmRequestType, setup->wValue, - setup->wIndex, setup->wLength, - transfer->timeout); - device().handle_events(); - return LIBUSB_SUCCESS; + void * addr = transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE; + new (device()._alloc) + Usb_device::Urb(addr, setup->wLength, itransfer, + device()._device, setup->bRequest, + setup->bmRequestType, setup->wValue, + setup->wIndex, setup->wLength, + transfer->timeout); + device().handle_events(); + return LIBUSB_SUCCESS; + } + + case LIBUSB_TRANSFER_TYPE_BULK: + case LIBUSB_TRANSFER_TYPE_BULK_STREAM: + type = Usb::Interface::Packet_descriptor::BULK; + break; + case LIBUSB_TRANSFER_TYPE_INTERRUPT: + type = Usb::Interface::Packet_descriptor::IRQ; + break; + case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: + type = Usb::Interface::Packet_descriptor::ISOC; + break; + + default: + usbi_err(TRANSFER_CTX(transfer), + "unknown endpoint type %d", transfer->type); + return LIBUSB_ERROR_INVALID_PARAM; } - case LIBUSB_TRANSFER_TYPE_BULK: - case LIBUSB_TRANSFER_TYPE_BULK_STREAM: - type = Usb::Interface::Packet_descriptor::BULK; - break; - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - type = Usb::Interface::Packet_descriptor::IRQ; - break; - case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - type = Usb::Interface::Packet_descriptor::ISOC; - break; - - default: - usbi_err(TRANSFER_CTX(transfer), - "unknown endpoint type %d", transfer->type); - return LIBUSB_ERROR_INVALID_PARAM; - } - - bool found = false; - device()._interfaces.for_each([&] (Usb_device::Interface &iface) { - iface.for_each_endpoint([&] (Usb::Endpoint &ep) { - if (found || transfer->endpoint != ep.address()) - return; - found = true; - new (device()._iface_slab) - Usb_device::Interface::Urb(transfer->buffer, transfer->length, - itransfer, iface, ep, type, - transfer->length, - transfer->num_iso_packets); - iface.handle_events(); + bool found = false; + device()._interfaces.for_each([&] (Usb_device::Interface &iface) { + iface.for_each_endpoint([&] (Usb::Endpoint &ep) { + if (found || transfer->endpoint != ep.address()) + return; + found = true; + new (device()._iface_slab) + Usb_device::Interface::Urb(transfer->buffer, transfer->length, + itransfer, iface, ep, type, + transfer->length, + transfer->num_iso_packets); + iface.handle_events(); + }); }); - }); - return found ? LIBUSB_SUCCESS : LIBUSB_ERROR_NOT_FOUND; + return found ? LIBUSB_SUCCESS : LIBUSB_ERROR_NOT_FOUND; + } catch (Usb_device::No_device&) { + return LIBUSB_ERROR_NO_DEVICE; + } } @@ -543,11 +578,15 @@ static void genode_clear_transfer_priv(struct usbi_transfer * itransfer) { } static int genode_handle_events(struct libusb_context *, struct pollfd *, POLL_NFDS_TYPE, int) { - libusb_genode_backend_signaling = false; - device().handle_events(); - device()._interfaces.for_each([&] (Usb_device::Interface &iface) { - iface.handle_events(); }); - return LIBUSB_SUCCESS; + try { + libusb_genode_backend_signaling = false; + device().handle_events(); + device()._interfaces.for_each([&] (Usb_device::Interface &iface) { + iface.handle_events(); }); + return LIBUSB_SUCCESS; + } catch(Usb_device::No_device&) { + return LIBUSB_ERROR_NO_DEVICE; + } } diff --git a/repos/libports/src/lib/mesa/files.list b/repos/libports/src/lib/mesa/files.list index 63c74aa5cc..e730d973a5 100644 --- a/repos/libports/src/lib/mesa/files.list +++ b/repos/libports/src/lib/mesa/files.list @@ -2010,6 +2010,7 @@ mesa-24.0.8/src/util/format/u_format_s3tc.c mesa-24.0.8/src/util/format/u_format_s3tc.h mesa-24.0.8/src/util/format/u_format_table.py mesa-24.0.8/src/util/format/u_format_tests.h +mesa-24.0.8/src/util/format/u_format_unpack_neon.c mesa-24.0.8/src/util/format/u_format_yuv.c mesa-24.0.8/src/util/format/u_format_yuv.h mesa-24.0.8/src/util/format/u_format_zs.c diff --git a/repos/libports/src/lib/qemu-usb/host.cc b/repos/libports/src/lib/qemu-usb/host.cc index d4f5d85e6f..005a0fe524 100644 --- a/repos/libports/src/lib/qemu-usb/host.cc +++ b/repos/libports/src/lib/qemu-usb/host.cc @@ -13,6 +13,7 @@ #include <usb_session/device.h> #include <util/list_model.h> #include <util/xml_node.h> +#include <os/backtrace.h> #include <extern_c_begin.h> #include <qemu_emul.h> @@ -244,6 +245,8 @@ class Interface : public List_model<::Interface>::Element template <typename FN> void for_each_endpoint(FN const &fn) { _endpoints.for_each([&] (Endpoint &endp) { fn(endp); }); } + + void io(); }; @@ -274,6 +277,13 @@ class Device : public List_model<Device>::Element struct Urb : Usb::Device::Urb { + /** + * Unconditionally set control transfer timeout to 1 sec, + * otherwise it can block a device forever, as we do not + * cancel control transfers yet in this backend. + */ + enum { CONTROL_XFER_TIMEOUT = 1000 }; + using Request_type = Usb::Device::Packet_descriptor::Request_type::access_t; @@ -289,7 +299,8 @@ class Device : public List_model<Device>::Element : Usb::Device::Urb(device._device, request, (Request_type)request_type, - value, index, size), + value, index, size, + CONTROL_XFER_TIMEOUT), _packet(packet) { } }; @@ -376,6 +387,8 @@ class Device : public List_model<Device>::Element _ifaces.for_each([&] (::Interface &iface) { if (iface.active()) fn(iface); }); } + + void io() { Signal_transmitter(_sigh_cap).submit(); } }; @@ -521,7 +534,7 @@ void Isoc_cache::_new_urb() sent = true; } - if (sent) _iface.update_urbs(); + if (sent) _iface.io(); } @@ -626,6 +639,12 @@ Usb::Interface &::Interface::_session() }; +void ::Interface::io() +{ + Signal_transmitter(_device.sigh_cap()).submit(); +} + + #define USB_HOST_DEVICE(obj) \ OBJECT_CHECK(USBHostDevice, (obj), TYPE_USB_HOST_DEVICE) @@ -734,15 +753,26 @@ void complete_packet(USBPacket * const p, Usb::Tagged_packet::Return_value v) usb_host_update_devices(); usb_host_update_ep(udev); } + if (p->state != USB_PACKET_ASYNC) { + error("Unexpected packet state for control xfer ", (int)p->state); + break; + } usb_generic_async_ctrl_complete(udev, p); return; case USB_ENDPOINT_XFER_BULK: case USB_ENDPOINT_XFER_INT: + if (p->state != USB_PACKET_ASYNC) { + error("Unexpected packet state for irq/bulk xfer ", (int)p->state); + break; + } usb_packet_complete(udev, p); - break; + return; default: - error("cannot produce data for unknown packet"); + error("cannot complete unknown packet type"); } + + /* unexpected outcome */ + backtrace(); } @@ -863,7 +893,7 @@ static void usb_host_handle_data(USBDevice *udev, USBPacket *p) new (_usb_session()->_alloc) ::Urb(_usb_session()->_urb_registry, iface, endp, type, usb_packet_size(p), p); - iface.update_urbs(); + iface.io(); return; case USB_ENDPOINT_XFER_ISOC: p->status = USB_RET_SUCCESS; @@ -902,13 +932,12 @@ static void usb_host_handle_control(USBDevice *udev, USBPacket *p, _usb_session()->_space.apply<Device>({ handle }, [&] (Device & device) { + p->status = USB_RET_ASYNC; new (_usb_session()->_alloc) Device::Urb(device, request & 0xff, (request >> 8) & 0xff, value, index, length, p); - device.update_urbs(); + device.io(); }); - - p->status = USB_RET_ASYNC; } diff --git a/repos/libports/src/lib/qemu-usb/webcam.cc b/repos/libports/src/lib/qemu-usb/webcam.cc index 8e07b37b7c..a557e28cf3 100644 --- a/repos/libports/src/lib/qemu-usb/webcam.cc +++ b/repos/libports/src/lib/qemu-usb/webcam.cc @@ -130,7 +130,7 @@ struct Capture_webcam /* construct/destruct capture connection and dataspace */ if (on) { _capture.construct(_env, "webcam"); - _capture->buffer(_area); + _capture->buffer({ .px = _area, .mm = { } }); _ds.construct(_env.rm(), _capture->dataspace()); } else { _ds.destruct(); diff --git a/repos/libports/src/qt6/base/target.mk b/repos/libports/src/qt6/base/target.mk index 98c6f46633..b1ba5cf803 100644 --- a/repos/libports/src/qt6/base/target.mk +++ b/repos/libports/src/qt6/base/target.mk @@ -1,5 +1,12 @@ TARGET = qt6_base.cmake_target +ifeq ($(CONTRIB_DIR),) +QT6_BASE_DIR = $(call select_from_repositories,src/lib/qt6_base) +else +QT6_BASE_PORT_DIR := $(call select_from_ports,qt6_base) +QT6_BASE_DIR = $(QT6_BASE_PORT_DIR)/src/lib/qt6_base +endif + LIBS = qt6_cmake ldso_so_support libc libm stdcxx qt6_component egl mesa base qoost INSTALL_LIBS = lib/libQt6Concurrent.lib.so \ @@ -68,7 +75,7 @@ build: cmake_prepared.tag -DFEATURE_vulkan=OFF \ -DFEATURE_reduce_relocations=OFF \ -DFEATURE_pkg_config=OFF \ - $(QT_DIR)/qtbase \ + $(QT6_BASE_DIR) \ $(QT6_OUTPUT_FILTER) @# diff --git a/repos/libports/src/qt6/declarative/target.mk b/repos/libports/src/qt6/declarative/target.mk index f23ef26ac5..5deff77b18 100644 --- a/repos/libports/src/qt6/declarative/target.mk +++ b/repos/libports/src/qt6/declarative/target.mk @@ -1,5 +1,12 @@ TARGET = qt6_declarative.cmake_target +ifeq ($(CONTRIB_DIR),) +QT6_DECLARATIVE_DIR = $(call select_from_repositories,src/lib/qt6_declarative) +else +QT6_DECLARATIVE_PORT_DIR := $(call select_from_ports,qt6_declarative) +QT6_DECLARATIVE_DIR = $(QT6_DECLARATIVE_PORT_DIR)/src/lib/qt6_declarative +endif + QT6_PORT_LIBS = libQt6Core libQt6Gui libQt6OpenGL libQt6Network libQt6Sql libQt6Test libQt6Widgets LIBS = qt6_cmake ldso_so_support libc libm mesa egl qt6_component stdcxx @@ -92,7 +99,7 @@ build: cmake_prepared.tag qt6_so_files -DCMAKE_MODULE_LINKER_FLAGS="$(GENODE_CMAKE_LFLAGS_SHLIB)" \ -DQT_QMAKE_TARGET_MKSPEC=$(QT_PLATFORM) \ -DCMAKE_INSTALL_PREFIX=/qt \ - $(QT_DIR)/qtdeclarative \ + $(QT6_DECLARATIVE_DIR) \ $(QT6_OUTPUT_FILTER) @# diff --git a/repos/libports/src/qt6/shadertools/target.mk b/repos/libports/src/qt6/shadertools/target.mk index ba16478e6d..a7b387c708 100644 --- a/repos/libports/src/qt6/shadertools/target.mk +++ b/repos/libports/src/qt6/shadertools/target.mk @@ -1,5 +1,12 @@ TARGET = qt6_shadertools.cmake_target +ifeq ($(CONTRIB_DIR),) +QT6_SHADERTOOLS_DIR = $(call select_from_repositories,src/lib/qt6_shadertools) +else +QT6_SHADERTOOLS_PORT_DIR := $(call select_from_ports,qt6_shadertools) +QT6_SHADERTOOLS_DIR = $(QT6_SHADERTOOLS_PORT_DIR)/src/lib/qt6_shadertools +endif + QT6_PORT_LIBS = libQt6Core libQt6Gui LIBS = qt6_cmake ldso_so_support libc libm egl mesa qt6_component stdcxx @@ -29,7 +36,7 @@ build: cmake_prepared.tag qt6_so_files -DCMAKE_MODULE_LINKER_FLAGS="$(GENODE_CMAKE_LFLAGS_SHLIB)" \ -DQT_QMAKE_TARGET_MKSPEC=$(QT_PLATFORM) \ -DCMAKE_INSTALL_PREFIX=/qt \ - $(QT_DIR)/qtshadertools \ + $(QT6_SHADERTOOLS_DIR) \ $(QT6_OUTPUT_FILTER) @# diff --git a/repos/libports/src/qt6/svg/target.mk b/repos/libports/src/qt6/svg/target.mk index 839d06843c..63c094c2fb 100644 --- a/repos/libports/src/qt6/svg/target.mk +++ b/repos/libports/src/qt6/svg/target.mk @@ -1,12 +1,22 @@ TARGET = qt6_svg.cmake_target +ifeq ($(CONTRIB_DIR),) +QT6_SVG_DIR = $(call select_from_repositories,src/lib/qt6_svg) +else +QT6_SVG_PORT_DIR := $(call select_from_ports,qt6_svg) +QT6_SVG_DIR = $(QT6_SVG_PORT_DIR)/src/lib/qt6_svg +endif + QT6_PORT_LIBS = libQt6Core libQt6Gui libQt6Widgets LIBS = qt6_cmake ldso_so_support libc libm egl mesa qt6_component stdcxx -INSTALL_LIBS = lib/libQt6Svg.lib.so +INSTALL_LIBS = lib/libQt6Svg.lib.so \ + lib/libQt6SvgWidgets.lib.so \ + plugins/imageformats/libqsvg.lib.so -BUILD_ARTIFACTS = $(notdir $(INSTALL_LIBS)) +BUILD_ARTIFACTS = $(notdir $(INSTALL_LIBS)) \ + qt6_libqsvg.tar build: cmake_prepared.tag qt6_so_files @@ -29,7 +39,7 @@ build: cmake_prepared.tag qt6_so_files -DCMAKE_MODULE_LINKER_FLAGS="$(GENODE_CMAKE_LFLAGS_SHLIB)" \ -DQT_QMAKE_TARGET_MKSPEC=$(QT_PLATFORM) \ -DCMAKE_INSTALL_PREFIX=/qt \ - $(QT_DIR)/qtsvg \ + $(QT6_SVG_DIR) \ $(QT6_OUTPUT_FILTER) @# @@ -66,6 +76,12 @@ build: cmake_prepared.tag qt6_so_files ln -sf $(CURDIR)/install/qt/$${LIB}.debug $(PWD)/debug/; \ done + @# + @# create tar archives + @# + + $(VERBOSE)tar chf $(PWD)/bin/qt6_libqsvg.tar $(TAR_OPT) --transform='s/\.stripped//' -C install qt/plugins/imageformats/libqsvg.lib.so.stripped + .PHONY: build QT6_TARGET_DEPS = build diff --git a/repos/libports/src/test/libc_alarm/main.c b/repos/libports/src/test/libc_alarm/main.c new file mode 100644 index 0000000000..e5a61d9c56 --- /dev/null +++ b/repos/libports/src/test/libc_alarm/main.c @@ -0,0 +1,52 @@ +/* + * \brief Libc alarm test + * \author Norman Feske + * \date 2024-08-30 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#include <signal.h> +#include <unistd.h> +#include <stdio.h> + +static unsigned triggered_alarms; + +static void sigalarm_handler(int) +{ + triggered_alarms++; +} + +int main(int, char **) +{ + static struct sigaction sa; + sa.sa_handler = sigalarm_handler; + + int ret = sigaction(SIGALRM, &sa, NULL); + if (ret < 0) { + printf("sigaction unexpectedly returned %d\n", ret); + return 1; + } + + signal(SIGALRM, sigalarm_handler); + + unsigned observed_alarms = 0; + + alarm(2); + + while (observed_alarms != 3) { + sleep(1); + printf("triggered_alarms=%u\n", triggered_alarms); + + if (triggered_alarms != observed_alarms) { + observed_alarms = triggered_alarms; + alarm(2); + } + } + return 0; +} diff --git a/repos/libports/src/test/libc_alarm/target.mk b/repos/libports/src/test/libc_alarm/target.mk new file mode 100644 index 0000000000..77a61b5d6e --- /dev/null +++ b/repos/libports/src/test/libc_alarm/target.mk @@ -0,0 +1,3 @@ +TARGET = test-libc_alarm +SRC_C = main.c +LIBS = posix diff --git a/repos/libports/src/test/libc_kqueue/kqueue.c b/repos/libports/src/test/libc_kqueue/kqueue.c new file mode 100644 index 0000000000..d0de8bbf1c --- /dev/null +++ b/repos/libports/src/test/libc_kqueue/kqueue.c @@ -0,0 +1,505 @@ +/* + * \brief kqueue test + * \author Benjamin Lamowski + * \date 2024-08-20 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* + * Note that our kqueue implementation does support EV_CLEAR + * for EVFILT_READ and EVFILT_WRITE, + */ + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include <sys/event.h> + +/* + * Information about the test. + */ +struct Test_info { + char const *name; /* Name of the test */ + char const *path; /* Path of the file to open */ + int open_flags; /* Flags for opening the file */ + int filter; /* kqueue filter */ + int flags; /* kqueue flags */ +}; + + +/* + * Structure to pass around open file descriptors. + */ +struct Fildes { + int fd; + int kq; +}; + + +/* + * Set up a kqueue, open the file and insert the initial kevent. + */ +int bringup(struct Test_info *test, struct Fildes *fildes) +{ + int ret = 0; + struct kevent event; + + fildes->kq = kqueue(); + if (fildes->kq == -1) { + printf("%s: Failed to create kqueue: %s\n", test->name, + strerror(errno)); + return ret; + } + + + fildes->fd = open(test->path, test->open_flags); + + if (fildes->fd == -1) { + close(fildes->kq); + printf("%s: Failed to open file %s: %s\n", test->name, + test->path, strerror(errno)); + + return ret; + } + + EV_SET(&event, fildes->fd, test->filter, test->flags, 0, 0, NULL); + + ret = kevent(fildes->kq, &event, 1, NULL, 0, NULL); + if (ret) { + close(fildes->fd); + close(fildes->kq); + printf("%s: Failed to register event: %s\n", + test->name, strerror(errno)); + return ret; + } + + return 0; +} + + +/* + * Get a result from the kqueue and close the file descriptors. + */ +int get_result(struct Test_info *test, struct Fildes *fildes) +{ + int ret = 0; + struct kevent result; + ret = kevent(fildes->kq, NULL, 0, &result, 1, NULL); + if (ret == -1) { + close(fildes->fd); + close(fildes->kq); + printf("%s: Failed to retrieve result: %s\n", test->name, + strerror(errno)); + return ret; + } + + close(fildes->fd); + close(fildes->kq); + + if (ret > 0) { + if (result.flags & EV_ERROR) { + printf("%s: ", test->name); + printf("%s: Event indcated failure: %s\n", test->name, + strerror(result.data)); + return -1; + } else { + printf("%s: Test successful.\n", test->name); + return 0; + } + } + + return 0; +} + + +/* + * Test getting a kevent if a file can be written to. + */ +int test_write() +{ + int ret = 0; + struct Test_info test = { + "Write test", + "/dev/log", + O_WRONLY, + EVFILT_WRITE, + EV_ADD + }; + struct Fildes fildes; + ret = bringup(&test, &fildes); + if (ret) + return ret; + + return get_result(&test, &fildes); +} + + +/* + * Test getting a kevent if a file can be read. + */ +int test_read() +{ + int ret = 0; + struct Test_info test = { + "Read test", + "/dev/rtc", + O_RDONLY, + EVFILT_READ, + EV_ADD + }; + struct Fildes fildes; + ret = bringup(&test, &fildes); + if (ret) + return ret; + + return get_result(&test, &fildes); +} + + +/* + * Test deleting a queued kevent. + */ +int test_delete() +{ + int ret = 0; + struct kevent event; + struct Test_info test = { + "Cancel test", + "/dev/rtc", + O_RDONLY, + EVFILT_READ, + EV_ADD + }; + struct Fildes fildes; + const struct timespec timeout = {.tv_sec = 0, .tv_nsec = 1000000}; + ret = bringup(&test, &fildes); + if (ret) + return ret; + + /* Delete the event */ + EV_SET(&event, fildes.fd, test.filter, EV_DELETE, 0, 0, NULL); + ret = kevent(fildes.kq, &event, 1, NULL, 0, NULL); + if (ret) { + close(fildes.fd); + close(fildes.kq); + printf("%s: Failed to delete event: %s\n", test.name, + strerror(errno)); + + return ret; + } + + ret = kevent(fildes.kq, NULL, 0, &event, 1, &timeout); + if (ret == -1) { + close(fildes.fd); + close(fildes.kq); + printf("%s: Failed to retrieve result: %s\n", test.name, + strerror(errno)); + + return ret; + } + + /* + * Since we can always read /dev/rtc, wetting the results will only + * timeout if the event has been deleted sucessfuly. + */ + if (ret == 0) { + printf("%s: Test successful.\n", test.name); + return 0; + } else { + printf("%s: Event was not deleted: %s\n", test.name, + strerror(errno)); + + return -1; + } +} + + +/* + * Test repeating a non-oneshot event. + */ +int test_repeat() +{ + int ret = 0; + struct Test_info test = { + "Repeat test", + "/dev/rtc", + O_RDONLY, + EVFILT_READ, + EV_ADD + }; + struct Fildes fildes; + struct kevent event1, event2; + + ret = bringup(&test, &fildes); + if (ret) + return ret; + + ret = kevent(fildes.kq, NULL, 0, &event1, 1, NULL); + if (ret == -1) { + close(fildes.fd); + close(fildes.kq); + printf("%s: Failed to retrieve result 1: %s\n", test.name, + strerror(errno)); + + return ret; + } + + ret = kevent(fildes.kq, NULL, 0, &event2, 1, NULL); + + close(fildes.fd); + close(fildes.kq); + + switch (ret) { + case 1: + printf("%s: Test successful.\n", test.name); + return 0; + case -1: + printf("%s: Failed to retrieve result 2: %s\n", + test.name, strerror(errno)); + break; + default: + printf("%s: Non-oneshot event was not repeated: %s\n", + test.name, strerror(errno)); + return -1; + } + + return ret; +} + + +/* + * Test queuing a oneshot event. + */ +int test_oneshot() +{ + int ret = 0; + struct Test_info test = { + "Oneshot test", + "/dev/rtc", + O_RDONLY, + EVFILT_READ, + EV_ADD | EV_ONESHOT + }; + struct Fildes fildes; + const struct timespec timeout = {.tv_sec = 0, .tv_nsec = 1000000}; + struct kevent event1, event2; + + ret = bringup(&test, &fildes); + if (ret) + return ret; + + ret = kevent(fildes.kq, NULL, 0, &event1, 1, NULL); + if (ret == -1) { + close(fildes.fd); + close(fildes.kq); + printf("%s: Failed to retrieve result 1: %s\n", test.name, + strerror(errno)); + return ret; + } + + ret = kevent(fildes.kq, NULL, 0, &event2, 1, &timeout); + if (ret == -1) { + close(fildes.fd); + close(fildes.kq); + printf("%s: Failed to retrieve result 2: %s\n", test.name, + strerror(errno)); + return ret; + } + + if (ret == 0) { + printf("%s: Test successful.\n", test.name); + return 0; + } else { + printf("%s: Oneshot event was repeated: %s\n", test.name, + strerror(errno)); + + return -1; + } +} + + +/* + * Test disabling a queued event. + */ +int test_disable() +{ + int ret = 0; + struct Test_info test = { + "Disable test", + "/dev/rtc", + O_RDONLY, + EVFILT_READ, + EV_ADD + }; + struct Fildes fildes; + const struct timespec timeout = {.tv_sec = 0, .tv_nsec = 1000000}; + struct kevent event; + + ret = bringup(&test, &fildes); + if (ret) + return ret; + + /* Disable the event */ + EV_SET(&event, fildes.fd, test.filter, EV_DISABLE, 0, 0, NULL); + ret = kevent(fildes.kq, &event, 1, NULL, 0, NULL); + if (ret) { + close(fildes.fd); + close(fildes.kq); + printf("%s: Failed to disable event: %s\n", test.name, + strerror(errno)); + return ret; + } + + ret = kevent(fildes.kq, NULL, 0, &event, 1, &timeout); + + close(fildes.fd); + close(fildes.kq); + + switch (ret) { + case 0: + printf("%s: Test successful.\n", test.name); + return 0; + case -1: + printf("%s: Failed to retrieve result: %s\n", test.name, + strerror(errno)); + return -1; + default: + printf("%s: Event was not disabled: %s\n", test.name, + strerror(errno)); + return -1; + } +} + + +/* + * Test (re-)enabling a disabled event. + */ +int test_enable() +{ + int ret = 0; + struct Test_info test = { + "Enable test", + "/dev/rtc", + O_RDONLY, + EVFILT_READ, + EV_ADD + }; + struct Fildes fildes; + const struct timespec timeout = {.tv_sec = 0, .tv_nsec = 1000000}; + struct kevent event; + + ret = bringup(&test, &fildes); + if (ret) + return ret; + + /* Disable the event */ + EV_SET(&event, fildes.fd, test.filter, EV_DISABLE, 0, 0, NULL); + ret = kevent(fildes.kq, &event, 1, NULL, 0, NULL); + if (ret) { + close(fildes.fd); + close(fildes.kq); + printf("%s: Failed to disable event: %s\n", test.name, + strerror(errno)); + + return ret; + } + + ret = kevent(fildes.kq, NULL, 0, &event, 1, &timeout); + if (ret == -1) { + close(fildes.fd); + close(fildes.kq); + printf("%s: Failed to retrieve result 2: %s\n", test.name, + strerror(errno)); + return ret; + } + + if (ret != 0) { + printf("%s: Event was not disabled: %s\n", test.name, + strerror(errno)); + return -1; + } + + /* (Re-)Enable the event */ + EV_SET(&event, fildes.fd, test.filter, EV_ENABLE, 0, 0, NULL); + ret = kevent(fildes.kq, &event, 1, NULL, 0, NULL); + if (ret) { + close(fildes.fd); + close(fildes.kq); + printf("%s: Failed to enable event: %s\n", test.name, + strerror(errno)); + return ret; + } + + return get_result(&test, &fildes); +} + + +/* + * Test queuing a disabled event. + */ +int test_queue_disabled() +{ + int ret = 0; + struct Test_info test = { + "Queue disabled test", + "/dev/rtc", + O_RDONLY, + EVFILT_READ, + EV_ADD | EV_DISABLE + }; + struct Fildes fildes; + const struct timespec timeout = {.tv_sec = 0, .tv_nsec = 1000000}; + struct kevent event; + + ret = bringup(&test, &fildes); + if (ret) + return ret; + + ret = kevent(fildes.kq, NULL, 0, &event, 1, &timeout); + + close(fildes.fd); + close(fildes.kq); + + switch (ret) { + case 0: + printf("%s: Test successful.\n", test.name); + return 0; + case -1: + printf("%s: Failed to retrieve result: %s\n", test.name, + strerror(errno)); + return -1; + default: + printf("%s: Event was not disabled: %s\n", test.name, + strerror(errno)); + return -1; + } +} + + +int main(int argc, char **argv) +{ + int retval = 0; + + retval += test_write(); + retval += test_read(); + retval += test_delete(); + retval += test_repeat(); + retval += test_oneshot(); + retval += test_disable(); + retval += test_enable(); + retval += test_queue_disabled(); + + if (!retval) + printf("--- test succeeded ---\n"); + + return retval; +} diff --git a/repos/libports/src/test/libc_kqueue/target.mk b/repos/libports/src/test/libc_kqueue/target.mk new file mode 100644 index 0000000000..100980f875 --- /dev/null +++ b/repos/libports/src/test/libc_kqueue/target.mk @@ -0,0 +1,5 @@ +TARGET = test-libc_kqueue +SRC_C = kqueue.c +LIBS = posix + +CC_CXX_WARN_STRICT = diff --git a/repos/libports/src/test/mesa_demo/eglut/eglut_genode.cc b/repos/libports/src/test/mesa_demo/eglut/eglut_genode.cc index d432ba8bf5..1ed9c8054f 100644 --- a/repos/libports/src/test/mesa_demo/eglut/eglut_genode.cc +++ b/repos/libports/src/test/mesa_demo/eglut/eglut_genode.cc @@ -57,13 +57,13 @@ struct Window : Genode_egl_window Window(Genode::Env &env, int w, int h) : - env(env), mode { .area = Gui::Area(w, h) } + env(env), mode { .area = Gui::Area(w, h), .alpha = false } { width = w; height = h; type = WINDOW; - gui.buffer(mode, false); + gui.buffer(mode); mode_change(); } @@ -82,7 +82,7 @@ struct Window : Genode_egl_window void refresh() { - gui.framebuffer.refresh(0, 0, mode.area.w, mode.area.h); + gui.framebuffer.refresh({ { 0, 0 }, mode.area }); } }; diff --git a/repos/libports/src/test/pthread/main.cc b/repos/libports/src/test/pthread/main.cc index bf7a9e406c..a9f6e89c45 100644 --- a/repos/libports/src/test/pthread/main.cc +++ b/repos/libports/src/test/pthread/main.cc @@ -25,6 +25,7 @@ /* Genode includes */ #include <base/log.h> #include <base/sleep.h> +#include <cpu/atomic.h> struct Thread_args { @@ -536,7 +537,7 @@ struct Test_mutex_stress } /* stay in mutex for some time */ - for (unsigned volatile d = 0; d < 30000; ++d) ; + for (unsigned volatile d = 0; d < 30000; ) d = d + 3; if (MUTEX_TYPE == PTHREAD_MUTEX_RECURSIVE) { _unlock(); @@ -1099,7 +1100,7 @@ static bool key_destructor_func_called = false; static void test_tls_data() { - int test; + int test = 0; if (pthread_setspecific(key, &test) != 0) { Genode::error("pthread_setspecific() failed"); @@ -1193,6 +1194,156 @@ static void test_thread_local_destructor() } +/* test_pthread_once() counters */ +static int volatile once_init, once_round, once_round_complete; + +static int inc(int volatile *counter) +{ + int next = *counter + 1; + while (!Genode::cmpxchg(counter, next - 1, next)) + next++; + return next; +} + +static void init_once1() { inc(&once_init); } +static void init_once2() { inc(&once_init); } +static void init_once3() { inc(&once_init); } + +static void init_once_nested() +{ + pthread_once_t once_nested = PTHREAD_ONCE_INIT; + + pthread_once(&once_nested, init_once1); + + inc(&once_init); +} + +struct Once_thread +{ + enum { ROUNDS = 1'000 }; + + struct Arg + { + pthread_once_t *once; + void (*init_once)(void); + }; + + unsigned _tag; + + Cond &_cond; + Mutex<PTHREAD_MUTEX_NORMAL> &_mutex; + + Arg _once1, _once2, _once3; + + pthread_t _thread; + + static void * _entry_trampoline(void *arg) + { + Once_thread *t = (Once_thread *)arg; + t->_entry(); + return nullptr; + } + + void _entry() + { + for (int i = 1; i <= ROUNDS; ++i) { + pthread_mutex_lock(_mutex.mutex()); + while (once_round != i) + pthread_cond_wait(_cond.cond(), _mutex.mutex()); + pthread_mutex_unlock(_mutex.mutex()); + + pthread_once(_once1.once, _once1.init_once); + pthread_once(_once2.once, _once2.init_once); + pthread_once(_once3.once, _once3.init_once); + + inc(&once_round_complete); + } + } + + Once_thread(unsigned tag, Cond &cond, Mutex<PTHREAD_MUTEX_NORMAL> &mutex, + Arg once1, Arg once2, Arg once3) + : _tag(tag), _cond(cond), _mutex(mutex), _once1(once1), _once2(once2), _once3(once3) + { + if (pthread_create(&_thread, 0, _entry_trampoline, this) != 0) { + printf("Error: pthread_create() failed\n"); + exit(-1); + } + } + + void join() { pthread_join(_thread, nullptr); } +}; + + +static void check_pthread_once(int num_init) +{ + if (once_init == num_init) return; + + Genode::error("unxpected pthread_once initializer call count ", + once_init, "/", num_init); + exit(-1); +} + +static void test_pthread_once() +{ + printf("main thread: test pthread_once()\n"); + + pthread_once_t once1, once2, once3; + + /* test one thread and double-init prevention */ + once_init = 0; once1 = once2 = once3 = PTHREAD_ONCE_INIT; + pthread_once(&once1, init_once1); + pthread_once(&once1, init_once1); + check_pthread_once(1); + + /* test one thread with consecutive onces */ + once_init = 0; once1 = once2 = once3 = PTHREAD_ONCE_INIT; + pthread_once(&once1, init_once1); + pthread_once(&once2, init_once2); + pthread_once(&once3, init_once3); + check_pthread_once(3); + + /* test one thread and nested pthread_once() with different onces */ + once_init = 0; once1 = once2 = once3 = PTHREAD_ONCE_INIT; + pthread_once(&once1, init_once_nested); + check_pthread_once(2); + + Cond cond; + + Mutex<PTHREAD_MUTEX_NORMAL> mutex; + + enum { NUM_THREADS = 6 }; + Once_thread threads[NUM_THREADS] = { + { 1, cond, mutex, { &once1, init_once1 }, { &once2, init_once2 }, { &once3, init_once3 } }, + { 2, cond, mutex, { &once3, init_once3 }, { &once1, init_once1 }, { &once2, init_once2 } }, + { 3, cond, mutex, { &once2, init_once2 }, { &once3, init_once3 }, { &once1, init_once1 } }, + { 4, cond, mutex, { &once1, init_once1 }, { &once2, init_once2 }, { &once3, init_once3 } }, + { 5, cond, mutex, { &once3, init_once3 }, { &once1, init_once1 }, { &once2, init_once2 } }, + { 6, cond, mutex, { &once2, init_once2 }, { &once3, init_once3 }, { &once1, init_once1 } }, + }; + + for (int i = 1; i <= Once_thread::ROUNDS; ++i) { + pthread_mutex_lock(mutex.mutex()); + + once_round = i; once_init = 0; once_round_complete = 0; + once1 = once2 = once3 = PTHREAD_ONCE_INIT; + pthread_cond_broadcast(cond.cond()); + + pthread_mutex_unlock(mutex.mutex()); + + pthread_once(&once1, init_once1); + pthread_once(&once2, init_once2); + pthread_once(&once3, init_once3); + + while (once_round_complete != NUM_THREADS) + usleep(1000); + + check_pthread_once(3); + } + + for (Once_thread &t : threads) t.join(); +} + + int main(int argc, char **argv) { printf("--- pthread test ---\n"); @@ -1212,6 +1363,7 @@ int main(int argc, char **argv) test_cleanup(); test_tls(); test_thread_local_destructor(); + test_pthread_once(); printf("--- returning from main ---\n"); return 0; diff --git a/repos/os/doc/init.txt b/repos/os/doc/init.txt deleted file mode 100644 index 532a46071c..0000000000 --- a/repos/os/doc/init.txt +++ /dev/null @@ -1,314 +0,0 @@ - - ======================================== - Configuring the init component of Genode - ======================================== - - Norman Feske - - -The Genode architecture facilitates the flexible construction of complex usage -scenarios out of Genode's components used as generic building blocks. Thanks -to the strictly hierarchic and, at the same time, recursive structure of -Genode, a parent has full control over the way, its children interact with each -other and with the parent. The init component plays a special role in that -picture. At boot time, it gets started by core, gets assigned all physical -resources, and controls the execution of all further components, which can -be further instances of init. Init's policy is driven by a configuration file, -which declares a number of children, their relationships, and resource -assignments. This document describes the configuration mechansism to steer the -policy of the init component. The configuration is described in a single XML file -called 'config' supplied via core's ROM service. - - -Configuration -############# - -At the parent-child interface, there are two operations that are subject to -policy decisions of the parent, the child announcing a service and the -child requesting a service. If a child announces a service, the parent is up -to decide if and how to make this service accessible to its other children. -When a child requests a service, the parent may deny the session request, -delegate the request to its own parent, implement the requested service -locally, or open a session at one of its other children. This decision may -depend on the requested service or session-construction arguments provided -by the child. Apart from assigning resources to children, the central -element of the policy implemented in the parent is a set of rules to -route session requests. Therefore, init's configuration concept is laid out -around components and the routing of session requests. The concept is best -illustrated by an example (the following config file can be used on Linux): - -! <config> -! <parent-provides> -! <service name="LOG"/> -! </parent-provides> -! <start name="timer"> -! <resource name="RAM" quantum="1M"/> -! <provides> <service name="Timer"/> </provides> -! </start> -! <start name="test-timer"> -! <resource name="RAM" quantum="1M"/> -! <route> -! <service name="Timer"> <child name="timer"/> </service> -! <service name="LOG"> <parent/> </service> -! </route> -! </start> -! </config> - -First, there is the declaration of services provided by the parent of the -configured init instance. In this case, we declare that the parent provides a -LOG service. For each child to start, there is a '<start>' -node describing resource assignments, declaring services provided by the child, -and holding a routing table for session requests originating from the child. -The first child is called "timer" and implements the "Timer" service. The -second component called "test-timer" is a client of the timer service. In its -routing table, we see that requests for "Timer" sessions should be routed to -the "timer" child whereas requests for "LOG" sessions should be delegated to -init's parent. Per-child service routing rules provide a flexible way to -express arbitrary client-server relationships. For example, service requests -may be transparently mediated through special policy components acting upon -session-construction arguments. There might be multiple children implementing -the same service, each addressed by different routing tables. If there is no -valid route to a requested service, the service is denied. In the example -above, the routing tables act effectively as a whitelist of services the child -is allowed to use. - -In practice, usage scenarios become more complex than the basic example, -increasing the size of routing tables. Furthermore, in many practical cases, -multiple children may use the same set of services, and require duplicated -routing tables within the configuration. In particular during development, the -elaborative specification of routing tables tend to become an inconvenience. -To alleviate this problem, there are two mechanisms, wildcards and a default -route. Instead of specifying a list of single service routes targeting the same -destination, the wildcard '<any-service>' becomes handy. For example, instead -of specifying -! <route> -! <service name="ROM"> <parent/> </service> -! <service name="RM"> <parent/> </service> -! <service name="PD"> <parent/> </service> -! <service name="CPU"> <parent/> </service> -! </route> -the following shortcut can be used: -! <route> -! <any-service> <parent/> </any-service> -! </route> -The latter version is not as strict as the first one because it permits the -child to create sessions at the parent, which were not whitelisted in the -elaborative version. Therefore, the use of wildcards is discouraged for -configuring untrusted components. Wildcards and explicit routes may be combined -as illustrated by the following example: -! <route> -! <service name="LOG"> <child name="nitlog"/> </service> -! <any-service> <parent/> </any-service> -! </route> -The routing table is processed starting with the first entry. If the route -matches the service request, it is taken, otherwise the remaining -routing-table entries are visited. This way, the explicit service route of -"LOG" sessions to "nitlog" shadows the LOG service provided by the parent. - -To emulate the traditional init policy, which allowed a child to use services -provided by arbitrary other children, there is a further wildcard called -'<any-child>'. Using this wildcard, such a policy can be expressed as follows: -! <route> -! <any-service> <parent/> </any-service> -! <any-service> <any-child/> </any-service> -! </route> -This rule would delegate all session requests referring to one of the parent's -services to the parent. If no parent service matches the session request, the -request is routed to any child providing the service. The rule can be further -reduced to: -! <route> -! <any-service> <parent/> <any-child/> </any-service> -! </route> -Potential ambiguities caused by multiple children providing the same service -are detected automatically. In this case, the ambiguity must be resolved using -an explicit route preceding the wildcards. - -To reduce the need to specify the same routing table for many children -in one configuration, there is a '<default-route>' mechanism. The default -route is declared within the '<config>' node and used for each '<start>' -entry with no '<route>' node. In particular during development, the default -route becomes handy to keep the configuration tidy and neat. - -The combination of explicit routes and wildcards is designed to scale well from -being convenient to use during development towards being highly secure at -deployment time. If only explicit rules are present in the configuration, the -permitted relationships between all components are explicitly defined and can be -easily verified. Note however that the degree those rules are enforced at the -kernel-interface level depends on the used base platform. - - -Advanced features -################# - -In addition to the service routing facility described in the previous section, -the following features are worth noting: - - -Resource quota saturation -========================= - -If a specified resource (i.e., RAM quota) exceeds the available resources. -The available resources are assigned completely to the child. This makes -it possible to assign all remaining resources to the last child by -simply specifying an overly large quantum. - - -Multiple instantiation of a single ELF binary -============================================= - -Each '<start>' node requires a unique 'name' attribute. By default, the -value of this attribute is used as file name for obtaining the ELF -binary at the parent's ROM service. If multiple instances of the same -ELF binary are needed, the binary name can be explicitly specified -using a '<binary>' sub node of the '<start>' node: -! <binary name="filename"/> -This way, the unique child names can be chosen independently from the -binary file name. - - -Nested configuration -==================== - -Each '<start>' node can host a '<config>' sub node. The content of this sub -node is provided to the child when a ROM session for the file name "config" is -requested. Thereby, arbitrary configuration parameters can be passed to the -child. For example, the following configuration starts 'timer-test' within an -init instance within another init instance. To show the flexibility of init's -service routing facility, the "Timer" session of the second-level 'timer-test' -child is routed to the timer service started at the first-level init instance. -! <config> -! <parent-provides> -! <service name="LOG"/> -! <service name="ROM"/> -! <service name="CPU"/> -! <service name="RM"/> -! <service name="PD"/> -! </parent-provides> -! <start name="timer"> -! <resource name="RAM" quantum="1M"/> -! <provides><service name="Timer"/></provides> -! </start> -! <start name="init"> -! <resource name="RAM" quantum="1M"/> -! <config> -! <parent-provides> -! <service name="Timer"/> -! <service name="LOG"/> -! </parent-provides> -! <start name="test-timer"> -! <resource name="RAM" quantum="1M"/> -! <route> -! <service name="Timer"> <parent/> </service> -! <service name="LOG"> <parent/> </service> -! </route> -! </start> -! </config> -! <route> -! <service name="Timer"> <child name="timer"/> </service> -! <service name="LOG"> <parent/> </service> -! <service name="ROM"> <parent/> </service> -! <service name="CPU"> <parent/> </service> -! <service name="RM"> <parent/> </service> -! <service name="PD"> <parent/> </service> -! </route> -! </start> -! </config> -The services ROM, CPU, RM, and PD are required by the second-level -init instance to create the timer-test component. - -As illustrated by this example, the use of the nested configuration feature -enables the construction of arbitrarily complex component trees via a single -configuration file. - - -Assigning subsystems to CPUs -============================ - -The assignment of subsystems to CPU nodes consists of two parts, the -definition of the affinity space dimensions as used for the init component, and -the association sub systems with affinity locations (relative to the affinity -space). The affinity space is configured as a sub node of the config node. For -example, the following declaration describes an affinity space of 4x2: - -! <config> -! ... -! <affinity-space width="4" height="2" /> -! ... -! </config> - -Subsystems can be constrained to parts of the affinity space using the -'<affinity>' sub node of a '<start>' entry: - -! <config> -! ... -! <start name="loader"> -! <affinity xpos="0" ypos="1" width="2" height="1" /> -! ... -! </start> -! ... -! </config> - - -Priority support -================ - -The number of CPU priorities to be distinguished by init can be specified with -'prio_levels' attribute of the '<config>' node. The value must be a power of -two. By default, no priorities are used. To assign a priority to a child -component, a priority value can be specified as 'priority' attribute of the -corresponding '<start>' node. Valid priority values lie in the range of --prio_levels + 1 (maximum priority degradation) to 0 (no priority degradation). - - -Verbosity -========= - -To ease the debugging, init can be directed to print various status information -as LOG output. To enable the verbose mode, assign the value "yes" to the -'verbose' attribute of the '<config>' node. - - -Propagation of exit events -========================== - -A component can notify its parent about its graceful exit via the exit RPC -function of the parent interface. By default, init responds to such a -notification from one of its children by merely printing a log message but -ignores it otherwise. However, there are scenarios where the exit of a -particular child should result in the exit of the entire init component. To -propagate the exit of a child to the parent of init, start nodes can host the -optional sub node '<exit>' with the attribute 'propagate' set to "yes". - -! <config> -! <start name="noux"> -! <exit propagate="yes"/> -! ... -! </start> -! </config> - -The exit value specified by the exiting child is forwarded to init's parent. - - -Using the configuration concept -############################### - -To get acquainted with the configuration format, there are two example -configuration files located at 'os/src/init/', which are both ready-to-use with -the Linux version of Genode. Both configurations produce the same scenario but -they differ in the way policy is expressed. The 'explicit_routing' -configuration is an example for the elaborative specification of all service -routes. All service requests not explicitly specified are denied. So this -policy is a whitelist enforcing mandatory access control on each session -request. The example illustrates well that such a elaborative specification is -possible in an intuitive manner. However, it is pretty comprehensive. In cases -where the elaborative specification of service routing is not fundamentally -important, in particular during development, the use of wildcards can help to -simplify the configuration. The 'wildcard' example demonstrates the use of a -default route for session-request resolution and wildcards. This variant is -less strict about which child uses which service. For development, its -simplicity is beneficial but for deployment, we recommend to remove wildcards -('<default-route>', '<any-child>', and '<any-service>') altogether. The -absence of such wildcards is easy to check automatically to ensure that service -routes are explicitly whitelisted. - -Further configuration examples can be found in the 'os/config/' directory. diff --git a/repos/os/include/audio_in_session/connection.h b/repos/os/include/audio_in_session/connection.h index 4893c80d05..fd0dd4ca62 100644 --- a/repos/os/include/audio_in_session/connection.h +++ b/repos/os/include/audio_in_session/connection.h @@ -26,13 +26,16 @@ struct Audio_in::Connection : Genode::Connection<Session>, Audio_in::Session_cli /** * Constructor * + * \param channel channel identifier (e.g., "left") + * \param label optional session label * \param progress_signal install progress signal, the client may then * call 'wait_for_progress', which is sent when the * server processed one or more packets */ - Connection(Genode::Env &env, char const *channel, bool progress_signal = false) + Connection(Genode::Env &env, char const *channel, + Label const &label = Label(), bool progress_signal = false) : - Genode::Connection<Session>(env, Label(), + Genode::Connection<Session>(env, label, Ram_quota { 10*1024 + sizeof(Stream) }, Args("channel=\"", channel, "\"")), Session_client(env.rm(), cap(), progress_signal) diff --git a/repos/os/include/audio_out_session/connection.h b/repos/os/include/audio_out_session/connection.h index 32589464b4..2ca4b5c73e 100644 --- a/repos/os/include/audio_out_session/connection.h +++ b/repos/os/include/audio_out_session/connection.h @@ -27,6 +27,7 @@ struct Audio_out::Connection : Genode::Connection<Session>, Audio_out::Session_c * Constructor * * \param channel channel identifier (e.g., "front left") + * \param label optional session label * \param alloc_signal install 'alloc_signal', the client may then use * 'wait_for_alloc' when the stream is full * \param progress_signal install progress signal, the client may then @@ -35,10 +36,11 @@ struct Audio_out::Connection : Genode::Connection<Session>, Audio_out::Session_c */ Connection(Genode::Env &env, char const *channel, + Label const &label = Label(), bool alloc_signal = true, bool progress_signal = false) : - Genode::Connection<Session>(env, Label(), + Genode::Connection<Session>(env, label, Ram_quota { 2*4096 + 2048 + sizeof(Stream) }, Args("channel=\"", channel, "\"")), Session_client(env.rm(), cap(), alloc_signal, progress_signal) diff --git a/repos/os/include/capture_session/capture_session.h b/repos/os/include/capture_session/capture_session.h index dc1fe698ea..4313c88b9a 100644 --- a/repos/os/include/capture_session/capture_session.h +++ b/repos/os/include/capture_session/capture_session.h @@ -68,18 +68,28 @@ struct Capture::Session : Genode::Session */ virtual void screen_size_sigh(Signal_context_capability) = 0; + /** + * Register signal handler informed of new data to capture + * + * A wakeup signal is delivered only after a call of 'capture_stopped'. + */ + virtual void wakeup_sigh(Signal_context_capability) = 0; + + enum class Buffer_result { OK, OUT_OF_RAM, OUT_OF_CAPS }; + + struct Buffer_attr + { + Area px; /* buffer area in pixels */ + Area mm; /* physical size in millimeters */ + }; + /** * Define dimensions of the shared pixel buffer * * The 'size' controls the server-side allocation of the shared pixel - * buffer and may affect the screen size of the GUI server. The screen - * size is bounding box of the pixel buffers of all capture clients. - * - * \throw Out_of_ram session quota does not suffice for specified - * buffer dimensions - * \throw Out_of_caps + * buffer and may affect the screen size of the GUI server. */ - virtual void buffer(Area size) = 0; + virtual Buffer_result buffer(Buffer_attr) = 0; /** * Request dataspace of the shared pixel buffer defined via 'buffer' @@ -111,9 +121,24 @@ struct Capture::Session : Genode::Session * * \return geometry information about the content that changed since the * previous call of 'capture_at' + * + * A client should call 'capture_at' at intervals between 10 to 40 ms + * (25-100 FPS). Should no change happen for more than 50 ms, the client + * may stop the periodic capturing and call 'capture_stopped' once. As soon + * as new changes becomes available for capturing, a wakeup signal tells + * the client to resume the periodic capturing. + * + * The nitpicker GUI server reflects 'capture_at' calls as 'sync' signals + * to its GUI clients, which thereby enables applications to synchronize + * their output to the display's refresh rate. */ virtual Affected_rects capture_at(Point) = 0; + /** + * Schedule wakeup signal + */ + virtual void capture_stopped() = 0; + /********************* ** RPC declaration ** @@ -121,13 +146,14 @@ struct Capture::Session : Genode::Session GENODE_RPC(Rpc_screen_size, Area, screen_size); GENODE_RPC(Rpc_screen_size_sigh, void, screen_size_sigh, Signal_context_capability); - GENODE_RPC_THROW(Rpc_buffer, void, buffer, - GENODE_TYPE_LIST(Out_of_ram, Out_of_caps), Area); + GENODE_RPC(Rpc_wakeup_sigh, void, wakeup_sigh, Signal_context_capability); + GENODE_RPC(Rpc_buffer, Buffer_result, buffer, Buffer_attr); GENODE_RPC(Rpc_dataspace, Dataspace_capability, dataspace); GENODE_RPC(Rpc_capture_at, Affected_rects, capture_at, Point); + GENODE_RPC(Rpc_capture_stopped, void, capture_stopped); - GENODE_RPC_INTERFACE(Rpc_screen_size, Rpc_screen_size_sigh, Rpc_buffer, - Rpc_dataspace, Rpc_capture_at); + GENODE_RPC_INTERFACE(Rpc_screen_size, Rpc_screen_size_sigh, Rpc_wakeup_sigh, + Rpc_buffer, Rpc_dataspace, Rpc_capture_at, Rpc_capture_stopped); }; #endif /* _INCLUDE__CAPTURE_SESSION__CAPTURE_SESSION_H_ */ diff --git a/repos/os/include/capture_session/client.h b/repos/os/include/capture_session/client.h deleted file mode 100644 index bf032d8d9f..0000000000 --- a/repos/os/include/capture_session/client.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * \brief Client-side capture session interface - * \author Norman Feske - * \date 2020-06-26 - */ - -/* - * Copyright (C) 2020 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _INCLUDE__CAPTURE_SESSION__CLIENT_H_ -#define _INCLUDE__CAPTURE_SESSION__CLIENT_H_ - -#include <capture_session/capture_session.h> -#include <base/rpc_client.h> - -namespace Capture { struct Session_client; } - - -struct Capture::Session_client : public Genode::Rpc_client<Session> -{ - /** - * Constructor - */ - Session_client(Capability<Session> session) : Rpc_client<Session>(session) { } - - Area screen_size() const override { return call<Rpc_screen_size>(); } - - void screen_size_sigh(Signal_context_capability sigh) override - { - call<Rpc_screen_size_sigh>(sigh); - } - - void buffer(Area size) override { call<Rpc_buffer>(size); } - - Dataspace_capability dataspace() override { return call<Rpc_dataspace>(); } - - Affected_rects capture_at(Point pos) override - { - return call<Rpc_capture_at>(pos); - } -}; - -#endif /* _INCLUDE__CAPTURE_SESSION__CLIENT_H_ */ diff --git a/repos/os/include/capture_session/connection.h b/repos/os/include/capture_session/connection.h index 35393a7737..f152057df0 100644 --- a/repos/os/include/capture_session/connection.h +++ b/repos/os/include/capture_session/connection.h @@ -14,7 +14,7 @@ #ifndef _INCLUDE__CAPTURE_SESSION__CONNECTION_H_ #define _INCLUDE__CAPTURE_SESSION__CONNECTION_H_ -#include <capture_session/client.h> +#include <capture_session/capture_session.h> #include <base/connection.h> #include <base/attached_dataspace.h> #include <os/texture.h> @@ -23,8 +23,7 @@ namespace Capture { class Connection; } -class Capture::Connection : public Genode::Connection<Session>, - public Session_client +class Capture::Connection : private Genode::Connection<Session> { private: @@ -32,19 +31,20 @@ class Capture::Connection : public Genode::Connection<Session>, public: + using Label = Genode::Session_label; + /** * Constructor */ Connection(Genode::Env &env, Label const &label = Label()) : Genode::Connection<Capture::Session>(env, label, - Ram_quota { 36*1024 }, Args()), - Session_client(cap()) + Ram_quota { 36*1024 }, Args()) { } - void buffer(Area size) override + void buffer(Session::Buffer_attr attr) { - size_t const needed = buffer_bytes(size); + size_t const needed = Session::buffer_bytes(attr.px); size_t const upgrade = needed > _session_quota ? needed - _session_quota : 0; @@ -53,10 +53,42 @@ class Capture::Connection : public Genode::Connection<Session>, _session_quota += upgrade; } - Session_client::buffer(size); + for (;;) { + using Result = Session::Buffer_result; + switch (cap().call<Session::Rpc_buffer>(attr)) { + case Result::OUT_OF_RAM: upgrade_ram(8*1024); break; + case Result::OUT_OF_CAPS: upgrade_caps(2); break; + case Result::OK: + return; + } + } } struct Screen; + + Area screen_size() const { return cap().call<Session::Rpc_screen_size>(); } + + void screen_size_sigh(Signal_context_capability sigh) + { + cap().call<Session::Rpc_screen_size_sigh>(sigh); + } + + void wakeup_sigh(Signal_context_capability sigh) + { + cap().call<Session::Rpc_wakeup_sigh>(sigh); + } + + Genode::Dataspace_capability dataspace() + { + return cap().call<Session::Rpc_dataspace>(); + } + + Session::Affected_rects capture_at(Point pos) + { + return cap().call<Session::Rpc_capture_at>(pos); + } + + void capture_stopped() { cap().call<Session::Rpc_capture_stopped>(); } }; @@ -64,29 +96,40 @@ class Capture::Connection::Screen { public: - Area const size; + struct Attr + { + Area px; /* buffer area in pixels */ + Area mm; /* physical size in millimeters */ + }; + + Attr const attr; private: Capture::Connection &_connection; - bool const _buffer_initialized = ( _connection.buffer(size), true ); + bool const _buffer_initialized = ( + _connection.buffer({ .px = attr.px, .mm = attr.mm }), true ); Attached_dataspace _ds; - Texture<Pixel> const _texture { _ds.local_addr<Pixel>(), nullptr, size }; + Texture<Pixel> const _texture { _ds.local_addr<Pixel>(), nullptr, attr.px }; public: - Screen(Capture::Connection &connection, Region_map &rm, Area size) + Screen(Capture::Connection &connection, Region_map &rm, Attr attr) : - size(size), _connection(connection), _ds(rm, _connection.dataspace()) + attr(attr), _connection(connection), _ds(rm, _connection.dataspace()) { } void with_texture(auto const &fn) const { fn(_texture); } - void apply_to_surface(Surface<Pixel> &surface) + Rect apply_to_surface(Surface<Pixel> &surface) { + Rect bounding_box { }; + + using Affected_rects = Session::Affected_rects; + Affected_rects const affected = _connection.capture_at(Capture::Point(0, 0)); with_texture([&] (Texture<Pixel> const &texture) { @@ -96,8 +139,13 @@ class Capture::Connection::Screen surface.clip(rect); Blit_painter::paint(surface, texture, Capture::Point(0, 0)); + + bounding_box = bounding_box.area.count() + ? Rect::compound(bounding_box, rect) + : rect; }); }); + return bounding_box; } }; diff --git a/repos/os/include/decorator/window.h b/repos/os/include/decorator/window.h index e5a54cc487..bc097c9de8 100644 --- a/repos/os/include/decorator/window.h +++ b/repos/os/include/decorator/window.h @@ -141,6 +141,8 @@ class Decorator::Window_base : private Genode::List_model<Window_base>::Element _stacked = true; } + void forget_neighbor() { _neighbor.destruct(); } + bool back_most() const { return _stacked && !_neighbor.constructed(); diff --git a/repos/os/include/decorator/window_stack.h b/repos/os/include/decorator/window_stack.h index 518cecbfe2..e305a84d49 100644 --- a/repos/os/include/decorator/window_stack.h +++ b/repos/os/include/decorator/window_stack.h @@ -257,7 +257,7 @@ void Decorator::Window_stack::update_model(Genode::Xml_node root_node, reversed.remove(back_most); Window_base &window = *back_most->object(); stack_back_most_window(window); - window.stacking_neighbor(Gui::View_id()); + window.forget_neighbor(); Window_base *neighbor = &window; diff --git a/repos/os/include/framebuffer_session/client.h b/repos/os/include/framebuffer_session/client.h index 57bc389e19..b70b93ca3d 100644 --- a/repos/os/include/framebuffer_session/client.h +++ b/repos/os/include/framebuffer_session/client.h @@ -20,24 +20,46 @@ namespace Framebuffer { struct Session_client; } -struct Framebuffer::Session_client : Genode::Rpc_client<Session> +struct Framebuffer::Session_client : Rpc_client<Session> { - explicit Session_client(Session_capability session) - : Genode::Rpc_client<Session>(session) { } + explicit Session_client(Session_capability cap) : Rpc_client<Session>(cap) { } - Genode::Dataspace_capability dataspace() override { - return call<Rpc_dataspace>(); } + Dataspace_capability dataspace() override { return call<Rpc_dataspace>(); } Mode mode() const override { return call<Rpc_mode>(); } - void mode_sigh(Genode::Signal_context_capability sigh) override { - call<Rpc_mode_sigh>(sigh); } + void mode_sigh(Signal_context_capability sigh) override { call<Rpc_mode_sigh>(sigh); } - void sync_sigh(Genode::Signal_context_capability sigh) override { - call<Rpc_sync_sigh>(sigh); } + void sync_sigh(Signal_context_capability sigh) override { call<Rpc_sync_sigh>(sigh); } - void refresh(int x, int y, int w, int h) override { - call<Rpc_refresh>(x, y, w, h); } + void sync_source(Session_label const &source) override { call<Rpc_sync_source>(source); } + + void refresh(Rect rect) override { call<Rpc_refresh>(rect); } + + /** + * Flush specified pixel region + * + * \deprecated + * \noapi + */ + void refresh(int x, int y, int w, int h) + { + refresh(Rect { { x, y }, { unsigned(w), unsigned(h) } }); + } + + Blit_result blit(Blit_batch const &batch) override { return call<Rpc_blit>(batch); } + + /** + * Transfer a single pixel region within the framebuffer + */ + Blit_result blit(Rect from, Point to) + { + Blit_batch batch { }; + batch.transfer[0] = { from, to }; + return blit(batch); + } + + void panning(Point pos) override { call<Rpc_panning>(pos); } }; #endif /* _INCLUDE__FRAMEBUFFER_SESSION__CLIENT_H_ */ diff --git a/repos/os/include/framebuffer_session/connection.h b/repos/os/include/framebuffer_session/connection.h index 7d6ac22fb2..ab3ce94c6e 100644 --- a/repos/os/include/framebuffer_session/connection.h +++ b/repos/os/include/framebuffer_session/connection.h @@ -31,7 +31,7 @@ struct Framebuffer::Connection : Genode::Connection<Session>, Session_client * session, you should validate the actual frame-buffer attributes * by calling the 'info' method of the frame-buffer interface. */ - Connection(Genode::Env &env, Framebuffer::Mode mode) + Connection(Env &env, Framebuffer::Mode mode) : Genode::Connection<Session>(env, Label(), Ram_quota { 8*1024 }, Args("fb_width=", mode.area.w, ", " diff --git a/repos/os/include/framebuffer_session/framebuffer_session.h b/repos/os/include/framebuffer_session/framebuffer_session.h index 3f45ab9410..b3dde2ba86 100644 --- a/repos/os/include/framebuffer_session/framebuffer_session.h +++ b/repos/os/include/framebuffer_session/framebuffer_session.h @@ -19,30 +19,120 @@ #include <dataspace/capability.h> #include <session/session.h> #include <os/surface.h> +#include <os/pixel_rgb888.h> +#include <os/pixel_alpha8.h> namespace Framebuffer { - struct Mode; struct Session; struct Session_client; - using Area = Genode::Surface_base::Area; + using namespace Genode; + + using Area = Surface_base::Area; + using Point = Surface_base::Point; + using Rect = Surface_base::Rect; + + struct Mode + { + Area area; + bool alpha; + + void print(Output &out) const { Genode::print(out, area); } + + /* + * If using an alpha channel, the alpha buffer follows the pixel + * buffer. The alpha buffer is followed by an input-mask buffer. + * + * The input-mask buffer contains a byte value per texture pixel, + * which describes the policy of handling user input referring to the + * pixel. If set to zero, the input is passed through the view such + * that it can be handled by one of the subsequent views in the view + * stack. If set to one, the input is consumed by the view. + */ + + void with_pixel_surface(auto &ds, auto const &fn) const + { + Surface<Pixel_rgb888> surface { ds.bytes(), area }; + fn(surface); + } + + void with_alpha_bytes(auto &ds, auto const &fn) const + { + if (!alpha) + return; + + size_t const offset = area.count()*sizeof(Pixel_rgb888); + ds.bytes().with_skipped_bytes(offset, [&] (Byte_range_ptr const &bytes) { + fn(bytes); }); + } + + void with_alpha_surface(auto &ds, auto const &fn) const + { + with_alpha_bytes(ds, [&] (Byte_range_ptr const &bytes) { + Surface<Pixel_alpha8> surface { bytes, area }; + fn(surface); }); + } + + void with_input_bytes(auto &ds, auto const &fn) const + { + if (!alpha) + return; + + size_t const offset = area.count()*sizeof(Pixel_rgb888) + area.count(); + ds.bytes().with_skipped_bytes(offset, [&] (Byte_range_ptr const &bytes) { + fn(bytes); }); + } + + void with_input_surface(auto &ds, auto const &fn) const + { + with_input_bytes(ds, [&] (Byte_range_ptr const &bytes) { + Surface<Pixel_input8> surface { bytes, area }; + fn(surface); }); + } + + size_t num_bytes() const + { + size_t const bytes_per_pixel = + sizeof(Pixel_rgb888) + alpha*(sizeof(Pixel_alpha8) + sizeof(Pixel_input8)); + + return area.count()*bytes_per_pixel; + } + }; + + struct Transfer + { + Rect from; /* source rectangle */ + Point to; /* destination position */ + + /** + * Return true if transfer is applicable to 'mode' + * + * Pixels are transferred only if the source rectangle lies within + * the bounds of the framebuffer, and source does not overlap the + * destination. + */ + bool valid(Mode const &mode) const + { + Rect const fb { { }, mode.area }; + Rect const dest { to, from.area }; + + return from.area.valid() + && fb.contains(from.p1()) && fb.contains(from.p2()) + && fb.contains(dest.p1()) && fb.contains(dest.p2()) + && !Rect::intersect(from, dest).valid(); + } + }; + + struct Blit_batch + { + static constexpr unsigned N = 4; + + Transfer transfer[N]; + }; } -/** - * Framebuffer mode info as returned by 'Framebuffer::Session::mode()' - */ -struct Framebuffer::Mode -{ - Area area; - - Genode::size_t bytes_per_pixel() const { return 4; } - - void print(Genode::Output &out) const { Genode::print(out, area); } -}; - - struct Framebuffer::Session : Genode::Session { /** @@ -70,7 +160,7 @@ struct Framebuffer::Session : Genode::Session * have detached the previously requested dataspace from its local * address space. */ - virtual Genode::Dataspace_capability dataspace() = 0; + virtual Dataspace_capability dataspace() = 0; /** * Request display-mode properties of the framebuffer ready to be @@ -89,33 +179,66 @@ struct Framebuffer::Session : Genode::Session * method. However, from the client's perspective, the original mode * stays in effect until the it calls 'dataspace()' again. */ - virtual void mode_sigh(Genode::Signal_context_capability sigh) = 0; + virtual void mode_sigh(Signal_context_capability sigh) = 0; /** * Flush specified pixel region * - * \param x,y,w,h region to be updated on physical frame buffer + * \param rect region to be updated on physical frame buffer */ - virtual void refresh(int x, int y, int w, int h) = 0; + virtual void refresh(Rect rect) = 0; + + enum class Blit_result { OK, OVERLOADED }; + + /** + * Transfer pixel regions within the framebuffer + */ + virtual Blit_result blit(Blit_batch const &) = 0; + + /** + * Define panning position of the framebuffer + * + * The panning position is the point within the framebuffer that + * corresponds to the top-left corner of the output. It is designated + * for implementing buffer flipping of double-buffered output, and for + * scrolling. + */ + virtual void panning(Point pos) = 0; /** * Register signal handler for refresh synchronization */ - virtual void sync_sigh(Genode::Signal_context_capability) = 0; + virtual void sync_sigh(Signal_context_capability) = 0; + + /** + * Define the preferred source of sync signals + * + * In the presence of multiple capture clients at the GUI server, each + * client captures the GUI at independent refresh rates. Hence, there is + * no single source of sync signals but there can be multiple. From the + * application's perspective, the most adequate sync source may depend on + * the positions of the capture clients at the GUI server and the position + * of the application's view. By specifying a capture client's label as + * 'sync_sigh', the application can take an informed decision. + */ + virtual void sync_source(Session_label const &) = 0; /********************* ** RPC declaration ** *********************/ - GENODE_RPC(Rpc_dataspace, Genode::Dataspace_capability, dataspace); + GENODE_RPC(Rpc_dataspace, Dataspace_capability, dataspace); GENODE_RPC(Rpc_mode, Mode, mode); - GENODE_RPC(Rpc_refresh, void, refresh, int, int, int, int); - GENODE_RPC(Rpc_mode_sigh, void, mode_sigh, Genode::Signal_context_capability); - GENODE_RPC(Rpc_sync_sigh, void, sync_sigh, Genode::Signal_context_capability); + GENODE_RPC(Rpc_refresh, void, refresh, Rect); + GENODE_RPC(Rpc_blit, Blit_result, blit, Blit_batch const &); + GENODE_RPC(Rpc_panning, void, panning, Point); + GENODE_RPC(Rpc_mode_sigh, void, mode_sigh, Signal_context_capability); + GENODE_RPC(Rpc_sync_sigh, void, sync_sigh, Signal_context_capability); + GENODE_RPC(Rpc_sync_source, void, sync_source, Session_label const &); GENODE_RPC_INTERFACE(Rpc_dataspace, Rpc_mode, Rpc_mode_sigh, Rpc_refresh, - Rpc_sync_sigh); + Rpc_blit, Rpc_panning, Rpc_sync_sigh, Rpc_sync_source); }; #endif /* _INCLUDE__FRAMEBUFFER_SESSION__FRAMEBUFFER_SESSION_H_ */ diff --git a/repos/os/include/gui_session/client.h b/repos/os/include/gui_session/client.h index 37da61b4bd..2228a8ef00 100644 --- a/repos/os/include/gui_session/client.h +++ b/repos/os/include/gui_session/client.h @@ -30,19 +30,22 @@ struct Gui::Session_client : Rpc_client<Session> Input::Session_capability input() override { return call<Rpc_input>(); } - View_result view(View_id id, View_attr const &attr) override { + Info_result info() override { + return call<Rpc_info>(); } + + [[nodiscard]] View_result view(View_id id, View_attr const &attr) override { return call<Rpc_view>(id, attr); } - Child_view_result child_view(View_id id, View_id parent, View_attr const &attr) override { + [[nodiscard]] Child_view_result child_view(View_id id, View_id parent, View_attr const &attr) override { return call<Rpc_child_view>(id, parent, attr); } void destroy_view(View_id view) override { call<Rpc_destroy_view>(view); } - Associate_result associate(View_id id, View_capability view) override { + [[nodiscard]] Associate_result associate(View_id id, View_capability view) override { return call<Rpc_associate>(id, view); } - View_capability_result view_capability(View_id id) override { + [[nodiscard]] View_capability_result view_capability(View_id id) override { return call<Rpc_view_capability>(id); } void release_view_id(View_id id) override { @@ -53,14 +56,8 @@ struct Gui::Session_client : Rpc_client<Session> void execute() override { call<Rpc_execute>(); } - Framebuffer::Mode mode() override { - return call<Rpc_mode>(); } - - void mode_sigh(Signal_context_capability sigh) override { - call<Rpc_mode_sigh>(sigh); } - - Buffer_result buffer(Framebuffer::Mode mode, bool alpha) override { - return call<Rpc_buffer>(mode, alpha); } + [[nodiscard]] Buffer_result buffer(Framebuffer::Mode mode) override { + return call<Rpc_buffer>(mode); } void focus(Gui::Session_capability session) override { call<Rpc_focus>(session); } diff --git a/repos/os/include/gui_session/connection.h b/repos/os/include/gui_session/connection.h index aa59a615b1..91743116e6 100644 --- a/repos/os/include/gui_session/connection.h +++ b/repos/os/include/gui_session/connection.h @@ -17,6 +17,7 @@ #include <gui_session/client.h> #include <framebuffer_session/client.h> #include <input_session/client.h> +#include <rom_session/client.h> #include <base/connection.h> namespace Gui { @@ -41,6 +42,54 @@ class Gui::Connection : private Genode::Connection<Session> Ram_quota _ram_quota { }; /* session quota donated for virtual frame buffer */ + /* + * Session quota at the construction time of the connection + * + * The 'Gui::Session::CAP_QUOTA' value is based the needs of the + * nitpicker GUI server. To accommodate the common case where a client + * is served by the wm, which in turn wraps a nitpicker session, extend + * the session quota according to the needs of the wm. + */ + static constexpr Ram_quota _RAM_QUOTA { 96*1024 }; + static constexpr Cap_quota _CAP_QUOTA { Session::CAP_QUOTA + 9 }; + + Constructible<Rom_session_client> _info_rom { }; + Constructible<Attached_dataspace> _info_ds { }; + + Rom_session_capability _info_rom_capability() + { + for (;;) { + using Error = Session::Info_error; + auto const result = _client.info(); + if (result == Error::OUT_OF_RAM) { upgrade_ram(8*1024); continue; } + if (result == Error::OUT_OF_CAPS) { upgrade_caps(2); continue; } + return result.convert<Rom_session_capability>( + [&] (Rom_session_capability cap) { return cap; }, + [&] (auto) /* handled above */ { return Rom_session_capability(); }); + } + } + + void _with_info_rom(auto const &fn) + { + if (!_info_ds.constructed()) + _info_rom.construct(_info_rom_capability()); + fn(*_info_rom); + } + + void _with_info_xml(auto const &fn) + { + _with_info_rom([&] (Rom_session_client &rom) { + if (!_info_ds.constructed() || rom.update() == false) + _info_ds.construct(_env.rm(), rom.dataspace()); + + try { + Xml_node xml(_info_ds->local_addr<char>(), _info_ds->size()); + fn(xml); } + catch (Xml_node::Invalid_syntax) { + warning("Gui::info has invalid XML syntax"); } + }); + } + public: View_ids view_ids { }; @@ -65,7 +114,8 @@ class Gui::Connection : private Genode::Connection<Session> */ Connection(Env &env, Session_label const &label = { }) : - Genode::Connection<Session>(env, label, Ram_quota { 36*1024 }, Args()), + Genode::Connection<Session>(env, label, _RAM_QUOTA, _CAP_QUOTA, + Affinity { }, Args { }), _env(env) { } @@ -142,9 +192,9 @@ class Gui::Connection : private Genode::Connection<Session> } } - void buffer(Framebuffer::Mode mode, bool use_alpha) + void buffer(Framebuffer::Mode mode) { - size_t const needed = Session_client::ram_quota(mode, use_alpha); + size_t const needed = Session_client::ram_quota(mode); size_t const upgrade = needed > _ram_quota.value ? needed - _ram_quota.value : 0u; if (upgrade > 0) { @@ -152,13 +202,12 @@ class Gui::Connection : private Genode::Connection<Session> _ram_quota.value += upgrade; } - for (bool retry = false; ; ) { + for (;;) { using Result = Session_client::Buffer_result; - auto const result = _client.buffer(mode, use_alpha); - if (result == Result::OUT_OF_RAM) { upgrade_ram(8*1024); retry = true; } - if (result == Result::OUT_OF_CAPS) { upgrade_caps(2); retry = true; } - if (!retry) - break; + auto const result = _client.buffer(mode); + if (result == Result::OUT_OF_RAM) { upgrade_ram(8*1024); continue; } + if (result == Result::OUT_OF_CAPS) { upgrade_caps(2); continue; } + break; } } @@ -188,14 +237,77 @@ class Gui::Connection : private Genode::Connection<Session> } /** - * Return physical screen mode + * Call 'fn' with mode information as 'Xml_node const &' argument */ - Framebuffer::Mode mode() { return _client.mode(); } + void with_info(auto const &fn) { _with_info_xml(fn); } + + Capability<Rom_session> info_rom_cap() + { + Capability<Rom_session> result { }; + _with_info_rom([&] (Rom_session_client &rom) { result = rom.rpc_cap(); }); + return result; + } + + using Panorama_result = Attempt<Gui::Rect, Gui::Undefined>; + + /** + * Return geometry of the total panorama + * + * The retured rectangle may be undefined for a client of the nitpicker + * GUI server in the absence of any capture client. + */ + Panorama_result panorama() + { + Gui::Rect result { }; + _with_info_xml([&] (Xml_node const &info) { + result = Rect::from_xml(info); }); + return result.valid() ? Panorama_result { result } + : Panorama_result { Undefined { } }; + } + + using Window_result = Attempt<Rect, Gui::Undefined>; + + /** + * Return suitable geometry of top-level view + * + * For nitpicker clients, the window is the bounding box of all capture + * clients. For window-manager clients, returned rectangle corresponds + * to the window size as defined by the layouter. + * + * The returned rectangle may be undefined when a client of the window + * manager has not defined a top-level view yet. Once a window is got + * closed, the returned rectangle is zero-sized. + */ + Window_result window() + { + Rect result { }; + bool closed = false; + _with_info_xml([&] (Xml_node const &info) { + Rect bb { }; /* bounding box of all captured rects */ + unsigned count = 0; + info.for_each_sub_node("capture", [&] (Xml_node const &capture) { + closed |= (capture.attribute_value("closed", false)); + bb = Rect::compound(bb, Rect::from_xml(capture)); + count++; + }); + result = (count == 1) ? bb : Rect::from_xml(info); + }); + if (closed) + return Rect { }; + + return result.valid() ? Window_result { result } + : Window_result { Undefined { } }; + } /** * Register signal handler to be notified about mode changes */ - void mode_sigh(Signal_context_capability sigh) { _client.mode_sigh(sigh); } + void info_sigh(Signal_context_capability sigh) + { + _with_info_rom([&] (Rom_session_client &rom) { rom.sigh(sigh); }); + if (sigh.valid()) + Signal_transmitter(sigh).submit(); + } void focus(Capability<Session> focused) { _client.focus(focused); } }; diff --git a/repos/os/include/gui_session/gui_session.h b/repos/os/include/gui_session/gui_session.h index 2e82d35582..e65042ca91 100644 --- a/repos/os/include/gui_session/gui_session.h +++ b/repos/os/include/gui_session/gui_session.h @@ -19,6 +19,7 @@ #include <os/surface.h> #include <framebuffer_session/capability.h> #include <input_session/capability.h> +#include <rom_session/rom_session.h> namespace Gui { @@ -44,6 +45,8 @@ namespace Gui { using Rect = Surface_base::Rect; using Point = Surface_base::Point; using Area = Surface_base::Area; + + struct Undefined { }; } @@ -171,6 +174,14 @@ struct Gui::Session : Genode::Session */ virtual Input::Session_capability input() = 0; + enum class Info_error { OUT_OF_RAM, OUT_OF_CAPS }; + using Info_result = Attempt<Capability<Rom_session>, Info_error>; + + /** + * Request ROM session containing the mode information + */ + virtual Info_result info() = 0; + struct View_attr { Title title; @@ -233,22 +244,12 @@ struct Gui::Session : Genode::Session */ virtual void execute() = 0; - /** - * Return physical screen mode - */ - virtual Framebuffer::Mode mode() = 0; - - /** - * Register signal handler to be notified about mode changes - */ - virtual void mode_sigh(Signal_context_capability) = 0; - enum class Buffer_result { OK, OUT_OF_RAM, OUT_OF_CAPS }; /** * Define dimensions of virtual framebuffer */ - virtual Buffer_result buffer(Framebuffer::Mode mode, bool use_alpha) = 0; + virtual Buffer_result buffer(Framebuffer::Mode mode) = 0; /** * Set focused session @@ -268,13 +269,13 @@ struct Gui::Session : Genode::Session /** * Return number of bytes needed for virtual framebuffer of specified size */ - static size_t ram_quota(Framebuffer::Mode mode, bool use_alpha) + static size_t ram_quota(Framebuffer::Mode mode) { /* * If alpha blending is used, each pixel requires an additional byte * for the alpha value and a byte holding the input mask. */ - return (mode.bytes_per_pixel() + 2*use_alpha)*mode.area.count(); + return (sizeof(Pixel_rgb888) + 2*mode.alpha)*mode.area.count(); } @@ -284,6 +285,7 @@ struct Gui::Session : Genode::Session GENODE_RPC(Rpc_framebuffer, Framebuffer::Session_capability, framebuffer); GENODE_RPC(Rpc_input, Input::Session_capability, input); + GENODE_RPC(Rpc_info, Info_result, info); GENODE_RPC(Rpc_view, View_result, view, View_id, View_attr const &); GENODE_RPC(Rpc_child_view, Child_view_result, child_view, View_id, View_id, View_attr const &); GENODE_RPC(Rpc_destroy_view, void, destroy_view, View_id); @@ -293,16 +295,13 @@ struct Gui::Session : Genode::Session GENODE_RPC(Rpc_command_dataspace, Dataspace_capability, command_dataspace); GENODE_RPC(Rpc_execute, void, execute); GENODE_RPC(Rpc_background, int, background, View_capability); - GENODE_RPC(Rpc_mode, Framebuffer::Mode, mode); - GENODE_RPC(Rpc_mode_sigh, void, mode_sigh, Signal_context_capability); GENODE_RPC(Rpc_focus, void, focus, Capability<Session>); - GENODE_RPC(Rpc_buffer, Buffer_result, buffer, Framebuffer::Mode, bool); + GENODE_RPC(Rpc_buffer, Buffer_result, buffer, Framebuffer::Mode); - GENODE_RPC_INTERFACE(Rpc_framebuffer, Rpc_input, + GENODE_RPC_INTERFACE(Rpc_framebuffer, Rpc_input, Rpc_info, Rpc_view, Rpc_child_view, Rpc_destroy_view, Rpc_associate, Rpc_view_capability, Rpc_release_view_id, - Rpc_command_dataspace, Rpc_execute, Rpc_mode, - Rpc_mode_sigh, Rpc_buffer, Rpc_focus); + Rpc_command_dataspace, Rpc_execute, Rpc_buffer, Rpc_focus); }; #endif /* _INCLUDE__GUI_SESSION__GUI_SESSION_H_ */ diff --git a/repos/os/include/input/component.h b/repos/os/include/input/component.h index c606823e89..e21f802583 100644 --- a/repos/os/include/input/component.h +++ b/repos/os/include/input/component.h @@ -25,11 +25,21 @@ namespace Input { class Session_component; } -class Input::Session_component : public Genode::Rpc_object<Input::Session> +class Input::Session_component : public Rpc_object<Input::Session> { + public: + + struct Action : Interface + { + virtual void exclusive_input_requested(bool) = 0; + }; + private: - Genode::Attached_ram_dataspace _ds; + Entrypoint &_ep; + Action &_action; + + Attached_ram_dataspace _ds; Event_queue _event_queue { }; @@ -38,12 +48,18 @@ class Input::Session_component : public Genode::Rpc_object<Input::Session> /** * Constructor * - * \param ram allocator for the session buffer + * \param ram allocator for the shared-memory input buffer */ - Session_component(Genode::Env &env, Genode::Ram_allocator &ram) + Session_component(Entrypoint &ep, Ram_allocator &ram, + Region_map &rm, Action &action) : - _ds(ram, env.rm(), Event_queue::QUEUE_SIZE*sizeof(Input::Event)) - { } + _ep(ep), _action(action), + _ds(ram, rm, Event_queue::QUEUE_SIZE*sizeof(Input::Event)) + { + _ep.manage(*this); + } + + ~Session_component() { _ep.dissolve(*this); } /** * Return reference to event queue of the session @@ -58,7 +74,7 @@ class Input::Session_component : public Genode::Rpc_object<Input::Session> try { _event_queue.add(event); } catch (Input::Event_queue::Overflow) { - Genode::warning("input overflow - resetting queue"); + warning("input overflow - resetting queue"); _event_queue.reset(); } } @@ -68,7 +84,7 @@ class Input::Session_component : public Genode::Rpc_object<Input::Session> ** Input::Session interface ** ******************************/ - Genode::Dataspace_capability dataspace() override { return _ds.cap(); } + Dataspace_capability dataspace() override { return _ds.cap(); } bool pending() const override { return !_event_queue.empty(); } @@ -83,10 +99,15 @@ class Input::Session_component : public Genode::Rpc_object<Input::Session> return cnt; } - void sigh(Genode::Signal_context_capability sigh) override + void sigh(Signal_context_capability sigh) override { _event_queue.sigh(sigh); } + + void exclusive(bool enabled) override + { + _action.exclusive_input_requested(enabled); + } }; #endif /* _INCLUDE__INPUT__COMPONENT_H_ */ diff --git a/repos/os/include/input_session/client.h b/repos/os/include/input_session/client.h index 633bc98d3d..f24aa3e32c 100644 --- a/repos/os/include/input_session/client.h +++ b/repos/os/include/input_session/client.h @@ -22,26 +22,25 @@ namespace Input { struct Session_client; } -class Input::Session_client : public Genode::Rpc_client<Session> +class Input::Session_client : public Rpc_client<Session> { private: - Genode::Attached_dataspace _event_ds; + Attached_dataspace _event_ds; - Genode::size_t const _max_events = - _event_ds.size() / sizeof(Input::Event); + size_t const _max_events = _event_ds.size() / sizeof(Input::Event); friend class Input::Binding; public: - Session_client(Genode::Region_map &local_rm, Session_capability session) + Session_client(Region_map &local_rm, Session_capability session) : - Genode::Rpc_client<Session>(session), + Rpc_client<Session>(session), _event_ds(local_rm, call<Rpc_dataspace>()) { } - Genode::Dataspace_capability dataspace() override { + Dataspace_capability dataspace() override { return call<Rpc_dataspace>(); } bool pending() const override { @@ -50,9 +49,12 @@ class Input::Session_client : public Genode::Rpc_client<Session> int flush() override { return call<Rpc_flush>(); } - void sigh(Genode::Signal_context_capability sigh) override { + void sigh(Signal_context_capability sigh) override { call<Rpc_sigh>(sigh); } + void exclusive(bool enabled) override { + call<Rpc_exclusive>(enabled); } + /** * Flush and apply functor to pending events * @@ -61,10 +63,10 @@ class Input::Session_client : public Genode::Rpc_client<Session> */ void for_each_event(auto const &fn) { - Genode::size_t const n = Genode::min((Genode::size_t)call<Rpc_flush>(), _max_events); + size_t const n = min((size_t)call<Rpc_flush>(), _max_events); Event const *ev_buf = _event_ds.local_addr<const Event>(); - for (Genode::size_t i = 0; i < n; ++i) + for (size_t i = 0; i < n; ++i) fn(ev_buf[i]); } }; diff --git a/repos/os/include/input_session/input_session.h b/repos/os/include/input_session/input_session.h index 5532896bd0..d53ba4f9e3 100644 --- a/repos/os/include/input_session/input_session.h +++ b/repos/os/include/input_session/input_session.h @@ -19,7 +19,12 @@ #include <session/session.h> #include <base/signal.h> -namespace Input { struct Session; } +namespace Input { + + using namespace Genode; + + struct Session; +} struct Input::Session : Genode::Session @@ -41,7 +46,7 @@ struct Input::Session : Genode::Session /** * Return capability to event buffer dataspace */ - virtual Genode::Dataspace_capability dataspace() = 0; + virtual Dataspace_capability dataspace() = 0; /** * Request input state @@ -60,19 +65,26 @@ struct Input::Session : Genode::Session /** * Register signal handler to be notified on arrival of new input */ - virtual void sigh(Genode::Signal_context_capability) = 0; + virtual void sigh(Signal_context_capability) = 0; + + /** + * Express intent to receive relative pointer events exclusively + */ + virtual void exclusive(bool) = 0; /********************* ** RPC declaration ** *********************/ - GENODE_RPC(Rpc_dataspace, Genode::Dataspace_capability, dataspace); - GENODE_RPC(Rpc_pending, bool, pending); - GENODE_RPC(Rpc_flush, int, flush); - GENODE_RPC(Rpc_sigh, void, sigh, Genode::Signal_context_capability); + GENODE_RPC(Rpc_dataspace, Dataspace_capability, dataspace); + GENODE_RPC(Rpc_pending, bool, pending); + GENODE_RPC(Rpc_flush, int, flush); + GENODE_RPC(Rpc_sigh, void, sigh, Signal_context_capability); + GENODE_RPC(Rpc_exclusive, void, exclusive, bool); - GENODE_RPC_INTERFACE(Rpc_dataspace, Rpc_pending, Rpc_flush, Rpc_sigh); + GENODE_RPC_INTERFACE(Rpc_dataspace, Rpc_pending, Rpc_flush, Rpc_sigh, + Rpc_exclusive); }; #endif /* _INCLUDE__INPUT_SESSION__INPUT_SESSION_H_ */ diff --git a/repos/os/include/os/pixel_alpha8.h b/repos/os/include/os/pixel_alpha8.h index f3e051b14c..4ba1718c0f 100644 --- a/repos/os/include/os/pixel_alpha8.h +++ b/repos/os/include/os/pixel_alpha8.h @@ -18,9 +18,11 @@ namespace Genode { - using Pixel_alpha8 = Genode::Pixel_rgba<uint8_t, Genode::Surface_base::ALPHA8, - 0, 0, 0, 0, 0, 0, 0xff, 0>; + using Pixel_alpha8 = Pixel_rgba<uint8_t, Surface_base::ALPHA8, + 0, 0, 0, 0, 0, 0, 0xff, 0>; + using Pixel_input8 = Pixel_rgba<uint8_t, Surface_base::INPUT8, + 0, 0, 0, 0, 0, 0, 0xff, 0>; /* * The second pixel parameter is ignored. It can be of any pixel type. diff --git a/repos/os/include/os/session_policy.h b/repos/os/include/os/session_policy.h index a374c409c9..d5a4cd2bcd 100644 --- a/repos/os/include/os/session_policy.h +++ b/repos/os/include/os/session_policy.h @@ -17,6 +17,7 @@ #include <base/session_label.h> #include <base/log.h> #include <session/session.h> +#include <util/reconstructible.h> #include <util/arg_string.h> #include <util/xml_node.h> @@ -57,7 +58,7 @@ struct Genode::Xml_node_label_score Xml_node_label_score() { } template <size_t N> - Xml_node_label_score(Xml_node node, String<N> const &label) + Xml_node_label_score(Xml_node const &node, String<N> const &label) : label_present (node.has_attribute("label")), prefix_present(node.has_attribute("label_prefix")), @@ -178,28 +179,31 @@ void Genode::with_matching_policy(String<N> const &label, /* * Find policy node that matches best */ - Xml_node best_match("<none/>"); - Xml_node_label_score best_score; + Constructible<Xml_node> best_match { }; + Xml_node_label_score best_score; policies.for_each_sub_node("policy", [&] (Xml_node const &policy) { Xml_node_label_score const score(policy, label); - if (score.stronger(best_score)) { - best_match = policy; - best_score = score; - } + if (score.stronger(best_score)) + policy.with_raw_node([&] (char const *ptr, size_t len) { + best_match.construct(ptr, len); + best_score = score; }); }); /* fall back to default policy if no match exists */ - if (best_match.has_type("none")) + if (!best_match.constructed()) policies.with_optional_sub_node("default-policy", [&] (Xml_node const &policy) { - best_match = policy; }); + policy.with_raw_node([&] (char const *ptr, size_t len) { + best_match.construct(ptr, len); }); }); - if (best_match.has_type("none")) + if (best_match.constructed()) { + Xml_node const &node = *best_match; + match_fn(node); + } else { no_match_fn(); - else - match_fn(best_match); + } } @@ -221,20 +225,24 @@ class Genode::Session_policy : public Xml_node * Query session policy from session label */ template <size_t N> - static Xml_node _query_policy(String<N> const &label, Xml_node config) + static Const_byte_range_ptr _query_policy(String<N> const &label, Xml_node const &config) { - Xml_node result("<none/>"); + char const *start_ptr = "<none/>"; + size_t num_bytes = 7; with_matching_policy(label, config, [&] (Xml_node const &policy) { - result = policy; }, + policy.with_raw_node([&] (char const *ptr, size_t len) { + start_ptr = ptr; + num_bytes = len; }); + }, [&] () { warning("no policy defined for label '", label, "'"); throw No_policy_defined(); }); - return result; + return { start_ptr, num_bytes }; } public: @@ -257,7 +265,7 @@ class Genode::Session_policy : public Xml_node * with the longest label is selected. */ template <size_t N> - Session_policy(String<N> const &label, Xml_node config) + Session_policy(String<N> const &label, Xml_node const &config) : Xml_node(_query_policy(label, config)) { } diff --git a/repos/os/include/os/surface.h b/repos/os/include/os/surface.h index 881f32593c..7c8ceb6d7a 100644 --- a/repos/os/include/os/surface.h +++ b/repos/os/include/os/surface.h @@ -22,6 +22,8 @@ namespace Genode { class Surface_base; template <typename> class Surface; + + struct Surface_window { unsigned y, h; }; } @@ -46,7 +48,7 @@ class Genode::Surface_base : Interface using Point = Rect::Point; using Area = Rect::Area; - enum Pixel_format { UNKNOWN, RGB565, RGB888, ALPHA8 }; + enum Pixel_format { UNKNOWN, RGB565, RGB888, ALPHA8, INPUT8 }; struct Flusher : Interface { @@ -124,15 +126,49 @@ class Genode::Surface : public Surface_base PT *_addr; /* base address of pixel buffer */ + static Area _sanitized(Area area, size_t const num_bytes) + { + /* prevent division by zero */ + if (area.w == 0) + return { }; + + size_t const bytes_per_line = area.w*sizeof(PT); + + return { .w = area.w, + .h = unsigned(min(num_bytes/bytes_per_line, area.h)) }; + } + public: PT *addr() { return _addr; } - /** - * Constructor + /* + * \deprecated */ - Surface(PT *addr, Area size) - : Surface_base(size, PT::format()), _addr(addr) { } + Surface(PT *addr, Area size) : Surface_base(size, PT::format()), _addr(addr) { } + + Surface(Byte_range_ptr const &bytes, Area const area) + : + Surface_base(_sanitized(area, bytes.num_bytes), PT::format()), + _addr((PT *)bytes.start) + { } + + /** + * Call 'fn' with a sub-window surface as argument + * + * This method is useful for managing multiple surfaces within one + * larger surface, for example for organizing a back buffer and a front + * buffer within one virtual framebuffer. + */ + void with_window(Surface_window const win, auto const &fn) const + { + /* clip window coordinates against surface boundaries */ + Rect const rect = Rect::intersect({ { 0, 0 }, { 1, size().h } }, + { { 0, int(win.y) }, { 1, win.h } }); + + Surface surface { _addr + rect.y1()*size().w, { size().w, rect.h() } }; + fn(surface); + } }; #endif /* _INCLUDE__OS__SURFACE_H_ */ diff --git a/repos/os/include/sandbox/sandbox.h b/repos/os/include/sandbox/sandbox.h index eb25be9814..b9fd6bf4b3 100644 --- a/repos/os/include/sandbox/sandbox.h +++ b/repos/os/include/sandbox/sandbox.h @@ -15,6 +15,7 @@ #define _INCLUDE__SANDBOX__SANDBOX_H_ #include <util/xml_node.h> +#include <util/callable.h> #include <util/noncopyable.h> #include <base/registry.h> #include <base/service.h> @@ -60,12 +61,13 @@ class Genode::Sandbox : Noncopyable Region_map &address_space; }; - struct Fn : Interface { virtual void call(Intrinsics &) const = 0; }; + using With_intrinsics = Callable<void, Intrinsics &>; /** - * Call 'Fn' with the 'Intrinsics' that apply for the specified PD + * Call 'fn' with the 'Intrinsics' that apply for the specified PD */ - virtual void with_intrinsics(Capability<Pd_session>, Pd_session &, Fn const &) = 0; + virtual void with_intrinsics(Capability<Pd_session>, Pd_session &, + With_intrinsics::Ft const &fn) = 0; /** * Start the initial thread of new PD at the given instruction pointer @@ -207,26 +209,13 @@ class Genode::Sandbox::Local_service_base : public Service using Resources = Session::Resources; - struct Request_fn : Interface - { - virtual void with_requested_session(Request &) = 0; - }; + using With_request = Callable<void, Request &>; + using With_upgrade = Callable<Upgrade_response, Session &, Resources const &>; + using With_close = Callable<Close_response, Session &>; - void _for_each_requested_session(Request_fn &); - - struct Upgrade_fn : Interface - { - virtual Upgrade_response with_upgraded_session(Session &, Resources) = 0; - }; - - void _for_each_upgraded_session(Upgrade_fn &); - - struct Close_fn : Interface - { - virtual Close_response close_session(Session &) = 0; - }; - - void _for_each_session_to_close(Close_fn &); + void _for_each_requested_session(With_request::Ft const &); + void _for_each_upgraded_session (With_upgrade::Ft const &); + void _for_each_session_to_close (With_close::Ft const &); Id_space<Parent::Server> _server_id_space { }; @@ -253,21 +242,9 @@ struct Genode::Sandbox::Local_service : private Local_service_base * ('resources', 'label', 'diag') and allows the caller to respond * to the session request ('deliver_session', 'deny'). */ - template <typename FN> - void for_each_requested_session(FN const &fn) + void for_each_requested_session(auto const &fn) { - struct Untyped_fn : Local_service_base::Request_fn - { - FN const &_fn; - Untyped_fn(FN const &fn) : _fn(fn) { } - - void with_requested_session(Request &request) override - { - _fn(request); - } - } untyped_fn(fn); - - _for_each_requested_session(untyped_fn); + _for_each_requested_session(With_request::Fn { fn }); } /** @@ -279,22 +256,11 @@ struct Genode::Sandbox::Local_service : private Local_service_base * * The functor must return an 'Upgrade_response'. */ - template <typename FN> - void for_each_upgraded_session(FN const &fn) + void for_each_upgraded_session(auto const &fn) { - struct Untyped_fn : Local_service_base::Upgrade_fn - { - FN const &_fn; - Untyped_fn(FN const &fn) : _fn(fn) { } - - Upgrade_response with_upgraded_session(Session &session, - Resources resources) override - { - return _fn(static_cast<ST &>(session), resources); - } - } untyped_fn(fn); - - _for_each_upgraded_session(untyped_fn); + _for_each_upgraded_session(With_upgrade::Fn { + [&] (Session &session, Resources const &resources) { + return fn(static_cast<ST &>(session), resources); } }); } /** @@ -303,21 +269,11 @@ struct Genode::Sandbox::Local_service : private Local_service_base * The functor is called with a reference to the session object (type * 'ST') as argument and must return a 'Close_response'. */ - template <typename FN> - void for_each_session_to_close(FN const &fn) + void for_each_session_to_close(auto const &fn) { - struct Untyped_fn : Local_service_base::Close_fn - { - FN const &_fn; - Untyped_fn(FN const &fn) : _fn(fn) { } - - Close_response close_session(Session &session) override - { - return _fn(static_cast<ST &>(session)); - } - } untyped_fn(fn); - - _for_each_session_to_close(untyped_fn); + _for_each_session_to_close(With_close::Fn { + [&] (Session &session) { + return fn(static_cast<ST &>(session)); } }); } }; diff --git a/repos/os/include/usb_session/device.h b/repos/os/include/usb_session/device.h index 412bfcf149..765d819425 100644 --- a/repos/os/include/usb_session/device.h +++ b/repos/os/include/usb_session/device.h @@ -671,6 +671,8 @@ inline Usb::Interface::Interface(Device &device, Index idx, size_t buffer_size) device._for_each_iface([&] (Xml_node node) { if (node.attribute_value<uint16_t>("number", INVALID) != idx.number) return; + if (node.attribute_value<uint16_t>("alt_setting", INVALID) != idx.alt_setting) + return; node.for_each_sub_node("endpoint", [&] (Xml_node node) { Endpoint ep { node.attribute_value<uint8_t>("address", 0), node.attribute_value<uint8_t>("attributes", 0) }; diff --git a/repos/os/include/util/dirty_rect.h b/repos/os/include/util/dirty_rect.h index 4c72935c94..c33af9b27f 100644 --- a/repos/os/include/util/dirty_rect.h +++ b/repos/os/include/util/dirty_rect.h @@ -136,6 +136,15 @@ class Genode::Dirty_rect rect = rect.valid() ? Rect::compound(rect, added) : added; } + + bool empty() const + { + for (unsigned i = 0; i < NUM_RECTS; i++) + if (_rects[i].area.count()) + return false; + + return true; + } }; #endif /* _INCLUDE__UTIL__DIRTY_RECT_H_ */ diff --git a/repos/os/lib/symbols/sandbox b/repos/os/lib/symbols/sandbox index 0025452386..63e4b2658d 100644 --- a/repos/os/lib/symbols/sandbox +++ b/repos/os/lib/symbols/sandbox @@ -1,7 +1,7 @@ _ZN6Genode7Sandbox12apply_configERKNS_8Xml_nodeE T -_ZN6Genode7Sandbox18Local_service_base26_for_each_session_to_closeERNS1_8Close_fnE T -_ZN6Genode7Sandbox18Local_service_base26_for_each_upgraded_sessionERNS1_10Upgrade_fnE T -_ZN6Genode7Sandbox18Local_service_base27_for_each_requested_sessionERNS1_10Request_fnE T +_ZN6Genode7Sandbox18Local_service_base26_for_each_session_to_closeERKNS_8CallableINS1_14Close_responseEJRNS_7SessionEEE2FtE T +_ZN6Genode7Sandbox18Local_service_base26_for_each_upgraded_sessionERKNS_8CallableINS1_16Upgrade_responseEJRNS_7SessionERKNS4_9ResourcesEEE2FtE T +_ZN6Genode7Sandbox18Local_service_base27_for_each_requested_sessionERKNS_8CallableIvJRNS1_7RequestEEE2FtE T _ZN6Genode7Sandbox18Local_service_baseC1ERS0_RKNS_6StringILm32EEERNS1_6WakeupE T _ZN6Genode7Sandbox18Local_service_baseC2ERS0_RKNS_6StringILm32EEERNS1_6WakeupE T _ZN6Genode7SandboxC1ERNS_3EnvERNS0_13State_handlerE T diff --git a/repos/os/recipes/api/audio_in_session/hash b/repos/os/recipes/api/audio_in_session/hash index 5808657001..be001e69f2 100644 --- a/repos/os/recipes/api/audio_in_session/hash +++ b/repos/os/recipes/api/audio_in_session/hash @@ -1 +1 @@ -2024-08-28 9addc940df85488fbf88469ff720b945e41c4246 +2024-12-10 b51b8e7b49ba5dc94392eb506f5ee3d867abf914 diff --git a/repos/os/recipes/api/audio_out_session/hash b/repos/os/recipes/api/audio_out_session/hash index 4a14699853..3266472ac9 100644 --- a/repos/os/recipes/api/audio_out_session/hash +++ b/repos/os/recipes/api/audio_out_session/hash @@ -1 +1 @@ -2024-08-28 3ee0c730a62a902abad8d5e600ad6378dbc20189 +2024-12-10 3d0e275e4c295cea47b7ae9d664a2a8883a0c65f diff --git a/repos/os/recipes/api/capture_session/hash b/repos/os/recipes/api/capture_session/hash index fe090d4d6a..c6476d3c1d 100644 --- a/repos/os/recipes/api/capture_session/hash +++ b/repos/os/recipes/api/capture_session/hash @@ -1 +1 @@ -2024-05-28 ba263e0698a28074a83c02495747b5d072689a64 +2024-10-07 846414c9f32cb58ea96be01751d62c36a2e6c581 diff --git a/repos/os/recipes/api/event_session/hash b/repos/os/recipes/api/event_session/hash index ce7d8eae4b..03b89d9eb7 100644 --- a/repos/os/recipes/api/event_session/hash +++ b/repos/os/recipes/api/event_session/hash @@ -1 +1 @@ -2024-08-28 efc8cae4ad60f15c35191be401473f75927df3e7 +2024-10-07 7f32d92e111a6bbb1aba5f9ecb7c52ee68bdcf62 diff --git a/repos/os/recipes/api/framebuffer_session/hash b/repos/os/recipes/api/framebuffer_session/hash index b11528d168..4648443b32 100644 --- a/repos/os/recipes/api/framebuffer_session/hash +++ b/repos/os/recipes/api/framebuffer_session/hash @@ -1 +1 @@ -2024-08-28 2520ff6b0c289e79423e51d0a9094628cde1dea7 +2024-10-07 5df052ce4cd1c5d21e08f928cef91f6283d0cb27 diff --git a/repos/os/recipes/api/genode_c_api/hash b/repos/os/recipes/api/genode_c_api/hash index 11acf407bd..6c8583b408 100644 --- a/repos/os/recipes/api/genode_c_api/hash +++ b/repos/os/recipes/api/genode_c_api/hash @@ -1 +1 @@ -2024-08-28 209fd3a405bf7f8b81d2ab0431ca72ff5681e580 +2024-10-29 f03289b5e371461fbc31a14e004e4bee993d441d diff --git a/repos/os/recipes/api/gui_session/hash b/repos/os/recipes/api/gui_session/hash index 881969bbab..ffb3b9cf65 100644 --- a/repos/os/recipes/api/gui_session/hash +++ b/repos/os/recipes/api/gui_session/hash @@ -1 +1 @@ -2024-08-28 743930bf7e1e72fc1a800d624f32e2fc90af2def +2024-10-29 11e0d6f92de9e605c0d62c57f0ea97e99f3d6ca0 diff --git a/repos/os/recipes/api/input_session/hash b/repos/os/recipes/api/input_session/hash index ffd32ebdd3..4fb11529f3 100644 --- a/repos/os/recipes/api/input_session/hash +++ b/repos/os/recipes/api/input_session/hash @@ -1 +1 @@ -2024-08-28 aafe9f18aa692d8579d037680a4795a2cd2bb305 +2024-10-07 d86f6ad6bf2877aa0367b835d73a18faf257373c diff --git a/repos/os/recipes/api/os/hash b/repos/os/recipes/api/os/hash index ad167abbdc..da6423bda1 100644 --- a/repos/os/recipes/api/os/hash +++ b/repos/os/recipes/api/os/hash @@ -1 +1 @@ -2024-08-28 77fd0c06ea7ace45f14cd726323cfacbd76011de +2024-10-07 e1072a343816c9df02ffd24da0faf2608dd2e399 diff --git a/repos/os/recipes/api/usb_session/hash b/repos/os/recipes/api/usb_session/hash index fe18225c1c..3ccc38f775 100644 --- a/repos/os/recipes/api/usb_session/hash +++ b/repos/os/recipes/api/usb_session/hash @@ -1 +1 @@ -2024-08-28 ba9453393e9c51b889f0342c718ffaeeb1849af3 +2024-12-10 4b4dff6c9c4f756830dece1f937f376b90b53a43 diff --git a/repos/os/recipes/pkg/black_hole/hash b/repos/os/recipes/pkg/black_hole/hash index 6ca7906920..a3783587a8 100644 --- a/repos/os/recipes/pkg/black_hole/hash +++ b/repos/os/recipes/pkg/black_hole/hash @@ -1 +1 @@ -2024-08-28 c41e3dea50933b66bfaf6be475c6a2a064ab2ef9 +2024-12-10 e3681081231dc4fc9c3703a4a1545e0e4b37409b diff --git a/repos/os/recipes/pkg/chroot/hash b/repos/os/recipes/pkg/chroot/hash index 4246904813..a0af3166b2 100644 --- a/repos/os/recipes/pkg/chroot/hash +++ b/repos/os/recipes/pkg/chroot/hash @@ -1 +1 @@ -2024-08-28 574169841518f1c0ff6f785aa260eeb9ff489782 +2024-12-10 f2fed7cfd3f387125506ed6a11bb3810b0d9f964 diff --git a/repos/os/recipes/pkg/clipboard/hash b/repos/os/recipes/pkg/clipboard/hash index 78346bc17d..30cccbfba1 100644 --- a/repos/os/recipes/pkg/clipboard/hash +++ b/repos/os/recipes/pkg/clipboard/hash @@ -1 +1 @@ -2024-08-28 b97e68aa7d023000231fcecdd7e2903263b451b3 +2024-12-10 492ff2a325c9535cc69ffee2351375f9fddec731 diff --git a/repos/os/recipes/pkg/cpu_balancer/hash b/repos/os/recipes/pkg/cpu_balancer/hash index bdbec8cce6..fc98e85bdc 100644 --- a/repos/os/recipes/pkg/cpu_balancer/hash +++ b/repos/os/recipes/pkg/cpu_balancer/hash @@ -1 +1 @@ -2024-08-28 6f5f124ce6e94e91f5fdda65909dfbfb64addf50 +2024-12-10 2fe00f0435b9d9d9804bbfd4d4a1542918db1789 diff --git a/repos/os/recipes/pkg/cpu_balancer_config/hash b/repos/os/recipes/pkg/cpu_balancer_config/hash index 447fc455b4..260102865b 100644 --- a/repos/os/recipes/pkg/cpu_balancer_config/hash +++ b/repos/os/recipes/pkg/cpu_balancer_config/hash @@ -1 +1 @@ -2024-08-28 8c129d8c18d8e8d7a28acbafd0c1f60a5c9e8c3e +2024-12-10 5fc3cf48f89228ed7dbf7e59fd9b36d6bfa6c7f6 diff --git a/repos/os/recipes/pkg/cpu_burner/hash b/repos/os/recipes/pkg/cpu_burner/hash index d86ed7258b..87b292a887 100644 --- a/repos/os/recipes/pkg/cpu_burner/hash +++ b/repos/os/recipes/pkg/cpu_burner/hash @@ -1 +1 @@ -2024-08-28 b16411d09f9c69ad831846dd8e9eb411c476a9e4 +2024-12-10 16be55d5616f6c4ec4fea15ff69018427360fdd6 diff --git a/repos/os/recipes/pkg/drivers_interactive-linux/hash b/repos/os/recipes/pkg/drivers_interactive-linux/hash index 3e370964fe..a3a4255bf6 100644 --- a/repos/os/recipes/pkg/drivers_interactive-linux/hash +++ b/repos/os/recipes/pkg/drivers_interactive-linux/hash @@ -1 +1 @@ -2024-08-28 bd4874ac5a7f21e15691d508ae4331bb74cc3049 +2024-12-10 fc42f5f795a11177c6c5545666c466a5da5e01db diff --git a/repos/os/recipes/pkg/drivers_interactive-pbxa9/hash b/repos/os/recipes/pkg/drivers_interactive-pbxa9/hash index ca8887b3ac..1f07d348fc 100644 --- a/repos/os/recipes/pkg/drivers_interactive-pbxa9/hash +++ b/repos/os/recipes/pkg/drivers_interactive-pbxa9/hash @@ -1 +1 @@ -2024-08-28 de1fa92ab2cef7fd463c99676f4f092cf043743e +2024-12-10 c7d3072c0e52005c078ff75f35d1a5e6e53ccddf diff --git a/repos/os/recipes/pkg/drivers_interactive-pc/hash b/repos/os/recipes/pkg/drivers_interactive-pc/hash index 4d43ff09b5..a8997a790d 100644 --- a/repos/os/recipes/pkg/drivers_interactive-pc/hash +++ b/repos/os/recipes/pkg/drivers_interactive-pc/hash @@ -1 +1 @@ -2024-08-28 109e3c8cc189664b63ba59c4ca0698235f268402 +2024-12-10 9f8df43b519b6a7a8300ff6b26bb8eaf82fcf2ba diff --git a/repos/os/recipes/pkg/drivers_interactive-virt_qemu_arm_v7a/hash b/repos/os/recipes/pkg/drivers_interactive-virt_qemu_arm_v7a/hash index e5ce27285a..7f42bf435a 100644 --- a/repos/os/recipes/pkg/drivers_interactive-virt_qemu_arm_v7a/hash +++ b/repos/os/recipes/pkg/drivers_interactive-virt_qemu_arm_v7a/hash @@ -1 +1 @@ -2024-08-28 cafd9716b4fd61d6a795bfd377333147d3c35b10 +2024-12-10 20b440c9294b767999b80fc746b77fca8a8c5f87 diff --git a/repos/os/recipes/pkg/drivers_interactive-virt_qemu_arm_v8a/hash b/repos/os/recipes/pkg/drivers_interactive-virt_qemu_arm_v8a/hash index e5ce27285a..7f42bf435a 100644 --- a/repos/os/recipes/pkg/drivers_interactive-virt_qemu_arm_v8a/hash +++ b/repos/os/recipes/pkg/drivers_interactive-virt_qemu_arm_v8a/hash @@ -1 +1 @@ -2024-08-28 cafd9716b4fd61d6a795bfd377333147d3c35b10 +2024-12-10 20b440c9294b767999b80fc746b77fca8a8c5f87 diff --git a/repos/os/recipes/pkg/drivers_nic-linux/hash b/repos/os/recipes/pkg/drivers_nic-linux/hash index 2438b34fd1..8206799ef6 100644 --- a/repos/os/recipes/pkg/drivers_nic-linux/hash +++ b/repos/os/recipes/pkg/drivers_nic-linux/hash @@ -1 +1 @@ -2024-08-28 54e690478f563e83c392e55dd132ac7fb99f6ed2 +2024-12-10 17f69f524824be2030911853aa0b1180302ce191 diff --git a/repos/os/recipes/pkg/drivers_nic-pbxa9/hash b/repos/os/recipes/pkg/drivers_nic-pbxa9/hash index b438845206..9791e12151 100644 --- a/repos/os/recipes/pkg/drivers_nic-pbxa9/hash +++ b/repos/os/recipes/pkg/drivers_nic-pbxa9/hash @@ -1 +1 @@ -2024-08-28 d65a4113881a6c47c0d1b7096a393a62a93c8fef +2024-12-10 0171b3651dae8f5d082597a32be42a31e53dc071 diff --git a/repos/os/recipes/pkg/drivers_nic-virt_qemu_arm_v7a/hash b/repos/os/recipes/pkg/drivers_nic-virt_qemu_arm_v7a/hash index db7de4f307..9a75127517 100644 --- a/repos/os/recipes/pkg/drivers_nic-virt_qemu_arm_v7a/hash +++ b/repos/os/recipes/pkg/drivers_nic-virt_qemu_arm_v7a/hash @@ -1 +1 @@ -2024-08-28 205c036d7f12e793426d539b7359bad3f96c728b +2024-12-10 d9819b656958843401632e2314ebc26eca3d84c0 diff --git a/repos/os/recipes/pkg/drivers_nic-virt_qemu_arm_v8a/hash b/repos/os/recipes/pkg/drivers_nic-virt_qemu_arm_v8a/hash index db7de4f307..9a75127517 100644 --- a/repos/os/recipes/pkg/drivers_nic-virt_qemu_arm_v8a/hash +++ b/repos/os/recipes/pkg/drivers_nic-virt_qemu_arm_v8a/hash @@ -1 +1 @@ -2024-08-28 205c036d7f12e793426d539b7359bad3f96c728b +2024-12-10 d9819b656958843401632e2314ebc26eca3d84c0 diff --git a/repos/os/recipes/pkg/dynamic_rom/hash b/repos/os/recipes/pkg/dynamic_rom/hash index d0c9d402b4..423099156a 100644 --- a/repos/os/recipes/pkg/dynamic_rom/hash +++ b/repos/os/recipes/pkg/dynamic_rom/hash @@ -1 +1 @@ -2024-08-28 a7ce460f1edb73e7ecc8aa92545b3971b571339e +2024-12-10 143522de81d54116bf6c45bb336053398238f474 diff --git a/repos/os/recipes/pkg/fs_report/hash b/repos/os/recipes/pkg/fs_report/hash index 1ada6b2f39..913be7a43b 100644 --- a/repos/os/recipes/pkg/fs_report/hash +++ b/repos/os/recipes/pkg/fs_report/hash @@ -1 +1 @@ -2024-08-28 49111736f6156f9abd2daa7066667d90d399f463 +2024-12-10 8dec5187f0a206815d3aca76eeefc15039d87943 diff --git a/repos/os/recipes/pkg/fs_rom/hash b/repos/os/recipes/pkg/fs_rom/hash index 66daadfc91..70186fcd4f 100644 --- a/repos/os/recipes/pkg/fs_rom/hash +++ b/repos/os/recipes/pkg/fs_rom/hash @@ -1 +1 @@ -2024-08-28 13078f911302683682fe15fbdcab79174f53845e +2024-12-10 db8040e8ea9638a67bdf4cbc890169715515015c diff --git a/repos/os/recipes/pkg/mixer/hash b/repos/os/recipes/pkg/mixer/hash index 9898fe2b77..d0825ea5d8 100644 --- a/repos/os/recipes/pkg/mixer/hash +++ b/repos/os/recipes/pkg/mixer/hash @@ -1 +1 @@ -2024-08-28 c5d05408a5d9bd04048e71f6747bb045ba04154d +2024-12-10 c0baa924c868bf386dbc97159c8d9f8b1d49c48f diff --git a/repos/os/recipes/pkg/nic_router-nat/hash b/repos/os/recipes/pkg/nic_router-nat/hash index b555b69ade..1571b343f5 100644 --- a/repos/os/recipes/pkg/nic_router-nat/hash +++ b/repos/os/recipes/pkg/nic_router-nat/hash @@ -1 +1 @@ -2024-08-28 c53c80c66a5ae6a656049168cfe9269dc8f3305c +2024-12-10 005b1e6ed934fe274f9f3ff9b1b32da6e38d89e8 diff --git a/repos/os/recipes/pkg/nic_uplink/hash b/repos/os/recipes/pkg/nic_uplink/hash index ecf6e9cead..6e90d199a6 100644 --- a/repos/os/recipes/pkg/nic_uplink/hash +++ b/repos/os/recipes/pkg/nic_uplink/hash @@ -1 +1 @@ -2024-08-28 4de53d351628ac0d8357ae131f2ac1a5e29c1c52 +2024-12-10 6400a3d7afc7915a52bc6cbff8e4e183ff413c81 diff --git a/repos/os/recipes/pkg/nit_focus/hash b/repos/os/recipes/pkg/nit_focus/hash index ca6d3466b5..e212962b87 100644 --- a/repos/os/recipes/pkg/nit_focus/hash +++ b/repos/os/recipes/pkg/nit_focus/hash @@ -1 +1 @@ -2024-08-28 4159f75b3dfa458441a9123c31caceeec870dbb1 +2024-12-10 4f248ac41db024a2bef58aa3bdd5eb3ce638a001 diff --git a/repos/os/recipes/pkg/nitpicker/hash b/repos/os/recipes/pkg/nitpicker/hash index ef8205576e..bc8768ceae 100644 --- a/repos/os/recipes/pkg/nitpicker/hash +++ b/repos/os/recipes/pkg/nitpicker/hash @@ -1 +1 @@ -2024-08-28 e5213ed6fe0f7e5886be8485dbce0b3735c2e8d3 +2024-12-10 26ad5051afd3dd8d7227d38b5d69c9d3613eb477 diff --git a/repos/os/recipes/pkg/part_block/hash b/repos/os/recipes/pkg/part_block/hash index fec8aec574..2027c839bd 100644 --- a/repos/os/recipes/pkg/part_block/hash +++ b/repos/os/recipes/pkg/part_block/hash @@ -1 +1 @@ -2024-08-28 423e0d1e28d25cf62015b0f1ff8ab9b7cc1468b3 +2024-12-10 136eee960b7709875cb83cada916f91c5dc1ea59 diff --git a/repos/os/recipes/pkg/ping/hash b/repos/os/recipes/pkg/ping/hash index f066c4bda4..a79e6a19ca 100644 --- a/repos/os/recipes/pkg/ping/hash +++ b/repos/os/recipes/pkg/ping/hash @@ -1 +1 @@ -2024-08-28 7202d580bb7ef6e8aaaf43df2536765f8ae5a050 +2024-12-10 9ac6fb2550fbc5083bb346d932c612c446177a51 diff --git a/repos/os/recipes/pkg/recall_fs/hash b/repos/os/recipes/pkg/recall_fs/hash index 2ea94753fc..9046b0fb6c 100644 --- a/repos/os/recipes/pkg/recall_fs/hash +++ b/repos/os/recipes/pkg/recall_fs/hash @@ -1 +1 @@ -2024-08-28 ed8c24ef4bee8bd853e816347f3da18ce0ef7ba7 +2024-12-10 126809511e7c96a49bcc4109ccea98102afc9495 diff --git a/repos/os/recipes/pkg/record_play_mixer/hash b/repos/os/recipes/pkg/record_play_mixer/hash index 0ec3726376..df66f4e79e 100644 --- a/repos/os/recipes/pkg/record_play_mixer/hash +++ b/repos/os/recipes/pkg/record_play_mixer/hash @@ -1 +1 @@ -2024-08-28 b11e46e3cf255aff47e40ffec6d7f51af7ddf9fd +2024-12-10 855cac282025e574e9a9619bfc063dbd0fa3700d diff --git a/repos/os/recipes/pkg/record_rom/hash b/repos/os/recipes/pkg/record_rom/hash index b559ee71aa..d82a67aacd 100644 --- a/repos/os/recipes/pkg/record_rom/hash +++ b/repos/os/recipes/pkg/record_rom/hash @@ -1 +1 @@ -2024-08-28 3714f312145c741e2f5425025fbb1b3dd94b357f +2024-12-10 644594d70aedeba0044a2158533659fc4a97dc3e diff --git a/repos/os/recipes/pkg/report_rom/hash b/repos/os/recipes/pkg/report_rom/hash index 5c07f5263e..830cf93c0c 100644 --- a/repos/os/recipes/pkg/report_rom/hash +++ b/repos/os/recipes/pkg/report_rom/hash @@ -1 +1 @@ -2024-08-28 ae5367e47fc1ced31e2158b331fdf65cb0f33181 +2024-12-10 b9df2d3f4b377dcbffc74699f3f8b4ea2ae62322 diff --git a/repos/os/recipes/pkg/rom_filter/hash b/repos/os/recipes/pkg/rom_filter/hash index 973f158981..66c9a18ca7 100644 --- a/repos/os/recipes/pkg/rom_filter/hash +++ b/repos/os/recipes/pkg/rom_filter/hash @@ -1 +1 @@ -2024-08-28 29f4002b075425f892404a7556d437485f4be670 +2024-12-10 e2941bcefa91bc1c10f7f613a5448d74f8eb64e4 diff --git a/repos/os/recipes/pkg/rom_reporter/hash b/repos/os/recipes/pkg/rom_reporter/hash index 82b18496ba..53dc464e2d 100644 --- a/repos/os/recipes/pkg/rom_reporter/hash +++ b/repos/os/recipes/pkg/rom_reporter/hash @@ -1 +1 @@ -2024-08-28 7963fe27e4221b7bdf046e93276c010a1712b665 +2024-12-10 237deb1aa4f2529673a94d62b6af56dd2a794200 diff --git a/repos/os/recipes/pkg/terminal_crosslink/hash b/repos/os/recipes/pkg/terminal_crosslink/hash index fefabb039d..76977444e9 100644 --- a/repos/os/recipes/pkg/terminal_crosslink/hash +++ b/repos/os/recipes/pkg/terminal_crosslink/hash @@ -1 +1 @@ -2024-08-28 f50f4f35b082febd80be925adeef6436bb2ba1d8 +2024-12-10 f2d581ac003d2fd10358fffb42c9f6bf8165b913 diff --git a/repos/os/recipes/pkg/test-audio_out/hash b/repos/os/recipes/pkg/test-audio_out/hash index 075504dad1..8ac508c916 100644 --- a/repos/os/recipes/pkg/test-audio_out/hash +++ b/repos/os/recipes/pkg/test-audio_out/hash @@ -1 +1 @@ -2024-08-28 cb7fdcc7e9bfbea1d0863e63bd4a8e6bd302fd56 +2024-12-10 7968e132ca758d6e0e7ea2ac1d7c8780ae4a2d42 diff --git a/repos/os/recipes/pkg/test-black_hole/hash b/repos/os/recipes/pkg/test-black_hole/hash index d5bc7096d9..f0b35c9278 100644 --- a/repos/os/recipes/pkg/test-black_hole/hash +++ b/repos/os/recipes/pkg/test-black_hole/hash @@ -1 +1 @@ -2024-08-28 15ab3da16f3a2751426cfd0ee039bf680ddd08e2 +2024-12-10 44b10a4df0900e97ea2d98762488d98e213d6663 diff --git a/repos/os/recipes/pkg/test-capture/hash b/repos/os/recipes/pkg/test-capture/hash index a2c1e76aed..c48707c51a 100644 --- a/repos/os/recipes/pkg/test-capture/hash +++ b/repos/os/recipes/pkg/test-capture/hash @@ -1 +1 @@ -2024-08-28 6ff1d504e233f04cc84a122d3eb9e06a3c6581e9 +2024-12-10 430cff18a2bfb4400a1db9e30156702b5bbde4db diff --git a/repos/os/recipes/pkg/test-clipboard/hash b/repos/os/recipes/pkg/test-clipboard/hash index 180dff6683..d667de1095 100644 --- a/repos/os/recipes/pkg/test-clipboard/hash +++ b/repos/os/recipes/pkg/test-clipboard/hash @@ -1 +1 @@ -2024-08-28 5c051f8ca01c7f62c96990e0d5202a7431e954a6 +2024-12-10 c46c8be63a92aec44be6278857c2939151cbb0d3 diff --git a/repos/os/recipes/pkg/test-dynamic_config/hash b/repos/os/recipes/pkg/test-dynamic_config/hash index 76a3bef7b0..155fce9bb7 100644 --- a/repos/os/recipes/pkg/test-dynamic_config/hash +++ b/repos/os/recipes/pkg/test-dynamic_config/hash @@ -1 +1 @@ -2024-08-28 842554dbf104a5b3a6a14afd897b9c3244266054 +2024-12-10 ab1b092f3a2726e489ccb74d19318d2b5babd793 diff --git a/repos/os/recipes/pkg/test-fault_detection/hash b/repos/os/recipes/pkg/test-fault_detection/hash index c4d13056b9..0d9555c573 100644 --- a/repos/os/recipes/pkg/test-fault_detection/hash +++ b/repos/os/recipes/pkg/test-fault_detection/hash @@ -1 +1 @@ -2024-08-28 ee0974f68b3bb803e51f494eec941316eb71391b +2024-12-10 75b56aa54d0a57259e3207a78edd913ec9474f62 diff --git a/repos/os/recipes/pkg/test-fs_packet/hash b/repos/os/recipes/pkg/test-fs_packet/hash index 5a7fc0456a..f5fb98a535 100644 --- a/repos/os/recipes/pkg/test-fs_packet/hash +++ b/repos/os/recipes/pkg/test-fs_packet/hash @@ -1 +1 @@ -2024-08-28 251061004e6917ebcf1a6758de1e7f0f0fedb31e +2024-12-10 8f401ff865cce40e9ab876265add90bb7976a15d diff --git a/repos/os/recipes/pkg/test-fs_report/hash b/repos/os/recipes/pkg/test-fs_report/hash index 1b731a875e..aaeeff65a5 100644 --- a/repos/os/recipes/pkg/test-fs_report/hash +++ b/repos/os/recipes/pkg/test-fs_report/hash @@ -1 +1 @@ -2024-08-28 0a6bdffbf892b1ad34c0bdf56aaa0e68a518ea7b +2024-12-10 80a177ba94a610b43a47d69123f3e6cef7f0312e diff --git a/repos/os/recipes/pkg/test-fs_rom_update/hash b/repos/os/recipes/pkg/test-fs_rom_update/hash index c823563123..836339a6ad 100644 --- a/repos/os/recipes/pkg/test-fs_rom_update/hash +++ b/repos/os/recipes/pkg/test-fs_rom_update/hash @@ -1 +1 @@ -2024-08-28 d9d37961539259f27b6ec79e73dfb00b2e36c184 +2024-12-10 84c8695c2dbe6500306246662ad38d9f4ae11d57 diff --git a/repos/os/recipes/pkg/test-fs_rom_update_fs/hash b/repos/os/recipes/pkg/test-fs_rom_update_fs/hash index c253704af2..7b921450a0 100644 --- a/repos/os/recipes/pkg/test-fs_rom_update_fs/hash +++ b/repos/os/recipes/pkg/test-fs_rom_update_fs/hash @@ -1 +1 @@ -2024-08-28 e3c7f02a31c15ea1d69932c267d97487fc3ec179 +2024-12-10 92c8f8ad5b54418a58af71a6e52ee23b17626248 diff --git a/repos/os/recipes/pkg/test-fs_rom_update_ram/hash b/repos/os/recipes/pkg/test-fs_rom_update_ram/hash index e4664f19cb..895e11ae97 100644 --- a/repos/os/recipes/pkg/test-fs_rom_update_ram/hash +++ b/repos/os/recipes/pkg/test-fs_rom_update_ram/hash @@ -1 +1 @@ -2024-08-28 4a13ad948a5caa7da0b8114e02dba7a6c7c2b105 +2024-12-10 d1180e8e24784e906d6e96f5099d1ebcc20d3b8a diff --git a/repos/os/recipes/pkg/test-init/hash b/repos/os/recipes/pkg/test-init/hash index 5d2054fdd9..b79e578237 100644 --- a/repos/os/recipes/pkg/test-init/hash +++ b/repos/os/recipes/pkg/test-init/hash @@ -1 +1 @@ -2024-08-28 0b2606f42a47c2c7f61a5bcdd10ea67e6b00a1a4 +2024-12-10 3ccf04d59d0a2057e500c721e69a507c4b8635f6 diff --git a/repos/os/recipes/pkg/test-init_loop/hash b/repos/os/recipes/pkg/test-init_loop/hash index c1ecdfe623..ae7bead5fd 100644 --- a/repos/os/recipes/pkg/test-init_loop/hash +++ b/repos/os/recipes/pkg/test-init_loop/hash @@ -1 +1 @@ -2024-08-28 1e90ae1676a0901ab5577d92adff5614f46d24ff +2024-12-10 be45da1f7d34e89dcff8462ba324e0520a0a5271 diff --git a/repos/os/recipes/pkg/test-lx_block/hash b/repos/os/recipes/pkg/test-lx_block/hash index 3289795d3d..3ab5f49bd5 100644 --- a/repos/os/recipes/pkg/test-lx_block/hash +++ b/repos/os/recipes/pkg/test-lx_block/hash @@ -1 +1 @@ -2024-08-28 a3e201e0b27969eec7bb37eb4e47e84b41bb96c7 +2024-12-10 c6663eede2843fffafc4b012e74618f857f089c3 diff --git a/repos/os/recipes/pkg/test-nic_loopback/hash b/repos/os/recipes/pkg/test-nic_loopback/hash index 1765cd704d..ee6e84d418 100644 --- a/repos/os/recipes/pkg/test-nic_loopback/hash +++ b/repos/os/recipes/pkg/test-nic_loopback/hash @@ -1 +1 @@ -2024-08-28 6b2050d8f09e76e35d9400a842f6e335a0b4f25f +2024-12-10 34771214c33eb6523a5ef3f1df1ca54eb2dacfc5 diff --git a/repos/os/recipes/pkg/test-nic_perf/hash b/repos/os/recipes/pkg/test-nic_perf/hash index 0da517b1f5..d4f3a8c0b7 100644 --- a/repos/os/recipes/pkg/test-nic_perf/hash +++ b/repos/os/recipes/pkg/test-nic_perf/hash @@ -1 +1 @@ -2024-08-28 ae90325a552fc6a9f0b7e2052e58e3a16055aa5f +2024-12-10 8acd02819376377d22ba36246340fe3b126c66f1 diff --git a/repos/os/recipes/pkg/test-nic_perf_router/hash b/repos/os/recipes/pkg/test-nic_perf_router/hash index bfb2b4bb81..0431f3f70a 100644 --- a/repos/os/recipes/pkg/test-nic_perf_router/hash +++ b/repos/os/recipes/pkg/test-nic_perf_router/hash @@ -1 +1 @@ -2024-08-28 fce14cb27791ef5d6c7816b3ba5ce834deb68141 +2024-12-10 b0fab2e5114cecfae163121f4a7bb9aee681803b diff --git a/repos/os/recipes/pkg/test-part_block_ahdi/hash b/repos/os/recipes/pkg/test-part_block_ahdi/hash index 8484f8d5ec..1fffe6e099 100644 --- a/repos/os/recipes/pkg/test-part_block_ahdi/hash +++ b/repos/os/recipes/pkg/test-part_block_ahdi/hash @@ -1 +1 @@ -2024-08-28 6ce89e36bb7943b4249be6e68abbe0770c3cc111 +2024-12-10 7636559fae5b7c62bc11cfede0ab413fa5f6f8fc diff --git a/repos/os/recipes/pkg/test-part_block_disk/hash b/repos/os/recipes/pkg/test-part_block_disk/hash index 593a1a5da3..7955b81b78 100644 --- a/repos/os/recipes/pkg/test-part_block_disk/hash +++ b/repos/os/recipes/pkg/test-part_block_disk/hash @@ -1 +1 @@ -2024-08-28 5a1a961235741ed2207769c134d9991425b5d702 +2024-12-10 7bde5f71e60dafe61cedf7e5bd6d811cabf8e424 diff --git a/repos/os/recipes/pkg/test-part_block_gpt/hash b/repos/os/recipes/pkg/test-part_block_gpt/hash index df4bcca5b6..e9a3fd12ea 100644 --- a/repos/os/recipes/pkg/test-part_block_gpt/hash +++ b/repos/os/recipes/pkg/test-part_block_gpt/hash @@ -1 +1 @@ -2024-08-28 dd0429546ec7fd239230674f5c68753900e7d7d3 +2024-12-10 eebf628d9bf993214af044c359bf28e7cda86f17 diff --git a/repos/os/recipes/pkg/test-part_block_mbr/hash b/repos/os/recipes/pkg/test-part_block_mbr/hash index 3b9b506731..c754b2717f 100644 --- a/repos/os/recipes/pkg/test-part_block_mbr/hash +++ b/repos/os/recipes/pkg/test-part_block_mbr/hash @@ -1 +1 @@ -2024-08-28 66fe19ccdd230143010a96a9c54f434c126560d9 +2024-12-10 f3df580afeaf1f5b63caf9663c9bb5b21d31b8f7 diff --git a/repos/os/recipes/pkg/test-path/hash b/repos/os/recipes/pkg/test-path/hash index 862dd97f81..0e26a15a52 100644 --- a/repos/os/recipes/pkg/test-path/hash +++ b/repos/os/recipes/pkg/test-path/hash @@ -1 +1 @@ -2024-08-28 5498469e18cf4dfdd5038adcde6eaeba6983e8d6 +2024-12-10 4c467afa2e10dae7daf0ae966448c5e893029008 diff --git a/repos/os/recipes/pkg/test-ram_fs_chunk/hash b/repos/os/recipes/pkg/test-ram_fs_chunk/hash index fdf683fed3..67a995a515 100644 --- a/repos/os/recipes/pkg/test-ram_fs_chunk/hash +++ b/repos/os/recipes/pkg/test-ram_fs_chunk/hash @@ -1 +1 @@ -2024-08-28 93b2e25bc33bf1977e97f4db5594b0c3de7970bd +2024-12-10 0cfa6a45b39a1b00350891e4f45bf49f4cc33cd8 diff --git a/repos/os/recipes/pkg/test-read_only_rom/hash b/repos/os/recipes/pkg/test-read_only_rom/hash index 4db0e1cb0c..4b8af349a7 100644 --- a/repos/os/recipes/pkg/test-read_only_rom/hash +++ b/repos/os/recipes/pkg/test-read_only_rom/hash @@ -1 +1 @@ -2024-08-28 7b4312a61c7885d47b01b277e4105a8b00521c3a +2024-12-10 292c21344f80ab656b55a18266e4aec9c2796872 diff --git a/repos/os/recipes/pkg/test-report_rom/hash b/repos/os/recipes/pkg/test-report_rom/hash index 4ec8df9a91..ce1e2703f6 100644 --- a/repos/os/recipes/pkg/test-report_rom/hash +++ b/repos/os/recipes/pkg/test-report_rom/hash @@ -1 +1 @@ -2024-08-28 4d6313bac482f836be5661382dea0fdfdd94881e +2024-12-10 db39ab6adbb08b565e7f0b195ed7672048a7bf6e diff --git a/repos/os/recipes/pkg/test-resource_request/hash b/repos/os/recipes/pkg/test-resource_request/hash index bb39dab888..9437f47416 100644 --- a/repos/os/recipes/pkg/test-resource_request/hash +++ b/repos/os/recipes/pkg/test-resource_request/hash @@ -1 +1 @@ -2024-08-28 c37ce63b507e4d2dcd178a3702c021eb14f0fca3 +2024-12-10 a4620d85337e88e504f44224202f96c1f7e300c6 diff --git a/repos/os/recipes/pkg/test-resource_yield/hash b/repos/os/recipes/pkg/test-resource_yield/hash index 1d6d1cb260..fc052a4672 100644 --- a/repos/os/recipes/pkg/test-resource_yield/hash +++ b/repos/os/recipes/pkg/test-resource_yield/hash @@ -1 +1 @@ -2024-08-28 b8ce62db44a3c559567eb00d843a77ba4f9cb2fa +2024-12-10 8c393666f30645dc89e26a3631139c53e4e6051e diff --git a/repos/os/recipes/pkg/test-rom_filter/hash b/repos/os/recipes/pkg/test-rom_filter/hash index 8b3a0a116f..053c356e4d 100644 --- a/repos/os/recipes/pkg/test-rom_filter/hash +++ b/repos/os/recipes/pkg/test-rom_filter/hash @@ -1 +1 @@ -2024-08-28 178400ea34d3205bfe85326940c88a2b5e98dcbc +2024-12-10 93a11acd4a9953358410fa5afa20816c1ef7dac7 diff --git a/repos/os/recipes/pkg/test-rtc/hash b/repos/os/recipes/pkg/test-rtc/hash index 87bd8be3ea..6be5791abe 100644 --- a/repos/os/recipes/pkg/test-rtc/hash +++ b/repos/os/recipes/pkg/test-rtc/hash @@ -1 +1 @@ -2024-08-28 aa2942f41357f27d25222aee950c33e7cf2a8ea9 +2024-12-10 ad0fcb040c71adc05524a2b51d5200abe17f9df8 diff --git a/repos/os/recipes/pkg/test-sandbox/hash b/repos/os/recipes/pkg/test-sandbox/hash index a491787c8f..7094c5446d 100644 --- a/repos/os/recipes/pkg/test-sandbox/hash +++ b/repos/os/recipes/pkg/test-sandbox/hash @@ -1 +1 @@ -2024-08-28 a3e3f9058e5434eda22d399c974f79ae081f5c3c +2024-12-10 cf18ec19a780a790da0ca29da408f343709fd6df diff --git a/repos/os/recipes/pkg/test-signal/hash b/repos/os/recipes/pkg/test-signal/hash index 2f4939df6f..689b3363e5 100644 --- a/repos/os/recipes/pkg/test-signal/hash +++ b/repos/os/recipes/pkg/test-signal/hash @@ -1 +1 @@ -2024-08-28 ba3c45f067b60dc46beb0a8c1d55c4b7e59b9919 +2024-12-10 6651448b967acfa6fa35490c33ba66468ca15844 diff --git a/repos/os/recipes/pkg/test-slab/hash b/repos/os/recipes/pkg/test-slab/hash index e9d97b2298..7dee375c10 100644 --- a/repos/os/recipes/pkg/test-slab/hash +++ b/repos/os/recipes/pkg/test-slab/hash @@ -1 +1 @@ -2024-08-28 e1cf31b4c376d205af8b517258c2c219fe204129 +2024-12-10 8e93f19b150b87f17cfc7da9d43dfd77d08058c5 diff --git a/repos/os/recipes/pkg/test-terminal_crosslink/hash b/repos/os/recipes/pkg/test-terminal_crosslink/hash index 708f5d84a0..80ab231bcb 100644 --- a/repos/os/recipes/pkg/test-terminal_crosslink/hash +++ b/repos/os/recipes/pkg/test-terminal_crosslink/hash @@ -1 +1 @@ -2024-08-28 4422c86c1cc849fc6818bb1795b6845c35b1abc4 +2024-12-10 439e12769dd1b10a7fbca67f8a3600ed85c73e85 diff --git a/repos/os/recipes/pkg/test-trace/hash b/repos/os/recipes/pkg/test-trace/hash index c4b25cd2c0..f498beb4b5 100644 --- a/repos/os/recipes/pkg/test-trace/hash +++ b/repos/os/recipes/pkg/test-trace/hash @@ -1 +1 @@ -2024-08-28 5a5402d0eb78610eb6809a7dbed567b7e0290d21 +2024-12-10 8b1d9c5d8c0e1fc25fb73f82e9fbd17a2b1562f3 diff --git a/repos/os/recipes/pkg/test-trace_buffer/hash b/repos/os/recipes/pkg/test-trace_buffer/hash index 849b99a860..9319adf9f6 100644 --- a/repos/os/recipes/pkg/test-trace_buffer/hash +++ b/repos/os/recipes/pkg/test-trace_buffer/hash @@ -1 +1 @@ -2024-08-28 25892f30627ae46aa946fd417bc2793372dd4076 +2024-12-10 cd133a9fdbb0c03d2eb90855214f04895dac2158 diff --git a/repos/os/recipes/pkg/test-trace_logger/hash b/repos/os/recipes/pkg/test-trace_logger/hash index 6e9e2ff3a1..563704837e 100644 --- a/repos/os/recipes/pkg/test-trace_logger/hash +++ b/repos/os/recipes/pkg/test-trace_logger/hash @@ -1 +1 @@ -2024-08-28 f1298cfe71193082724a00cade803279bbcdb173 +2024-12-10 34659066c9f8136a068de2c950a667af4723c5d1 diff --git a/repos/os/recipes/pkg/test-utf8/hash b/repos/os/recipes/pkg/test-utf8/hash index db9c50c2d2..fbb1527479 100644 --- a/repos/os/recipes/pkg/test-utf8/hash +++ b/repos/os/recipes/pkg/test-utf8/hash @@ -1 +1 @@ -2024-08-28 863444372f9a90b2716155cb6504e4c55dcfad71 +2024-12-10 f3c0f3112925869ae49f117e4c4155118b6411cd diff --git a/repos/os/recipes/pkg/test-vfs_block/hash b/repos/os/recipes/pkg/test-vfs_block/hash index 6dcbe2dad0..10e4d08d1f 100644 --- a/repos/os/recipes/pkg/test-vfs_block/hash +++ b/repos/os/recipes/pkg/test-vfs_block/hash @@ -1 +1 @@ -2024-08-28 a9de0e9530bea26db56d29db03e4b20ecc1ca60a +2024-12-10 eeca3761f9434183be43b6cd540065ffed9f2b5f diff --git a/repos/os/recipes/pkg/test-vfs_capture/README b/repos/os/recipes/pkg/test-vfs_capture/README new file mode 100644 index 0000000000..350afd5dad --- /dev/null +++ b/repos/os/recipes/pkg/test-vfs_capture/README @@ -0,0 +1,2 @@ + + Test for the VFS capture session plugin diff --git a/repos/os/recipes/pkg/test-vfs_capture/archives b/repos/os/recipes/pkg/test-vfs_capture/archives new file mode 100644 index 0000000000..073845e71d --- /dev/null +++ b/repos/os/recipes/pkg/test-vfs_capture/archives @@ -0,0 +1,3 @@ +_/src/test-vfs_capture +_/src/vfs +_/src/vfs_capture diff --git a/repos/os/recipes/pkg/test-vfs_capture/hash b/repos/os/recipes/pkg/test-vfs_capture/hash new file mode 100644 index 0000000000..115ce4be5f --- /dev/null +++ b/repos/os/recipes/pkg/test-vfs_capture/hash @@ -0,0 +1 @@ +2024-12-10-c f3182fa61f59571b2a102df0b5e1278ecfedecb1 diff --git a/repos/os/recipes/pkg/test-vfs_capture/runtime b/repos/os/recipes/pkg/test-vfs_capture/runtime new file mode 100644 index 0000000000..6dd1345baa --- /dev/null +++ b/repos/os/recipes/pkg/test-vfs_capture/runtime @@ -0,0 +1,18 @@ +<runtime ram="8M" caps="200" binary="test-vfs_capture"> + + <requires> <capture/> <gui/> <timer/> </requires> + + <config period_ms="20" width="1024" height="768"> + <vfs><dir name="dev"><capture/></dir></vfs> + <view/> + </config> + + <content> + <rom label="ld.lib.so"/> + <rom label="test-vfs_capture"/> + <rom label="vfs"/> + <rom label="vfs.lib.so"/> + <rom label="vfs_capture.lib.so"/> + </content> + +</runtime> diff --git a/repos/os/recipes/pkg/test-vfs_stress_fs/hash b/repos/os/recipes/pkg/test-vfs_stress_fs/hash index 8802c4c09c..3041954c8b 100644 --- a/repos/os/recipes/pkg/test-vfs_stress_fs/hash +++ b/repos/os/recipes/pkg/test-vfs_stress_fs/hash @@ -1 +1 @@ -2024-08-28 77eb8d1bfe000cb018983e7dcd116e4a15ade031 +2024-12-10 fa3eb4c5118eebbae25b5b78a77f4e7129a58857 diff --git a/repos/os/recipes/pkg/test-vfs_stress_ram/hash b/repos/os/recipes/pkg/test-vfs_stress_ram/hash index 91649440f2..3ab9a495d6 100644 --- a/repos/os/recipes/pkg/test-vfs_stress_ram/hash +++ b/repos/os/recipes/pkg/test-vfs_stress_ram/hash @@ -1 +1 @@ -2024-08-28 f64cfc165893d5eb69fc1123cf7f134989db9b37 +2024-12-10 6aa2d5b4e845628874e5e883c6922a135a9772c5 diff --git a/repos/os/recipes/pkg/test-weak_ptr/hash b/repos/os/recipes/pkg/test-weak_ptr/hash index 64051135aa..652ba759f6 100644 --- a/repos/os/recipes/pkg/test-weak_ptr/hash +++ b/repos/os/recipes/pkg/test-weak_ptr/hash @@ -1 +1 @@ -2024-08-28 c9e90f0aa074fed1a20d4a31a896646ffbfaf90d +2024-12-10 3a190e230f73ce1bbfe13b9d05e18cbf67663ae8 diff --git a/repos/os/recipes/pkg/top/hash b/repos/os/recipes/pkg/top/hash index 2bf65625b6..5be4b1cf14 100644 --- a/repos/os/recipes/pkg/top/hash +++ b/repos/os/recipes/pkg/top/hash @@ -1 +1 @@ -2024-08-28 d7e0424e702d4a5590877758d9480b8bcac31b3a +2024-12-10 b3518ad2b844590d173d502b7105b6de2d9c0c53 diff --git a/repos/os/recipes/pkg/trace_logger/hash b/repos/os/recipes/pkg/trace_logger/hash index d06e4e1697..a344b86cb3 100644 --- a/repos/os/recipes/pkg/trace_logger/hash +++ b/repos/os/recipes/pkg/trace_logger/hash @@ -1 +1 @@ -2024-08-28 00665e0359842337c2d74625235b5bc1337d196e +2024-12-10 aad0a3f76bdc9be33d7c84d70b392e00a5a1e3a6 diff --git a/repos/os/recipes/pkg/vfs/hash b/repos/os/recipes/pkg/vfs/hash index 85c5adc7ed..289e782afc 100644 --- a/repos/os/recipes/pkg/vfs/hash +++ b/repos/os/recipes/pkg/vfs/hash @@ -1 +1 @@ -2024-08-28 00d243d66ffc9dd572b68a15aacc9873070a9146 +2024-12-10 b2c85c9380fb3f56dc310b06f6e17335ee32da03 diff --git a/repos/os/recipes/pkg/vfs_block/hash b/repos/os/recipes/pkg/vfs_block/hash index c7309569b7..abd7955098 100644 --- a/repos/os/recipes/pkg/vfs_block/hash +++ b/repos/os/recipes/pkg/vfs_block/hash @@ -1 +1 @@ -2024-08-28 5bd7e196ae824cd85dfafb7c8392d9e864b5171f +2024-12-10 ce23eea170b0ca521afa68d737d612c8c5f2fc5f diff --git a/repos/os/recipes/pkg/waveform_player/hash b/repos/os/recipes/pkg/waveform_player/hash index d97f888f26..86442a2113 100644 --- a/repos/os/recipes/pkg/waveform_player/hash +++ b/repos/os/recipes/pkg/waveform_player/hash @@ -1 +1 @@ -2024-08-28 eb0e8dafd06e991b175b474fd73781b08fd87d2d +2024-12-10 608ca6d121e9c0bd01c3610aef2b4ae3140af221 diff --git a/repos/os/recipes/src/acpi/hash b/repos/os/recipes/src/acpi/hash index a1ed2dae4a..42c27fa739 100644 --- a/repos/os/recipes/src/acpi/hash +++ b/repos/os/recipes/src/acpi/hash @@ -1 +1 @@ -2024-08-28 2fd2f87bbcf296e1e10159ece5ab700534e5039f +2024-12-10 6c176b3b33d8ab0c8f233d4baa1ef610231ce453 diff --git a/repos/os/recipes/src/ahci/hash b/repos/os/recipes/src/ahci/hash index 547452230d..b65f9ef79b 100644 --- a/repos/os/recipes/src/ahci/hash +++ b/repos/os/recipes/src/ahci/hash @@ -1 +1 @@ -2024-08-28 3e23b7249f34258a15c095a4ad1542168b107a7d +2024-12-10 b7150dd8a071eae80a708e83cd37d1d55780b6e1 diff --git a/repos/os/recipes/src/black_hole/hash b/repos/os/recipes/src/black_hole/hash index 1ca68e550a..aed15c05cd 100644 --- a/repos/os/recipes/src/black_hole/hash +++ b/repos/os/recipes/src/black_hole/hash @@ -1 +1 @@ -2024-08-28 4962dc655cb9fa2908a5168c8a7934636f48e635 +2024-12-10 79e77ad57dad4f7d1aaec19775a0152c6fcbb52a diff --git a/repos/os/recipes/src/block_tester/hash b/repos/os/recipes/src/block_tester/hash index c590dcaf9d..ef25e48081 100644 --- a/repos/os/recipes/src/block_tester/hash +++ b/repos/os/recipes/src/block_tester/hash @@ -1 +1 @@ -2024-08-28 7d29036c6589004365584f99d5df8b9ce0ba641d +2024-12-10 dae172832f4807555576543f357da42f71e7504b diff --git a/repos/os/recipes/src/boot_fb/hash b/repos/os/recipes/src/boot_fb/hash index 9e37f31477..bbb7b6f6f9 100644 --- a/repos/os/recipes/src/boot_fb/hash +++ b/repos/os/recipes/src/boot_fb/hash @@ -1 +1 @@ -2024-08-28 bb7ff929095525804b70526ad4748aefce6e3769 +2024-12-10 b6a060efcd81d6c6f3abbd24d259824c0a31a209 diff --git a/repos/os/recipes/src/cached_fs_rom/hash b/repos/os/recipes/src/cached_fs_rom/hash index 8f9f285bbf..c88f7b474a 100644 --- a/repos/os/recipes/src/cached_fs_rom/hash +++ b/repos/os/recipes/src/cached_fs_rom/hash @@ -1 +1 @@ -2024-08-28 1cdd09c43aeb4b1314397324d1a05596d17d21f6 +2024-12-10 4ff5c94c19cb938b2a820fdfc1a440b00e173e51 diff --git a/repos/os/recipes/src/chroot/hash b/repos/os/recipes/src/chroot/hash index b663da4b05..f327510e40 100644 --- a/repos/os/recipes/src/chroot/hash +++ b/repos/os/recipes/src/chroot/hash @@ -1 +1 @@ -2024-08-28 1f0221b00fbc210596d482975eca07648a682f55 +2024-12-10 0c372f2ea15195a756b6070709ef5ce27bc18b07 diff --git a/repos/os/recipes/src/clipboard/hash b/repos/os/recipes/src/clipboard/hash index f480235606..cdab4b59b5 100644 --- a/repos/os/recipes/src/clipboard/hash +++ b/repos/os/recipes/src/clipboard/hash @@ -1 +1 @@ -2024-08-28 46762b9a50d16c87cdbef248f863a9dbd9ae9a11 +2024-12-10 904c0ca529c7b5e079df1970c28b092d8a8bc1c5 diff --git a/repos/os/recipes/src/cpu_balancer/hash b/repos/os/recipes/src/cpu_balancer/hash index 7b656ff72d..23573c8fd9 100644 --- a/repos/os/recipes/src/cpu_balancer/hash +++ b/repos/os/recipes/src/cpu_balancer/hash @@ -1 +1 @@ -2024-08-28 48eb3f206877333f8e323af20cb9ec10ae614636 +2024-12-10 1fc6dec421671c4ece73fe34c62aa05bc6077e9d diff --git a/repos/os/recipes/src/cpu_burner/hash b/repos/os/recipes/src/cpu_burner/hash index e5d09ed594..326cf57a68 100644 --- a/repos/os/recipes/src/cpu_burner/hash +++ b/repos/os/recipes/src/cpu_burner/hash @@ -1 +1 @@ -2024-08-28 ffe690a0456c4ed6258cb0f64399496aca8e433b +2024-12-10 7f889005afeb75ede2ee5fd299f175efcecdce2d diff --git a/repos/os/recipes/src/dummy/hash b/repos/os/recipes/src/dummy/hash index cfdca09606..0ba0d58e23 100644 --- a/repos/os/recipes/src/dummy/hash +++ b/repos/os/recipes/src/dummy/hash @@ -1 +1 @@ -2024-08-28 6c4f877755d6be6b1b2e89ffb1de03e7adfc0a48 +2024-12-10 834f7ac29ab523125e69b5aba8b4ad93c62087df diff --git a/repos/os/recipes/src/dummy_rtc/hash b/repos/os/recipes/src/dummy_rtc/hash index ca9a144c49..84e6adad20 100644 --- a/repos/os/recipes/src/dummy_rtc/hash +++ b/repos/os/recipes/src/dummy_rtc/hash @@ -1 +1 @@ -2024-08-28 dc2367f7e79053fb331b452f047518722cfac65b +2024-12-10 44b6c927d46a6fbec22dcdd66edd70d6e6135c10 diff --git a/repos/os/recipes/src/dynamic_rom/hash b/repos/os/recipes/src/dynamic_rom/hash index f07f6465bc..c09cff81e5 100644 --- a/repos/os/recipes/src/dynamic_rom/hash +++ b/repos/os/recipes/src/dynamic_rom/hash @@ -1 +1 @@ -2024-08-28 37105dc54508d46fcdb1f9bb9aedddbb1cca9a6a +2024-12-10 c91d1398c69ad6600c0b35e15e88a772c02dc75e diff --git a/repos/os/recipes/src/event_filter/hash b/repos/os/recipes/src/event_filter/hash index 60df876575..0727beabee 100644 --- a/repos/os/recipes/src/event_filter/hash +++ b/repos/os/recipes/src/event_filter/hash @@ -1 +1 @@ -2024-08-28 1e212e5ab3a5255c5d9c40922cde8098fe1bebc3 +2024-12-10 d2b1397c1e14e02b31544f6931e0efaae7039004 diff --git a/repos/os/recipes/src/fb_sdl/hash b/repos/os/recipes/src/fb_sdl/hash index 68fd025ba5..16a3cec914 100644 --- a/repos/os/recipes/src/fb_sdl/hash +++ b/repos/os/recipes/src/fb_sdl/hash @@ -1 +1 @@ -2024-08-28 13a9c65bdc0ded9f6bd656d96027d0656bf60730 +2024-12-10 9dc136e357953eba2ddab11f0b5da0b4d31bedf9 diff --git a/repos/os/recipes/src/fs_report/hash b/repos/os/recipes/src/fs_report/hash index ce0ba4dd4a..31f07aad5b 100644 --- a/repos/os/recipes/src/fs_report/hash +++ b/repos/os/recipes/src/fs_report/hash @@ -1 +1 @@ -2024-08-28 6b332d9e4052ddd45bf7bd17a447965dccf35974 +2024-12-10 7f96fc5e5f061e8587c1702a6e611a88480b59f0 diff --git a/repos/os/recipes/src/fs_rom/hash b/repos/os/recipes/src/fs_rom/hash index 681c8e3509..2cc8a5e376 100644 --- a/repos/os/recipes/src/fs_rom/hash +++ b/repos/os/recipes/src/fs_rom/hash @@ -1 +1 @@ -2024-08-28 3133d7ce70162177b43d5408f9afc68e934f7c94 +2024-12-10 b9940e311a6dc0c05ae4544d50e913ea8b9f008e diff --git a/repos/os/recipes/src/global_keys_handler/hash b/repos/os/recipes/src/global_keys_handler/hash index a3c2277183..c657264c23 100644 --- a/repos/os/recipes/src/global_keys_handler/hash +++ b/repos/os/recipes/src/global_keys_handler/hash @@ -1 +1 @@ -2024-08-28 c6d9cbd45c65c29605185a1f440245d8c2881a69 +2024-12-10 07cd9ef3f22ea00b32850c327850771b20049073 diff --git a/repos/os/recipes/src/gui_fb/hash b/repos/os/recipes/src/gui_fb/hash index 005212b958..b5f4b56817 100644 --- a/repos/os/recipes/src/gui_fb/hash +++ b/repos/os/recipes/src/gui_fb/hash @@ -1 +1 @@ -2024-08-28 39675bf74414d875db6e7e08178efad70a173754 +2024-12-10 8d50a86ce244b92246aba5ae52060e97dbb05810 diff --git a/repos/os/recipes/src/init/hash b/repos/os/recipes/src/init/hash index f9f4dfe48c..1d4a263080 100644 --- a/repos/os/recipes/src/init/hash +++ b/repos/os/recipes/src/init/hash @@ -1 +1 @@ -2024-08-28 dc258dc1b9b73a8bffa368c433c37978953b40e9 +2024-12-10 72f9e41fb6bbfd5bfa0872dfb99c1e5ad753e192 diff --git a/repos/os/recipes/src/intel_gpu/hash b/repos/os/recipes/src/intel_gpu/hash index 930fed0362..d1b2ab6c5d 100644 --- a/repos/os/recipes/src/intel_gpu/hash +++ b/repos/os/recipes/src/intel_gpu/hash @@ -1 +1 @@ -2024-08-28 8d5d8b317b79ca58cd59eb1c5500d20d697042f0 +2024-12-10 22276df12ec4da59812a000d7d4900ea1a20a5d6 diff --git a/repos/os/recipes/src/lan9118_nic/hash b/repos/os/recipes/src/lan9118_nic/hash index 21fc683bed..4d80fc19ce 100644 --- a/repos/os/recipes/src/lan9118_nic/hash +++ b/repos/os/recipes/src/lan9118_nic/hash @@ -1 +1 @@ -2024-08-28 b2861fa78e8e8a48b0e1410d8dc276f4135a5dbb +2024-12-10 49d31219c002852f388fb69206e69049b4ef25db diff --git a/repos/os/recipes/src/linux_nic/hash b/repos/os/recipes/src/linux_nic/hash index de97546c78..f95f7e711c 100644 --- a/repos/os/recipes/src/linux_nic/hash +++ b/repos/os/recipes/src/linux_nic/hash @@ -1 +1 @@ -2024-08-28 9bf66a7a85d42c764ad4f106825b80653949dbe8 +2024-12-10 ab777237430869e92255695855b5ba68cfef9bf7 diff --git a/repos/os/recipes/src/linux_rtc/hash b/repos/os/recipes/src/linux_rtc/hash index cb7147d447..07b79ebca8 100644 --- a/repos/os/recipes/src/linux_rtc/hash +++ b/repos/os/recipes/src/linux_rtc/hash @@ -1 +1 @@ -2024-08-28 b6644cc91883c0fe48673b740e72545c3d5c4062 +2024-12-10 c3bdf284904bda04df5ba638b68d8b7d7e2ec6bf diff --git a/repos/os/recipes/src/log_core/hash b/repos/os/recipes/src/log_core/hash index 3b2fb0ec42..ff3c36c516 100644 --- a/repos/os/recipes/src/log_core/hash +++ b/repos/os/recipes/src/log_core/hash @@ -1 +1 @@ -2024-08-28 cf0c839a7f1896eb6155bcf86ab162edaeab9e2e +2024-12-10 0fa3811be356607f69a9c34e1a39c53364519c3e diff --git a/repos/os/recipes/src/log_terminal/hash b/repos/os/recipes/src/log_terminal/hash index 7cbdd16355..b4d7913286 100644 --- a/repos/os/recipes/src/log_terminal/hash +++ b/repos/os/recipes/src/log_terminal/hash @@ -1 +1 @@ -2024-08-28 615aefc66ab251f9eb45d076aad7ac2167491694 +2024-12-10 f775033533d042df9b0e102c73daf94376148a3e diff --git a/repos/os/recipes/src/lx_block/hash b/repos/os/recipes/src/lx_block/hash index dc1515576c..dd11c15c9e 100644 --- a/repos/os/recipes/src/lx_block/hash +++ b/repos/os/recipes/src/lx_block/hash @@ -1 +1 @@ -2024-08-28 cf3cc85143826a2efeec9cff29797adc66405954 +2024-12-10 aa31a53451b3f8624dcc26a122d87c126bd946d7 diff --git a/repos/os/recipes/src/lx_fs/hash b/repos/os/recipes/src/lx_fs/hash index 3ddd75e0cd..3308f75958 100644 --- a/repos/os/recipes/src/lx_fs/hash +++ b/repos/os/recipes/src/lx_fs/hash @@ -1 +1 @@ -2024-08-28 c4f4e9afe514699d9eb0575580909f9a00634a8f +2024-12-10 4e54ea3679cf0be030921690d578e6019141c2f8 diff --git a/repos/os/recipes/src/mixer/hash b/repos/os/recipes/src/mixer/hash index 4af2158c6e..dd8a2aa1ba 100644 --- a/repos/os/recipes/src/mixer/hash +++ b/repos/os/recipes/src/mixer/hash @@ -1 +1 @@ -2024-08-28 f69f49e772c17708b9a2e19b141ee6ab04212296 +2024-12-10 1afef68eddc9c0001bf2d86c2830d32d2512fbaf diff --git a/repos/os/recipes/src/monitor/hash b/repos/os/recipes/src/monitor/hash index 2930e7cc29..8ca69f653c 100644 --- a/repos/os/recipes/src/monitor/hash +++ b/repos/os/recipes/src/monitor/hash @@ -1 +1 @@ -2024-08-28 86ce5436f6c276ad11ea55528029b2a1459c0357 +2024-12-10 e74969fbf7c7fe519c560d2f0a13bed492682151 diff --git a/repos/os/recipes/src/nic_bridge/hash b/repos/os/recipes/src/nic_bridge/hash index 6ef529cd31..45908f672d 100644 --- a/repos/os/recipes/src/nic_bridge/hash +++ b/repos/os/recipes/src/nic_bridge/hash @@ -1 +1 @@ -2024-08-28 c1743ba6b12dfb64cba5e87b22a9bf1ab4dfbbaa +2024-12-10 c5564e51bd9a038a86b55fa19379bee5325aa0c8 diff --git a/repos/os/recipes/src/nic_loopback/hash b/repos/os/recipes/src/nic_loopback/hash index ad2efeee92..afaa85af13 100644 --- a/repos/os/recipes/src/nic_loopback/hash +++ b/repos/os/recipes/src/nic_loopback/hash @@ -1 +1 @@ -2024-08-28 154ce058d9f762645af1e1b5a263210f04710897 +2024-12-10 7ffdfae6eff697763b0f9fb8139d62a644c8f5cd diff --git a/repos/os/recipes/src/nic_perf/hash b/repos/os/recipes/src/nic_perf/hash index 74b62c0e40..161039250d 100644 --- a/repos/os/recipes/src/nic_perf/hash +++ b/repos/os/recipes/src/nic_perf/hash @@ -1 +1 @@ -2024-08-28 286b90d18f311c8fd7e0a391d21b29519e72a2a9 +2024-12-10 42c32bde67db9ae6174b0ef5f0e7b523503e406c diff --git a/repos/os/recipes/src/nic_router/hash b/repos/os/recipes/src/nic_router/hash index 2de584c011..fe020238b1 100644 --- a/repos/os/recipes/src/nic_router/hash +++ b/repos/os/recipes/src/nic_router/hash @@ -1 +1 @@ -2024-08-28 70281fbc5484ea75e8c94bbaac99b6c8b775648e +2024-12-10 16170a13d62ecdeef52a8fabc4c514b1ec296844 diff --git a/repos/os/recipes/src/nic_uplink/hash b/repos/os/recipes/src/nic_uplink/hash index be0809ac2b..5caf84e8b5 100644 --- a/repos/os/recipes/src/nic_uplink/hash +++ b/repos/os/recipes/src/nic_uplink/hash @@ -1 +1 @@ -2024-08-28 65b0200a2de1cff1cd9fb8ceb31e43b8f5e18570 +2024-12-10 acd9b50f2f02aae72dfbcc1e577aa241138079e0 diff --git a/repos/os/recipes/src/nit_focus/hash b/repos/os/recipes/src/nit_focus/hash index b4d5137aa4..7ba2bbbfa7 100644 --- a/repos/os/recipes/src/nit_focus/hash +++ b/repos/os/recipes/src/nit_focus/hash @@ -1 +1 @@ -2024-08-28 8219e10ae0930bb718a096cab0ec9496ed253c79 +2024-12-10 bac87d7749efca1f9230d79c5c900557a1b5d068 diff --git a/repos/os/recipes/src/nitpicker/hash b/repos/os/recipes/src/nitpicker/hash index 552e6a1bcb..798f501051 100644 --- a/repos/os/recipes/src/nitpicker/hash +++ b/repos/os/recipes/src/nitpicker/hash @@ -1 +1 @@ -2024-08-28 dadc09daf55a9f1e4fb15ef79ddd995d30428a06 +2024-12-10 8be12d1011cf342aafa6b6d454aa98c5cd75ab31 diff --git a/repos/os/recipes/src/nvme/hash b/repos/os/recipes/src/nvme/hash index 0db41540d1..7068b7dce7 100644 --- a/repos/os/recipes/src/nvme/hash +++ b/repos/os/recipes/src/nvme/hash @@ -1 +1 @@ -2024-08-28 5e63e438d4f7dcc5174f5c344f865fc82a0c317f +2024-12-10 bf8ea49d32e8b2ae50c1fcd115a910f90c1ebd21 diff --git a/repos/os/recipes/src/part_block/hash b/repos/os/recipes/src/part_block/hash index bc94f4a7e8..1ba1922f9f 100644 --- a/repos/os/recipes/src/part_block/hash +++ b/repos/os/recipes/src/part_block/hash @@ -1 +1 @@ -2024-08-28 37c8ede3c26d8ad0e5ac590126b26feb0816a8a7 +2024-12-10 87e0d8059f550f26c87ddcf959b93b012cc279f5 diff --git a/repos/os/recipes/src/pbxa9_drivers/hash b/repos/os/recipes/src/pbxa9_drivers/hash index 215da7f3af..61f2c3776c 100644 --- a/repos/os/recipes/src/pbxa9_drivers/hash +++ b/repos/os/recipes/src/pbxa9_drivers/hash @@ -1 +1 @@ -2024-08-28 b3511b56dcd1134f748024a9106318b479b579fd +2024-12-10 e6a76b8eec3dac34915a26befadfc2718fb137f8 diff --git a/repos/os/recipes/src/pc_rtc/hash b/repos/os/recipes/src/pc_rtc/hash index 9e446e81e2..3819fff9bb 100644 --- a/repos/os/recipes/src/pc_rtc/hash +++ b/repos/os/recipes/src/pc_rtc/hash @@ -1 +1 @@ -2024-08-28 d0330367f25dd201e6e06aa83d273f0881321502 +2024-12-10 0799f5d0e962855e5ca091f31d6808ed62e9be96 diff --git a/repos/os/recipes/src/pci_decode/hash b/repos/os/recipes/src/pci_decode/hash index 12362d32d8..11e001d3ff 100644 --- a/repos/os/recipes/src/pci_decode/hash +++ b/repos/os/recipes/src/pci_decode/hash @@ -1 +1 @@ -2024-10-10 cbcb285fdcf46050b5757714e238bb9450869bf0 +2024-12-10 2f925bffecde0d9685940b26aba5b63f08d43f53 diff --git a/repos/os/recipes/src/ping/hash b/repos/os/recipes/src/ping/hash index 761da312e4..43075ff22d 100644 --- a/repos/os/recipes/src/ping/hash +++ b/repos/os/recipes/src/ping/hash @@ -1 +1 @@ -2024-08-28 16b5573c7eea8dd9172ece805b44ef18d7505e26 +2024-12-10 62e289ad0a8e948ce2dd8f27ff0812bf74bf720e diff --git a/repos/os/recipes/src/platform/hash b/repos/os/recipes/src/platform/hash index fb87e05367..313e3697ed 100644 --- a/repos/os/recipes/src/platform/hash +++ b/repos/os/recipes/src/platform/hash @@ -1 +1 @@ -2024-08-28 67cf804d752327c4e4a097757b2ebf2e5b75f89f +2024-12-10 81f530290840850d6a24d23efad9d98d32674707 diff --git a/repos/os/recipes/src/ps2/hash b/repos/os/recipes/src/ps2/hash index 80c1bc2bda..1a2a5ec49f 100644 --- a/repos/os/recipes/src/ps2/hash +++ b/repos/os/recipes/src/ps2/hash @@ -1 +1 @@ -2024-08-28 dfe678caeba22efb241f2af2a1d961848651aa76 +2024-12-10 557ee35ec7f013935b909de6e3e9239bdcc5e25d diff --git a/repos/os/recipes/src/record_play_mixer/hash b/repos/os/recipes/src/record_play_mixer/hash index bec675f356..93367c0805 100644 --- a/repos/os/recipes/src/record_play_mixer/hash +++ b/repos/os/recipes/src/record_play_mixer/hash @@ -1 +1 @@ -2024-08-28 eb2513f7433a89f334b054e0398f09ab6a8f507d +2024-12-10 f87120b971a2fe5732884f78ecd127c86eb6ce28 diff --git a/repos/os/recipes/src/record_rom/hash b/repos/os/recipes/src/record_rom/hash index d2982130f1..a13c6cd110 100644 --- a/repos/os/recipes/src/record_rom/hash +++ b/repos/os/recipes/src/record_rom/hash @@ -1 +1 @@ -2024-08-28 90dcb7d4b3d74cd5fdbfd9476be9721eac6c5911 +2024-12-10 03a7445f301bde7571821df2621553f01fac3066 diff --git a/repos/os/recipes/src/report_rom/hash b/repos/os/recipes/src/report_rom/hash index d56753b891..8c06b6aaf8 100644 --- a/repos/os/recipes/src/report_rom/hash +++ b/repos/os/recipes/src/report_rom/hash @@ -1 +1 @@ -2024-08-28 0984d7cd3d0f1a00aa5d544fbb822e11cc77b1f6 +2024-12-10 a467e32a23f0dddd908e3e4f0d02f2ec5da0667e diff --git a/repos/os/recipes/src/rom_filter/hash b/repos/os/recipes/src/rom_filter/hash index 035b4d0f17..c02785c261 100644 --- a/repos/os/recipes/src/rom_filter/hash +++ b/repos/os/recipes/src/rom_filter/hash @@ -1 +1 @@ -2024-08-28 2fe10d71efd7382dfe1e7889723b95d99349884e +2024-12-10 45460d0e472086d52b0bbe4b0595597b095190b7 diff --git a/repos/os/recipes/src/rom_logger/hash b/repos/os/recipes/src/rom_logger/hash index 48c76e38b9..905a0c3936 100644 --- a/repos/os/recipes/src/rom_logger/hash +++ b/repos/os/recipes/src/rom_logger/hash @@ -1 +1 @@ -2024-08-28 5a6f6b3bafa20cd506eef7b4847414d1872e5bcf +2024-12-10 5072967f8816c410b06b587248bec7a1fac9f4ec diff --git a/repos/os/recipes/src/rom_reporter/hash b/repos/os/recipes/src/rom_reporter/hash index a6eb1136d1..45474d2143 100644 --- a/repos/os/recipes/src/rom_reporter/hash +++ b/repos/os/recipes/src/rom_reporter/hash @@ -1 +1 @@ -2024-08-28 feddcd36ae165e2c28e37722b3da61c1fba5658c +2024-12-10 c42be74728b96c5a040e60bcaabc402a102d43ba diff --git a/repos/os/recipes/src/rom_to_file/hash b/repos/os/recipes/src/rom_to_file/hash index e5f2c3371f..9f8ae941bc 100644 --- a/repos/os/recipes/src/rom_to_file/hash +++ b/repos/os/recipes/src/rom_to_file/hash @@ -1 +1 @@ -2024-08-28 a8f79b66f52389d62b83301c06ee8612d5d6d047 +2024-12-10 e902ab50d196a6099b173570078b734d87f11459 diff --git a/repos/os/recipes/src/sandbox/hash b/repos/os/recipes/src/sandbox/hash index 806149b576..7b0dd62a60 100644 --- a/repos/os/recipes/src/sandbox/hash +++ b/repos/os/recipes/src/sandbox/hash @@ -1 +1 @@ -2024-08-28 bc4953db26ba1dd6c69e7554e1df5f5127464c59 +2024-12-10 0360bbd4009c6c0d6580253c6c692bdc0a741846 diff --git a/repos/os/recipes/src/sequence/hash b/repos/os/recipes/src/sequence/hash index 2e0c6ad0c9..e1e7705555 100644 --- a/repos/os/recipes/src/sequence/hash +++ b/repos/os/recipes/src/sequence/hash @@ -1 +1 @@ -2024-08-28 2e988c647845e8b695147f1993c410b94e0d65ee +2024-12-10 52406777fadfcafc060623b0cfdfb8ef5f866b4f diff --git a/repos/os/recipes/src/shim/hash b/repos/os/recipes/src/shim/hash index 9112c41ef3..56e4100137 100644 --- a/repos/os/recipes/src/shim/hash +++ b/repos/os/recipes/src/shim/hash @@ -1 +1 @@ -2024-08-28 e13c8a42dabbb213bb08098aa854cc375f994103 +2024-12-10 b0457a09ddb747ee1d1786ad680b86a94b932246 diff --git a/repos/os/recipes/src/terminal_crosslink/hash b/repos/os/recipes/src/terminal_crosslink/hash index 4afa31ae20..4c983ebc7e 100644 --- a/repos/os/recipes/src/terminal_crosslink/hash +++ b/repos/os/recipes/src/terminal_crosslink/hash @@ -1 +1 @@ -2024-08-28 d70713dcfe6d291cc3a63656e2dbdd4741e52f35 +2024-12-10 ebbe8d67def50c5ecee46eb139df0dc918011cc9 diff --git a/repos/os/recipes/src/terminal_log/hash b/repos/os/recipes/src/terminal_log/hash index e9fb7f29a8..3b0175c32c 100644 --- a/repos/os/recipes/src/terminal_log/hash +++ b/repos/os/recipes/src/terminal_log/hash @@ -1 +1 @@ -2024-08-28 f7f1b169fa7a4753ac3ec971ad3a2e467fd3762e +2024-12-10 32f8e5105daeb3ad311cf02e6009990552dd4d82 diff --git a/repos/os/recipes/src/test-audio_out/hash b/repos/os/recipes/src/test-audio_out/hash index 53d6b35319..36837b6ae0 100644 --- a/repos/os/recipes/src/test-audio_out/hash +++ b/repos/os/recipes/src/test-audio_out/hash @@ -1 +1 @@ -2024-08-28 dcfc4cb84249b4226e3cffdb07fd9808a717c0db +2024-12-10 3f5936595bcdefb3e2867f6cd494db49f75a2526 diff --git a/repos/os/recipes/src/test-black_hole/hash b/repos/os/recipes/src/test-black_hole/hash index d425b12ed9..42a582e2ac 100644 --- a/repos/os/recipes/src/test-black_hole/hash +++ b/repos/os/recipes/src/test-black_hole/hash @@ -1 +1 @@ -2024-08-28 d88a13621cdf0dba9fc7f1ce4c54f9cdfcad216b +2024-12-10 15555fa3fd9f65873f08f580f33c697a2c0bf0aa diff --git a/repos/os/recipes/src/test-bomb/hash b/repos/os/recipes/src/test-bomb/hash index 6170b0d095..57c670ecf6 100644 --- a/repos/os/recipes/src/test-bomb/hash +++ b/repos/os/recipes/src/test-bomb/hash @@ -1 +1 @@ -2024-08-28 dbf9173b1648ce7d617d7cf6c7318715fd0bcc78 +2024-12-10 ee5a1cab8ba075e993541d0aa4c3fd080e617b5d diff --git a/repos/os/recipes/src/test-capture/hash b/repos/os/recipes/src/test-capture/hash index 8bbfabbe86..2a0d4246fd 100644 --- a/repos/os/recipes/src/test-capture/hash +++ b/repos/os/recipes/src/test-capture/hash @@ -1 +1 @@ -2024-08-28 e7a0de28a2648266ae28af34ef5a6f53665b6c2e +2024-12-10 8af243f5b990e3eb7d97fe700feefcea21efa9e1 diff --git a/repos/os/recipes/src/test-clipboard/hash b/repos/os/recipes/src/test-clipboard/hash index f75de7ea33..fa3dbf60cc 100644 --- a/repos/os/recipes/src/test-clipboard/hash +++ b/repos/os/recipes/src/test-clipboard/hash @@ -1 +1 @@ -2024-08-28 a2d112feeabd4de21f1b8a7200401218f3424bd8 +2024-12-10 04c753f946f63cfa96550d39993aa6645cf3c44b diff --git a/repos/os/recipes/src/test-dynamic_config/hash b/repos/os/recipes/src/test-dynamic_config/hash index 69182bd92d..4a2fb2e72e 100644 --- a/repos/os/recipes/src/test-dynamic_config/hash +++ b/repos/os/recipes/src/test-dynamic_config/hash @@ -1 +1 @@ -2024-08-28 db654c9253ff8ad21fa7df99b7288ac00a786777 +2024-12-10 2a53631de0cc443194a491ecde801a4af3e1db4e diff --git a/repos/os/recipes/src/test-fault_detection/hash b/repos/os/recipes/src/test-fault_detection/hash index 5289218346..e2b9c2539d 100644 --- a/repos/os/recipes/src/test-fault_detection/hash +++ b/repos/os/recipes/src/test-fault_detection/hash @@ -1 +1 @@ -2024-08-28 cfbd4a26d49960ea7e524b717d730b4ee50e98a5 +2024-12-10 74e5553293febfc0359394b17c4524641e6a6492 diff --git a/repos/os/recipes/src/test-fs_packet/hash b/repos/os/recipes/src/test-fs_packet/hash index 225bc17936..ee5769d941 100644 --- a/repos/os/recipes/src/test-fs_packet/hash +++ b/repos/os/recipes/src/test-fs_packet/hash @@ -1 +1 @@ -2024-08-28 f9646b60feda933e42c81b68f53f5447eddb164f +2024-12-10 a2403b99fd8b634933a5a215d3d7db84125f5b92 diff --git a/repos/os/recipes/src/test-fs_report/hash b/repos/os/recipes/src/test-fs_report/hash index 59e0d07690..c1de30fd2f 100644 --- a/repos/os/recipes/src/test-fs_report/hash +++ b/repos/os/recipes/src/test-fs_report/hash @@ -1 +1 @@ -2024-08-28 708df57adbc949e24ff02c724959eb6646d44f11 +2024-12-10 82e408448ce74780f2a0617f4ae60319e0142bb8 diff --git a/repos/os/recipes/src/test-immutable_rom/hash b/repos/os/recipes/src/test-immutable_rom/hash index 1cb2e946c1..9f1c17d8df 100644 --- a/repos/os/recipes/src/test-immutable_rom/hash +++ b/repos/os/recipes/src/test-immutable_rom/hash @@ -1 +1 @@ -2024-08-28 7780569ec1dd23d51e1a2038b9a31d13b61d8573 +2024-12-10 8818e702bdaf391188717b33f69491b647fc1ac9 diff --git a/repos/os/recipes/src/test-init/hash b/repos/os/recipes/src/test-init/hash index 4efdc065b5..54b9c23787 100644 --- a/repos/os/recipes/src/test-init/hash +++ b/repos/os/recipes/src/test-init/hash @@ -1 +1 @@ -2024-08-28 365a2cc80ad946930dd0db03bb3129d0d9d2ef6d +2024-12-10 c960da84de4ab52c820a29677f2d3aa01e169cf3 diff --git a/repos/os/recipes/src/test-init_loop/hash b/repos/os/recipes/src/test-init_loop/hash index 32f7b85e11..ffcb1b151e 100644 --- a/repos/os/recipes/src/test-init_loop/hash +++ b/repos/os/recipes/src/test-init_loop/hash @@ -1 +1 @@ -2024-08-28 0478334a0cc818ebb7cb723329b45195e60d73fb +2024-12-10 d68cc0641cc756ce557f4f4f122914799e36a635 diff --git a/repos/os/recipes/src/test-nic_loopback/hash b/repos/os/recipes/src/test-nic_loopback/hash index d374cbb3c3..0360dc803b 100644 --- a/repos/os/recipes/src/test-nic_loopback/hash +++ b/repos/os/recipes/src/test-nic_loopback/hash @@ -1 +1 @@ -2024-08-28 41f73f810cf5e5bd497c3bf90fce62be3e17842d +2024-12-10 d0580484d7a23b4e7629e0fe5c30f3637a4b25a4 diff --git a/repos/os/recipes/src/test-path/hash b/repos/os/recipes/src/test-path/hash index 30f865dbba..b67c096974 100644 --- a/repos/os/recipes/src/test-path/hash +++ b/repos/os/recipes/src/test-path/hash @@ -1 +1 @@ -2024-08-28 33f071198958e69f82f7d2c589d7a95a41dcf052 +2024-12-10 4712a0b2bb26e010847123d81e23d03f824fcd5e diff --git a/repos/os/recipes/src/test-ram_fs_chunk/hash b/repos/os/recipes/src/test-ram_fs_chunk/hash index 890ef57e19..b93a31435e 100644 --- a/repos/os/recipes/src/test-ram_fs_chunk/hash +++ b/repos/os/recipes/src/test-ram_fs_chunk/hash @@ -1 +1 @@ -2024-08-28 8950e35c0ab4fa91170cc7206f2205d76bf44328 +2024-12-10 319b46cecd32f4c07f80d08b963adbe3c1323d10 diff --git a/repos/os/recipes/src/test-report_rom/hash b/repos/os/recipes/src/test-report_rom/hash index fdbaaee51c..2918fec7fb 100644 --- a/repos/os/recipes/src/test-report_rom/hash +++ b/repos/os/recipes/src/test-report_rom/hash @@ -1 +1 @@ -2024-08-28 105a58b2b55607cb930f589a90ec40ffb837ff02 +2024-12-10 a5e09e10fb5efec705a5736e583e61ed5483f75c diff --git a/repos/os/recipes/src/test-resource_request/hash b/repos/os/recipes/src/test-resource_request/hash index 8a5812d6b5..527c129017 100644 --- a/repos/os/recipes/src/test-resource_request/hash +++ b/repos/os/recipes/src/test-resource_request/hash @@ -1 +1 @@ -2024-08-28 7e4ae3f7c782ede9a0f9642f4968500f8f21adad +2024-12-10 75de3a73bf9557cc04ad3ac58efa80079b9b6590 diff --git a/repos/os/recipes/src/test-resource_yield/hash b/repos/os/recipes/src/test-resource_yield/hash index 1e4e71e286..62cd370216 100644 --- a/repos/os/recipes/src/test-resource_yield/hash +++ b/repos/os/recipes/src/test-resource_yield/hash @@ -1 +1 @@ -2024-08-28 3f89fcc630fff1ab87357a582f2d62f3a9cbb3d9 +2024-12-10 6c0224c13085c3ee383fe2dc490bda41fd0d037c diff --git a/repos/os/recipes/src/test-rtc/hash b/repos/os/recipes/src/test-rtc/hash index b6160c4f39..7e5a61bb9b 100644 --- a/repos/os/recipes/src/test-rtc/hash +++ b/repos/os/recipes/src/test-rtc/hash @@ -1 +1 @@ -2024-08-28 ea02423124ff7f6489147864f0b8886216d32c18 +2024-12-10 faaf348a1d79cd45cb4a570666f8faf0803161a6 diff --git a/repos/os/recipes/src/test-sandbox/hash b/repos/os/recipes/src/test-sandbox/hash index ee25a54c4d..c67f71347b 100644 --- a/repos/os/recipes/src/test-sandbox/hash +++ b/repos/os/recipes/src/test-sandbox/hash @@ -1 +1 @@ -2024-08-28 5378c82f5d3026e66ab1d19d6941342066fcb6db +2024-12-10 5e50b16ec36b0f7f430d08662f3114cb516d68e7 diff --git a/repos/os/recipes/src/test-signal/hash b/repos/os/recipes/src/test-signal/hash index 05311482ad..84282782d3 100644 --- a/repos/os/recipes/src/test-signal/hash +++ b/repos/os/recipes/src/test-signal/hash @@ -1 +1 @@ -2024-08-28 7dcc54ae03b0782cb52a8c02e4543933bbfe9184 +2024-12-10 5a998298c13ed3f966884d603361cadb349781ff diff --git a/repos/os/recipes/src/test-slab/hash b/repos/os/recipes/src/test-slab/hash index 9da408eee7..67b601aaa5 100644 --- a/repos/os/recipes/src/test-slab/hash +++ b/repos/os/recipes/src/test-slab/hash @@ -1 +1 @@ -2024-08-28 5510fc2de1ba54933b8a51a5a9b58ba06cd536e2 +2024-12-10 f5c7f96a603d97b567dbeb08b1cf49faf097d1bd diff --git a/repos/os/recipes/src/test-terminal_crosslink/hash b/repos/os/recipes/src/test-terminal_crosslink/hash index a2070eba9c..d7f9b5c31b 100644 --- a/repos/os/recipes/src/test-terminal_crosslink/hash +++ b/repos/os/recipes/src/test-terminal_crosslink/hash @@ -1 +1 @@ -2024-08-28 9a8b89742dc6b7bef331438dd6ddfdabc9dc584d +2024-12-10 875c8da8b34dc57b510dc7cda0ef548836031155 diff --git a/repos/os/recipes/src/test-terminal_echo/hash b/repos/os/recipes/src/test-terminal_echo/hash index f8215c8410..5212e1c5d2 100644 --- a/repos/os/recipes/src/test-terminal_echo/hash +++ b/repos/os/recipes/src/test-terminal_echo/hash @@ -1 +1 @@ -2024-08-28 c4727d97f7e1950c28486f301c5bdaaf9fd00b49 +2024-12-10 75320e38524ceba2e4cfd447ae1bf1599ec92b9a diff --git a/repos/os/recipes/src/test-trace/hash b/repos/os/recipes/src/test-trace/hash index 19968b53c5..f30dab442d 100644 --- a/repos/os/recipes/src/test-trace/hash +++ b/repos/os/recipes/src/test-trace/hash @@ -1 +1 @@ -2024-08-28 205189edc1d835aea19dc18396278ee8c4b189f1 +2024-12-10 c0eb5f42b9e8a82de2d4d6f6533c105744b86639 diff --git a/repos/os/recipes/src/test-trace_buffer/hash b/repos/os/recipes/src/test-trace_buffer/hash index de3ebb17d3..98561eeb98 100644 --- a/repos/os/recipes/src/test-trace_buffer/hash +++ b/repos/os/recipes/src/test-trace_buffer/hash @@ -1 +1 @@ -2024-08-28 138b99e002cd9d96f6591666055254f6de2b4aa8 +2024-12-10 ebe51ebbc21a122e74488300e10556e781e3ceae diff --git a/repos/os/recipes/src/test-trace_logger/hash b/repos/os/recipes/src/test-trace_logger/hash index 6c09005d1b..992e74e786 100644 --- a/repos/os/recipes/src/test-trace_logger/hash +++ b/repos/os/recipes/src/test-trace_logger/hash @@ -1 +1 @@ -2024-08-28 611d656a5af50e8c075caee877ee23b3cc1eb075 +2024-12-10 594e66cae6c80c2f78a3c0c34c63cafa681c3016 diff --git a/repos/os/recipes/src/test-utf8/hash b/repos/os/recipes/src/test-utf8/hash index 693afa466b..69a82a36d4 100644 --- a/repos/os/recipes/src/test-utf8/hash +++ b/repos/os/recipes/src/test-utf8/hash @@ -1 +1 @@ -2024-08-28 5ceb66868a75cd9afe2d8084bcb15294483eada8 +2024-12-10 67b1a1ad0dddcdc22dd6e266309f8221ff30173f diff --git a/repos/os/recipes/src/test-vfs_capture/hash b/repos/os/recipes/src/test-vfs_capture/hash index 1b9426c7bc..f260073413 100644 --- a/repos/os/recipes/src/test-vfs_capture/hash +++ b/repos/os/recipes/src/test-vfs_capture/hash @@ -1 +1 @@ -2024-08-28 5b7b47efe4e44d264f0a1d641654857682c9f77b +2024-12-10 2507933a77757949ac10c85ff90454d9f6ba0be3 diff --git a/repos/os/recipes/src/test-vfs_stress/hash b/repos/os/recipes/src/test-vfs_stress/hash index 5f80f01b68..29e351ed7e 100644 --- a/repos/os/recipes/src/test-vfs_stress/hash +++ b/repos/os/recipes/src/test-vfs_stress/hash @@ -1 +1 @@ -2024-08-28 3084bca229034888a620b9332d4ceb95934fb024 +2024-12-10 c26f6d3071b186404355651fb1754b0bb3a83058 diff --git a/repos/os/recipes/src/test-weak_ptr/hash b/repos/os/recipes/src/test-weak_ptr/hash index ecdce83f81..1fb919a1fc 100644 --- a/repos/os/recipes/src/test-weak_ptr/hash +++ b/repos/os/recipes/src/test-weak_ptr/hash @@ -1 +1 @@ -2024-08-28 14a7ccaa7b1310bf05751862171ec66cf880e63e +2024-12-10 0d8b486da780dc4628726a95e85288db6b44c0c9 diff --git a/repos/os/recipes/src/top/hash b/repos/os/recipes/src/top/hash index 4cbec9a0f0..3a119c22c2 100644 --- a/repos/os/recipes/src/top/hash +++ b/repos/os/recipes/src/top/hash @@ -1 +1 @@ -2024-08-28 a8799e80657634344afe1f7e37ea6ae07ff8626c +2024-12-10 fb5cc2aca003707c643c48291aad89b3cf068a45 diff --git a/repos/os/recipes/src/trace_logger/hash b/repos/os/recipes/src/trace_logger/hash index bbeaea2321..164e8a85d4 100644 --- a/repos/os/recipes/src/trace_logger/hash +++ b/repos/os/recipes/src/trace_logger/hash @@ -1 +1 @@ -2024-08-28 af92c04a89ebf03c55961a3ffad40b7fcff173bd +2024-12-10 58108de21ea66a2c6a202afece58e841e7945b7b diff --git a/repos/os/recipes/src/trace_policy/hash b/repos/os/recipes/src/trace_policy/hash index 7cd9b0cbbf..b4b47c5461 100644 --- a/repos/os/recipes/src/trace_policy/hash +++ b/repos/os/recipes/src/trace_policy/hash @@ -1 +1 @@ -2024-08-28 446d90af0b814e1db57daaa742c81a31d3bcc52b +2024-12-10 0f119f60514d3d5e9ca183b1ca3a3793db5e42c3 diff --git a/repos/os/recipes/src/trace_subject_reporter/hash b/repos/os/recipes/src/trace_subject_reporter/hash index f45807c8fe..0011aabbc6 100644 --- a/repos/os/recipes/src/trace_subject_reporter/hash +++ b/repos/os/recipes/src/trace_subject_reporter/hash @@ -1 +1 @@ -2024-08-28 d2acad6f8bcabe66c4ff4dc2e4e3db060d266bfe +2024-12-10 b639feda628c3e0be1395a757ff2fc2dbd69d61f diff --git a/repos/os/recipes/src/usb_block/hash b/repos/os/recipes/src/usb_block/hash index d0bc0228d3..68f0827b80 100644 --- a/repos/os/recipes/src/usb_block/hash +++ b/repos/os/recipes/src/usb_block/hash @@ -1 +1 @@ -2024-08-28 05b74e055bbb240f2e4d1d774cdd9822f0e142ee +2024-12-10 4f2e138e4bb0b415513e8020df100c7f3afdff34 diff --git a/repos/os/recipes/src/vfs/hash b/repos/os/recipes/src/vfs/hash index c1abe71776..0a21b73a2b 100644 --- a/repos/os/recipes/src/vfs/hash +++ b/repos/os/recipes/src/vfs/hash @@ -1 +1 @@ -2024-08-28 883fdeb460736948ca7ecace7a87f12b256b2d2b +2024-12-10 ed7285b93b7c97cc1c4bc7232352df00c49163b2 diff --git a/repos/os/recipes/src/vfs_block/hash b/repos/os/recipes/src/vfs_block/hash index af778d3cad..386302e0bf 100644 --- a/repos/os/recipes/src/vfs_block/hash +++ b/repos/os/recipes/src/vfs_block/hash @@ -1 +1 @@ -2024-08-28 67575c5b8013628a808b10ec4eda364ec43bd63f +2024-12-10 6fe9dad44ab96be4d7961d3d988c5c1fb1fdf8d5 diff --git a/repos/os/recipes/src/vfs_capture/hash b/repos/os/recipes/src/vfs_capture/hash index 24b7ff7d23..3a7536de22 100644 --- a/repos/os/recipes/src/vfs_capture/hash +++ b/repos/os/recipes/src/vfs_capture/hash @@ -1 +1 @@ -2024-08-28 a47991d5b099ea566155be7715ccd584c2602134 +2024-12-10 7f415f1af883ac86392ee58046019cf5ece95044 diff --git a/repos/os/recipes/src/vfs_tap/hash b/repos/os/recipes/src/vfs_tap/hash index ee224e12ab..42721c96a6 100644 --- a/repos/os/recipes/src/vfs_tap/hash +++ b/repos/os/recipes/src/vfs_tap/hash @@ -1 +1 @@ -2024-08-28 efb069bc92e6345e06cdef2307796bea2de20e2d +2024-12-10 81dec905b7b2b85ae8d607f21a54cead0d7ddaaf diff --git a/repos/os/recipes/src/virt_qemu_drivers/hash b/repos/os/recipes/src/virt_qemu_drivers/hash index fe614c9ac1..448fd17a4a 100644 --- a/repos/os/recipes/src/virt_qemu_drivers/hash +++ b/repos/os/recipes/src/virt_qemu_drivers/hash @@ -1 +1 @@ -2024-08-28 1bd387ae01057f8a2e691ccdd093ebb2aa5fd1f4 +2024-12-10 64dd8599af610aaa64b6f0a90cbf5005012c5b1e diff --git a/repos/os/recipes/src/virtdev_rom/hash b/repos/os/recipes/src/virtdev_rom/hash index 25e8c00b3f..dc102cac81 100644 --- a/repos/os/recipes/src/virtdev_rom/hash +++ b/repos/os/recipes/src/virtdev_rom/hash @@ -1 +1 @@ -2024-08-28 e87b6a429afdd7a91fea7d6328772c68334addc8 +2024-12-10 f76e0e464d22514cf6692e7ffa2d73d4584beaf0 diff --git a/repos/os/recipes/src/virtio_fb/hash b/repos/os/recipes/src/virtio_fb/hash index 60d115645d..c2acd28f34 100644 --- a/repos/os/recipes/src/virtio_fb/hash +++ b/repos/os/recipes/src/virtio_fb/hash @@ -1 +1 @@ -2024-08-28 ff1f478d3ec28456acb9cb7d24b8fef959971049 +2024-12-10 3d9ff76635ecc31153232aca767010f4b2bcaac7 diff --git a/repos/os/recipes/src/virtio_input/hash b/repos/os/recipes/src/virtio_input/hash index 8a62380bed..c1e120d6e5 100644 --- a/repos/os/recipes/src/virtio_input/hash +++ b/repos/os/recipes/src/virtio_input/hash @@ -1 +1 @@ -2024-08-28 520998c1c17bce5fc956f25bb177b4fb15bad307 +2024-12-10 fa470f0bcb4ed25c14e6c8bb8538ff7637ee7d59 diff --git a/repos/os/recipes/src/virtio_nic/hash b/repos/os/recipes/src/virtio_nic/hash index a89a534f39..d06dbed6bb 100644 --- a/repos/os/recipes/src/virtio_nic/hash +++ b/repos/os/recipes/src/virtio_nic/hash @@ -1 +1 @@ -2024-08-28 6d1065aedf9477b2058d77e7b65ff0fac90cf586 +2024-12-10 771ed5473eba6aff46ba9b9dd000748f0736633a diff --git a/repos/os/recipes/src/vmm/hash b/repos/os/recipes/src/vmm/hash index c3e211df91..134cbaa832 100644 --- a/repos/os/recipes/src/vmm/hash +++ b/repos/os/recipes/src/vmm/hash @@ -1 +1 @@ -2024-08-28 43e940305d0578c3d74c927f07923ab9e5932d2b +2024-12-10 aa9108db658757b08f096287633ac1118c5e46e3 diff --git a/repos/os/recipes/src/waveform_player/hash b/repos/os/recipes/src/waveform_player/hash index 3b0e640464..7f8f7a17ca 100644 --- a/repos/os/recipes/src/waveform_player/hash +++ b/repos/os/recipes/src/waveform_player/hash @@ -1 +1 @@ -2024-08-28 161f756662fe55ee21eeecdea02a0a035bc975e3 +2024-12-10 67e20dc1d36c7ea3d65c0251ee552a24f793135d diff --git a/repos/os/run/demo.run b/repos/os/run/demo.run index 2d4368dd5c..4c7514fd87 100644 --- a/repos/os/run/demo.run +++ b/repos/os/run/demo.run @@ -202,7 +202,7 @@ puts $launchpad_config_fd {<config> <launcher name="launchpad" ram_quota="6M" caps="1000"> <configfile name="launchpad.config" /> </launcher> - <launcher name="nitlog" ram_quota="1M" caps="100"/> + <launcher name="nitlog" ram_quota="1500K" caps="100"/> <launcher name="liquid_fb" ram_quota="9M" caps="100"> <config resize_handle="on" /> </launcher> diff --git a/repos/os/run/fb_bench.run b/repos/os/run/fb_bench.run index 1185dd4ded..38f52bb00f 100644 --- a/repos/os/run/fb_bench.run +++ b/repos/os/run/fb_bench.run @@ -71,7 +71,7 @@ install_config { </start> <start name="gui_fb"> - <resource name="RAM" quantum="4M"/> + <resource name="RAM" quantum="5M"/> <provides> <service name="Framebuffer"/> <service name="Input"/> </provides> <config/> <route> diff --git a/repos/os/src/app/pci_decode/drhd.h b/repos/os/src/app/pci_decode/drhd.h index 6592687f1e..75714d6a51 100644 --- a/repos/os/src/app/pci_decode/drhd.h +++ b/repos/os/src/app/pci_decode/drhd.h @@ -34,10 +34,14 @@ struct Drhd : List_model<Drhd>::Element struct Device : Registry<Device>::Element { - Bdf bdf; + enum { IOAPIC = 0x3 }; - Device(Registry<Device> & registry, Bdf bdf) - : Registry<Device>::Element(registry, *this), bdf(bdf) + Bdf bdf; + uint8_t type; + uint8_t id; + + Device(Registry<Device> & registry, Bdf bdf, uint8_t type, uint8_t id) + : Registry<Device>::Element(registry, *this), bdf(bdf), type(type), id(id) { } }; diff --git a/repos/os/src/app/pci_decode/ioapic.h b/repos/os/src/app/pci_decode/ioapic.h new file mode 100644 index 0000000000..3c3598b55c --- /dev/null +++ b/repos/os/src/app/pci_decode/ioapic.h @@ -0,0 +1,42 @@ +/* + * \brief IOAPIC reporting from ACPI information in list models + * \author Johannes Schlatow + * \date 2024-03-20 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + + +#include <util/list_model.h> + +using namespace Genode; + +struct Ioapic : List_model<Ioapic>::Element +{ + using Ioapic_name = String<16>; + + uint8_t id; + addr_t addr; + uint32_t base_irq; + + Ioapic(uint8_t id, addr_t addr, uint32_t base_irq) + : id(id), addr(addr), base_irq(base_irq) + { } + + Ioapic_name name() const { return Ioapic_name("ioapic", id); } + + bool matches(Xml_node const &node) const + { + return id == node.attribute_value("id", 0UL); + } + + static bool type_matches(Xml_node const &node) + { + return node.has_type("ioapic"); + } +}; diff --git a/repos/os/src/app/pci_decode/main.cc b/repos/os/src/app/pci_decode/main.cc index e3dcca33b3..55d0f5c763 100644 --- a/repos/os/src/app/pci_decode/main.cc +++ b/repos/os/src/app/pci_decode/main.cc @@ -22,6 +22,7 @@ #include <irq.h> #include <rmrr.h> #include <drhd.h> +#include <ioapic.h> #include <pci/config.h> using namespace Genode; @@ -50,6 +51,7 @@ struct Main List_model<Irq_override> irq_override_list {}; List_model<Rmrr> reserved_memory_list {}; List_model<Drhd> drhd_list {}; + List_model<Ioapic> ioapic_list {}; Constructible<Attached_io_mem_dataspace> pci_config_ds {}; @@ -149,6 +151,8 @@ bus_t Main::parse_pci_function(Bdf bdf, if (msi) cfg.msi_cap->write<Pci::Config::Msi_capability::Control::Enable>(0); if (msi_x) cfg.msi_x_cap->write<Pci::Config::Msi_x_capability::Control::Enable>(0); + /* XXX we might need to skip PCI-discoverable IOAPIC and IOMMU devices */ + gen.node("device", [&] { auto string = [&] (uint64_t v) { return String<16>(Hex(v)); }; @@ -228,26 +232,10 @@ bus_t Main::parse_pci_function(Bdf bdf, }); { - /* Apply GSI/MSI/MSI-X quirks based on vendor/device/class */ - using Cc = Config::Class_code_rev_id; - - bool const hdaudio = cfg.read<Cc::Class_code>() == 0x40300; + /* Apply GSI/MSI/MSI-X quirks based on vendor/device */ auto const vendor_id = cfg.read<Config::Vendor>(); auto const device_id = cfg.read<Config::Device>(); - if (hdaudio && vendor_id == 0x1022 /* AMD */) { - /** - * see dde_bsd driver dev/pci/azalia.c - * - * PCI_PRODUCT_AMD_17_HDA - * PCI_PRODUCT_AMD_17_1X_HDA - * PCI_PRODUCT_AMD_HUDSON2_HDA - */ - if (device_id == 0x1457 || device_id == 0x15e3 || - device_id == 0x780d) - msi = msi_x = false; - } - /* * Force use of GSI on given ath9k device as using MSI * does not work. @@ -507,6 +495,55 @@ void Main::parse_acpi_device_info(Xml_node const &xml, Xml_generator & gen) if (xml.has_sub_node("sci_int")) parse_acpica_info(xml, gen); + /* + * IOAPIC devices + */ + bool intr_remap = false; + xml.with_optional_sub_node("dmar", [&] (Xml_node const & node) { + intr_remap = node.attribute_value("intr_remap", intr_remap); }); + + ioapic_list.for_each([&] (Ioapic const & ioapic) { + gen.node("device", [&] + { + gen.attribute("name", ioapic.name()); + gen.attribute("type", "ioapic"); + gen.node("io_mem", [&] + { + gen.attribute("address", String<20>(Hex(ioapic.addr))); + gen.attribute("size", "0x1000"); + }); + + /* find corresponding drhd and add <io_mmu/> node and Routing_id property */ + drhd_list.for_each([&] (Drhd const & drhd) { + drhd.devices.for_each([&] (Drhd::Device const & device) { + if (device.type == Drhd::Device::IOAPIC && device.id == ioapic.id) { + gen.node("io_mmu", [&] { gen.attribute("name", drhd.name()); }); + gen.node("property", [&] + { + gen.attribute("name", "routing_id"); + gen.attribute("value", String<10>(Hex(Pci::Bdf::rid(device.bdf)))); + }); + } + }); + }); + + gen.node("property", [&] + { + gen.attribute("name", "irq_start"); + gen.attribute("value", ioapic.base_irq); + }); + + if (!intr_remap) + return; + + gen.node("property", [&] + { + gen.attribute("name", "remapping"); + gen.attribute("value", "yes"); + }); + }); + }); + /* Intel DMA-remapping hardware units */ drhd_list.for_each([&] (Drhd const & drhd) { gen.node("device", [&] @@ -702,6 +739,25 @@ Main::Main(Env & env) : env(env) [&] (Rmrr &, Xml_node const &) { } ); + ioapic_list.update_from_xml(xml, + + /* create */ + [&] (Xml_node const &node) -> Ioapic & + { + uint8_t id = node.attribute_value("id", (uint8_t)0U); + addr_t addr = node.attribute_value("addr", 0U); + uint32_t base = node.attribute_value("base_irq", 0U); + + return *new (heap) Ioapic(id, addr, base); + }, + + /* destroy */ + [&] (Ioapic &ioapic) { destroy(heap, &ioapic); }, + + /* update */ + [&] (Ioapic &, Xml_node const &) { } + ); + unsigned nbr { 0 }; drhd_list.update_from_xml(xml, @@ -722,18 +778,22 @@ Main::Main(Env & env) : env(env) Drhd::Scope::EXPLICIT, nbr++); /* parse device scopes which define the explicitly assigned devices */ - bus_t bus = 0; - dev_t dev = 0; - func_t fn = 0; + bus_t bus = 0; + dev_t dev = 0; + func_t fn = 0; + uint8_t type = 0; + uint8_t id = 0; node.for_each_sub_node("scope", [&] (Xml_node node) { - bus = node.attribute_value<uint8_t>("bus_start", 0U); + bus = node.attribute_value<uint8_t>("bus_start", 0U); + type = node.attribute_value<uint8_t>("type", 0U); + id = node.attribute_value<uint8_t>("id", 0U); node.with_optional_sub_node("path", [&] (Xml_node node) { dev = node.attribute_value<uint8_t>("dev", 0); fn = node.attribute_value<uint8_t>("func", 0); }); - new (heap) Drhd::Device(drhd->devices, {bus, dev, fn}); + new (heap) Drhd::Device(drhd->devices, {bus, dev, fn}, type, id); }); return *drhd; diff --git a/repos/os/src/app/pointer/main.cc b/repos/os/src/app/pointer/main.cc index ec98137354..cfdc39cb7f 100644 --- a/repos/os/src/app/pointer/main.cc +++ b/repos/os/src/app/pointer/main.cc @@ -133,9 +133,7 @@ void Pointer::Main::_resize_gui_buffer_if_needed(Gui::Area pointer_size) if (pointer_size == _current_pointer_size) return; - Framebuffer::Mode const mode { .area = pointer_size }; - - _gui.buffer(mode, true /* use alpha */); + _gui.buffer({ .area = pointer_size, .alpha = true }); _pointer_ds = _gui.framebuffer.dataspace(); @@ -163,7 +161,7 @@ void Pointer::Main::_show_default_pointer() convert_default_pointer_data_to_pixels(ds.local_addr<Genode::Pixel_rgb888>(), pointer_size); - _gui.framebuffer.refresh(0, 0, pointer_size.w, pointer_size.h); + _gui.framebuffer.refresh({ { 0, 0 }, pointer_size }); Gui::Rect geometry(Gui::Point(0, 0), pointer_size); _gui.enqueue<Gui::Session::Command::Geometry>(_view.id(), geometry); @@ -224,7 +222,7 @@ void Pointer::Main::_show_shape_pointer(Shape_report &shape_report) Dither_painter::paint(alpha_surface, texture); } - _gui.framebuffer.refresh(0, 0, shape_size.w, shape_size.h); + _gui.framebuffer.refresh({ { 0, 0 }, shape_size }); Gui::Rect geometry(shape_hot, shape_size); _gui.enqueue<Gui::Session::Command::Geometry>(_view.id(), geometry); @@ -333,9 +331,9 @@ Pointer::Main::Main(Genode::Env &env) : _env(env) * pointer size to let the user know right from the start if the * RAM quota is too low. */ - Framebuffer::Mode const mode { .area = { Pointer::MAX_WIDTH, Pointer::MAX_HEIGHT } }; - _gui.buffer(mode, true /* use alpha */); + _gui.buffer({ .area = { Pointer::MAX_WIDTH, Pointer::MAX_HEIGHT }, + .alpha = true }); if (_shapes_enabled) { try { diff --git a/repos/os/src/app/sequence/main.cc b/repos/os/src/app/sequence/main.cc index cdb1fbfe7a..0ba3e6995e 100644 --- a/repos/os/src/app/sequence/main.cc +++ b/repos/os/src/app/sequence/main.cc @@ -135,12 +135,14 @@ struct Sequence::Child : Genode::Child_policy return route(service); } + Ram_allocator &session_md_ram() override { return _env.pd(); } + /** * Only a single child is managed at a time so * no additional PD management is required. */ - Pd_session &ref_pd() override { return _env.pd(); } - Pd_session_capability ref_pd_cap() const override { return _env.pd_session_cap(); } + Pd_account &ref_account() override { return _env.pd(); } + Capability<Pd_account> ref_account_cap() const override { return _env.pd_session_cap(); } /** * Always queue a reload signal and store the exit value. The @@ -175,9 +177,9 @@ struct Sequence::Child : Genode::Child_policy if (ram.value) { Ram_quota avail = _env.pd().avail_ram(); if (avail.value > ram.value) { - ref_pd().transfer_quota(pd_cap, ram); + ref_account().transfer_quota(pd_cap, ram); } else { - ref_pd().transfer_quota(pd_cap, Ram_quota{avail.value >> 1}); + ref_account().transfer_quota(pd_cap, Ram_quota{avail.value >> 1}); _env.parent().resource_request(args); } } @@ -185,9 +187,9 @@ struct Sequence::Child : Genode::Child_policy if (caps.value) { Cap_quota avail = _env.pd().avail_caps(); if (avail.value > caps.value) { - ref_pd().transfer_quota(pd_cap, caps); + ref_account().transfer_quota(pd_cap, caps); } else { - ref_pd().transfer_quota(pd_cap, Cap_quota{avail.value >> 1}); + ref_account().transfer_quota(pd_cap, Cap_quota{avail.value >> 1}); _env.parent().resource_request(args); } } @@ -201,9 +203,9 @@ struct Sequence::Child : Genode::Child_policy */ void init(Pd_session &pd, Pd_session_capability pd_cap) override { - pd.ref_account(ref_pd_cap()); - ref_pd().transfer_quota(pd_cap, Cap_quota{_env.pd().avail_caps().value >> 1}); - ref_pd().transfer_quota(pd_cap, Ram_quota{_env.pd().avail_ram().value >> 1}); + pd.ref_account(ref_account_cap()); + ref_account().transfer_quota(pd_cap, Cap_quota{_env.pd().avail_caps().value >> 1}); + ref_account().transfer_quota(pd_cap, Ram_quota{_env.pd().avail_ram().value >> 1}); } Id_space<Parent::Server> &server_id_space() override { return _server_ids; } diff --git a/repos/os/src/app/shim/main.cc b/repos/os/src/app/shim/main.cc index bf01a07bb1..0018a923ed 100644 --- a/repos/os/src/app/shim/main.cc +++ b/repos/os/src/app/shim/main.cc @@ -108,14 +108,16 @@ class Shim::Main : public Child_policy Binary_name binary_name() const override { return "binary"; } - Pd_session &ref_pd() override { return _env.pd(); } - Pd_session_capability ref_pd_cap() const override { return _env.pd_session_cap(); } + Ram_allocator &session_md_ram() override { return _env.ram(); } + + Pd_account &ref_account() override { return _env.pd(); } + Capability<Pd_account> ref_account_cap() const override { return _env.pd_session_cap(); } void init(Pd_session &pd, Pd_session_capability pd_cap) override { - pd.ref_account(ref_pd_cap()); - ref_pd().transfer_quota(pd_cap, _cap_quota); - ref_pd().transfer_quota(pd_cap, _ram_quota); + pd.ref_account(_env.pd_session_cap()); + ref_account().transfer_quota(pd_cap, _cap_quota); + ref_account().transfer_quota(pd_cap, _ram_quota); } Route resolve_session_request(Service::Name const &name, diff --git a/repos/os/src/app/status_bar/main.cc b/repos/os/src/app/status_bar/main.cc index ceefc3426d..141c6a2aad 100644 --- a/repos/os/src/app/status_bar/main.cc +++ b/repos/os/src/app/status_bar/main.cc @@ -44,18 +44,21 @@ struct Status_bar::Buffer Gui::Connection &_gui; - Framebuffer::Mode const _nit_mode { _gui.mode() }; + Gui::Area const _scr_area = _gui.panorama().convert<Gui::Area>( + [&] (Gui::Rect rect) { return rect.area; }, + [&] (Gui::Undefined) { return Gui::Area { 1, 1 }; }); /* * Dimension nitpicker buffer depending on nitpicker's screen size. * The status bar is as wide as nitpicker's screen and has a fixed * height. */ - Framebuffer::Mode const _mode { .area = { _nit_mode.area.w, HEIGHT } }; + Framebuffer::Mode const _mode { .area = { _scr_area.w, HEIGHT }, + .alpha = false }; Dataspace_capability _init_buffer() { - _gui.buffer(_mode, false); + _gui.buffer(_mode); return _gui.framebuffer.dataspace(); } @@ -157,7 +160,7 @@ void Status_bar::Buffer::draw(Domain_name const &domain_name, _draw_label(surface, view_rect.center(_label_size(domain_name, label)), domain_name, label, color); - _gui.framebuffer.refresh(0, 0, area.w, area.h); + _gui.framebuffer.refresh({ { 0, 0 }, area }); } @@ -197,7 +200,7 @@ struct Status_bar::Main { /* register signal handlers */ _focus_ds.sigh(_focus_handler); - _gui.mode_sigh(_mode_handler); + _gui.info_sigh(_mode_handler); /* import initial state */ _handle_mode(); diff --git a/repos/os/src/driver/acpi/acpi.cc b/repos/os/src/driver/acpi/acpi.cc index d0c0283a98..3135df3f65 100644 --- a/repos/os/src/driver/acpi/acpi.cc +++ b/repos/os/src/driver/acpi/acpi.cc @@ -42,13 +42,11 @@ static const bool verbose = false; */ struct Apic_struct { - enum Types { SRC_OVERRIDE = 2 }; + enum Types { IOAPIC = 1, SRC_OVERRIDE = 2 }; uint8_t type; uint8_t length; - bool is_override() { return type == SRC_OVERRIDE; } - Apic_struct *next() { return reinterpret_cast<Apic_struct *>((uint8_t *)this + length); } } __attribute__((packed)); @@ -75,6 +73,15 @@ struct Apic_override : Apic_struct uint16_t flags; } __attribute__((packed)); +/* ACPI spec 5.2.12.3 */ +struct Apic_ioapic : Apic_struct +{ + uint8_t id; + uint8_t reserved; + uint32_t addr; + uint32_t base_irq; +} __attribute__((packed)); + struct Dmar_struct_header; /* ACPI spec 5.2.6 */ @@ -169,6 +176,7 @@ struct Device_scope : Genode::Mmio<0x6> struct Type : Register<0x0, 8> { enum { PCI_END_POINT = 0x1 }; }; struct Length : Register<0x1, 8> { }; + struct Id : Register<0x4, 8> { }; struct Bus : Register<0x5, 8> { }; struct Path : Genode::Mmio<0x2> @@ -406,6 +414,34 @@ class Irq_override : public List<Irq_override>::Element }; +/** + * List that holds IOAPIC information + */ +class Ioapic : public List<Ioapic>::Element +{ + private: + + uint8_t _id; /* I/O APIC id */ + uint32_t _addr; /* physical address */ + uint32_t _base_irq; /* base irq number */ + + public: + + Ioapic(uint8_t id, uint32_t addr, uint32_t base) + : _id(id), _addr(addr), _base_irq(base) { } + + static List<Ioapic> *list() + { + static List<Ioapic> _list; + return &_list; + } + + uint8_t id() const { return _id; } + uint32_t addr() const { return _addr; } + uint32_t base_irq() const { return _base_irq; } +}; + + /** * List that holds the result of the mcfg table parsing which are pointers * to the extended pci config space - 4k for each device. @@ -581,7 +617,7 @@ class Table_wrapper return sum; } - bool valid() { return !checksum((uint8_t *)_table, _table->size); } + bool valid() { return _table && !checksum((uint8_t *)_table, _table->size); } bool is_ivrs() const { return _cmp("IVRS");} @@ -611,22 +647,37 @@ class Table_wrapper bool is_dmar() { return _cmp("DMAR"); } /** - * Parse override structures + * Parse MADT/APIC table */ void parse_madt(Genode::Allocator &alloc) { Apic_struct *apic = _table->apic_struct(); for (; apic < _table->end(); apic = apic->next()) { - if (!apic->is_override()) - continue; + Apic_override *o; + Apic_ioapic *ioapic; - Apic_override *o = static_cast<Apic_override *>(apic); - - Genode::log("MADT IRQ ", o->irq, " -> GSI ", (unsigned)o->gsi, " " - "flags: ", (unsigned)o->flags); - - Irq_override::list()->insert(new (&alloc) + switch (apic->type) { + + case Apic_struct::Types::SRC_OVERRIDE: + o = static_cast<Apic_override *>(apic); + + Genode::log("MADT IRQ ", o->irq, " -> GSI ", (unsigned)o->gsi, " " + "flags: ", (unsigned)o->flags); + + Irq_override::list()->insert(new (&alloc) Irq_override(o->irq, o->gsi, o->flags)); + break; + + case Apic_struct::Types::IOAPIC: + ioapic = static_cast<Apic_ioapic *>(apic); + + Ioapic::list()->insert(new (&alloc) + Ioapic(ioapic->id, ioapic->addr, ioapic->base_irq)); + break; + + default: + break; + } } } @@ -649,7 +700,7 @@ class Table_wrapper } } - void parse_dmar(Genode::Allocator &alloc) const + Dmar_struct_header const & parse_dmar(Genode::Allocator &alloc) const { Dmar_struct_header *head = _table->dmar_header(); Genode::log(head->width + 1, " bit DMA physical addressable", @@ -661,14 +712,21 @@ class Table_wrapper }); Dmar_entry::list()->insert(new (&alloc) Dmar_entry(head->clone(alloc))); + + return *head; } Table_wrapper(Acpi::Memory &memory, addr_t base, Registry<Info> ®istry, Allocator &heap) : _base(base), _table(0) { - /* make table header accessible */ - _table = reinterpret_cast<Generic *>(memory.map_region(base, 8)); + try { + /* make table header accessible */ + _table = reinterpret_cast<Generic *>(memory.map_region(base, 8)); + } catch (Service_denied &) { + error(__func__, " failed with exception"); + return; + } /* table size is known now - make it completely accessible (in place) */ memory.map_region(base, _table->size); @@ -929,7 +987,7 @@ class Element : private List<Element>::Element if (_name_len + parent_len > sizeof(_name)) { Genode::error("name is not large enough"); - throw -1; + return; } memcpy(_name, parent->_name, parent_len); @@ -1359,7 +1417,14 @@ class Acpi_table Genode::uint8_t value; }; + struct Dmar_info + { + bool intr_remap; + Genode::uint8_t host_address_width; + }; + Genode::Constructible<Reset_info> _reset_info { }; + Genode::Constructible<Dmar_info> _dmar_info { }; unsigned short _sci_int { }; bool _sci_int_valid { }; @@ -1380,7 +1445,7 @@ class Acpi_table !Table_wrapper::checksum(area + addr, 20)) return area + addr; - throw -2; + return 0; } /** @@ -1394,8 +1459,7 @@ class Acpi_table try { _mmio.construct(_env, BIOS_BASE, BIOS_SIZE); return _search_rsdp(_mmio->local_addr<uint8_t>(), BIOS_SIZE); - } - catch (...) { } + } catch (...) { } /* search EBDA (BIOS addr + 0x40e) */ try { @@ -1475,7 +1539,10 @@ class Acpi_table if (table.is_dmar()) { Genode::log("Found DMAR"); - table.parse_dmar(_heap); + Dmar_struct_header const & head = table.parse_dmar(_heap); + _dmar_info.construct( + Dmar_info { (bool)(head.flags & Dmar_struct_header::INTR_REMAP_MASK), + (uint8_t)(head.width + 1) }); } } catch (Acpi::Memory::Unsupported_range &) { } @@ -1523,51 +1590,58 @@ class Acpi_table if (!rsdt && !xsdt) { uint8_t * ptr_rsdp = _rsdp(); - struct rsdp { - char signature[8]; - uint8_t checksum; - char oemid[6]; - uint8_t revision; - /* table pointer at 16 byte offset in RSDP structure (5.2.5.3) */ - uint32_t rsdt; - /* With ACPI 2.0 */ - uint32_t len; - uint64_t xsdt; - uint8_t checksum_extended; - uint8_t reserved[3]; - } __attribute__((packed)); - struct rsdp * rsdp = reinterpret_cast<struct rsdp *>(ptr_rsdp); + if (ptr_rsdp) { + struct rsdp { + char signature[8]; + uint8_t checksum; + char oemid[6]; + uint8_t revision; + /* table pointer at 16 byte offset in RSDP structure (5.2.5.3) */ + uint32_t rsdt; + /* With ACPI 2.0 */ + uint32_t len; + uint64_t xsdt; + uint8_t checksum_extended; + uint8_t reserved[3]; + } __attribute__((packed)); + struct rsdp * rsdp = reinterpret_cast<struct rsdp *>(ptr_rsdp); - if (!rsdp) { - Genode::error("No valid ACPI RSDP structure found"); - return; + if (rsdp) { + rsdt = rsdp->rsdt; + xsdt = rsdp->xsdt; + acpi_revision = rsdp->revision; + } else { + Genode::error("No valid ACPI RSDP structure found"); + } } - rsdt = rsdp->rsdt; - xsdt = rsdp->xsdt; - acpi_revision = rsdp->revision; /* drop rsdp io_mem mapping since rsdt/xsdt may overlap */ _mmio.destruct(); } - if (acpi_revision != 0 && xsdt && sizeof(addr_t) != sizeof(uint32_t)) { - /* running 64bit and xsdt is valid */ - Table_wrapper table(_memory, xsdt, _table_registry, _heap); - if (!table.valid()) throw -1; + if (rsdt || xsdt) { + if (acpi_revision != 0 && xsdt && sizeof(addr_t) != sizeof(uint32_t)) { + /* running 64bit and xsdt is valid */ + Table_wrapper table(_memory, xsdt, _table_registry, _heap); + if (table.valid()) { + uint64_t * entries = reinterpret_cast<uint64_t *>(table.table() + 1); + _parse_tables(entries, table.entry_count(entries)); - uint64_t * entries = reinterpret_cast<uint64_t *>(table.table() + 1); - _parse_tables(entries, table.entry_count(entries)); + log("XSDT ", *table.table()); + } else + error("XSDT parsing error"); - Genode::log("XSDT ", *table.table()); - } else { - /* running (32bit) or (64bit and xsdt isn't valid) */ - Table_wrapper table(_memory, rsdt, _table_registry, _heap); - if (!table.valid()) throw -1; + } else { + /* running (32bit) or (64bit and xsdt isn't valid) */ + Table_wrapper table(_memory, rsdt, _table_registry, _heap); + if (table.valid()) { + uint32_t * entries = reinterpret_cast<uint32_t *>(table.table() + 1); + _parse_tables(entries, table.entry_count(entries)); - uint32_t * entries = reinterpret_cast<uint32_t *>(table.table() + 1); - _parse_tables(entries, table.entry_count(entries)); - - Genode::log("RSDT ", *table.table()); + log("RSDT ", *table.table()); + } else + error("RSDT parsing error"); + } } /* free up memory of elements not of any use */ @@ -1589,6 +1663,13 @@ class Acpi_table if (_sci_int_valid) xml.node("sci_int", [&] () { xml.attribute("irq", _sci_int); }); + if (_dmar_info.constructed()) + xml.node("dmar", [&] () { + xml.attribute("intr_remap", _dmar_info->intr_remap); + xml.attribute("host_address_width", _dmar_info->host_address_width); + }); + + if (!_reset_info.constructed()) return; @@ -1653,11 +1734,21 @@ void Acpi::generate_report(Genode::Env &env, Genode::Allocator &alloc, }); } + for (Ioapic *i = Ioapic::list()->first(); i; i = i->next()) + { + xml.node("ioapic", [&] () { + xml.attribute("id", i->id()); + xml.attribute("base_irq", i->base_irq()); + attribute_hex(xml, "addr", i->addr()); + }); + } + /* lambda definition for scope evaluation in rmrr */ auto func_scope = [&] (Device_scope const &scope) { xml.node("scope", [&] () { xml.attribute("bus_start", scope.read<Device_scope::Bus>()); + xml.attribute("id", scope.read<Device_scope::Id>()); xml.attribute("type", scope.read<Device_scope::Type>()); scope.for_each_path([&](auto const &path) { @@ -1733,6 +1824,10 @@ void Acpi::generate_report(Genode::Env &env, Genode::Allocator &alloc, * Intel opregion lookup & parsing must be finished before acpi * report is sent, therefore the invocation is placed exactly here. */ - Pci_config_space::intel_opregion(env); + try { + Pci_config_space::intel_opregion(env); + } catch (...) { + error("Intel opregion handling failed"); + } }); } diff --git a/repos/os/src/driver/framebuffer/boot/main.cc b/repos/os/src/driver/framebuffer/boot/main.cc index 02f3511e3b..d257fd39f8 100644 --- a/repos/os/src/driver/framebuffer/boot/main.cc +++ b/repos/os/src/driver/framebuffer/boot/main.cc @@ -87,8 +87,9 @@ struct Framebuffer::Main Capture::Connection _capture { _env }; - Capture::Connection::Screen _captured_screen { _capture, _env.rm(), _info.size }; - + Capture::Connection::Screen _captured_screen { _capture, _env.rm(), { + .px = _info.size, + .mm = { } } }; Timer::Connection _timer { _env }; Signal_handler<Main> _timer_handler { _env.ep(), *this, &Main::_handle_timer }; diff --git a/repos/os/src/driver/framebuffer/pl11x/main.cc b/repos/os/src/driver/framebuffer/pl11x/main.cc index dd6bbfd349..54611e4ccb 100644 --- a/repos/os/src/driver/framebuffer/pl11x/main.cc +++ b/repos/os/src/driver/framebuffer/pl11x/main.cc @@ -59,7 +59,9 @@ struct Pl11x_driver::Main Capture::Connection _capture { _env }; - Capture::Connection::Screen _captured_screen { _capture, _env.rm(), _size }; + Capture::Connection::Screen _captured_screen { _capture, _env.rm(), { + .px = _size, + .mm = { } } }; /* diff --git a/repos/os/src/driver/framebuffer/ram/main.cc b/repos/os/src/driver/framebuffer/ram/main.cc index 8d4d0c2425..38d099c2a9 100644 --- a/repos/os/src/driver/framebuffer/ram/main.cc +++ b/repos/os/src/driver/framebuffer/ram/main.cc @@ -65,8 +65,9 @@ class Main Capture::Area const _size { SCR_WIDTH, SCR_HEIGHT }; Capture::Connection _capture { _env }; - Capture::Connection::Screen _captured_screen { _capture, _env.rm(), _size }; - + Capture::Connection::Screen _captured_screen { _capture, _env.rm(), { + .px = _size, + .mm = { } } }; Timer::Connection _timer { _env }; Signal_handler<Main> _timer_handler { _env.ep(), *this, &Main::_handle_timer }; diff --git a/repos/os/src/driver/framebuffer/sdl/main.cc b/repos/os/src/driver/framebuffer/sdl/main.cc index 7376dcf44e..d88cf5c8f6 100644 --- a/repos/os/src/driver/framebuffer/sdl/main.cc +++ b/repos/os/src/driver/framebuffer/sdl/main.cc @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2006-2017 Genode Labs GmbH + * Copyright (C) 2006-2024 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -31,63 +31,100 @@ namespace Fb_sdl { class Main; + class Sdl; + using namespace Genode; -} - - -/* fatal exceptions */ -struct Sdl_init_failed : Genode::Exception { }; -struct Sdl_videodriver_not_supported : Genode::Exception { }; -struct Sdl_createwindow_failed : Genode::Exception { }; -struct Sdl_createrenderer_failed : Genode::Exception { }; -struct Sdl_creatergbsurface_failed : Genode::Exception { }; -struct Sdl_createtexture_failed : Genode::Exception { }; - - -struct Fb_sdl::Main -{ - Env &_env; - - Attached_rom_dataspace _config { _env, "config" }; - - Timer::Connection _timer { _env }; - Event::Connection _event { _env }; using Area = Capture::Area; - using Point = Capture::Area; + using Rect = Capture::Rect; using Pixel = Capture::Pixel; using Affected_rects = Capture::Session::Affected_rects; using Event_batch = Event::Session_client::Batch; - void _init_sdl() + static constexpr int USER_EVENT_CAPTURE_WAKEUP = 99; +} + + +/** + * Interplay with libSDL + */ +struct Fb_sdl::Sdl : Noncopyable +{ + Event::Connection &_event; + Capture::Connection &_capture; + Region_map &_rm; + + struct Ticks { Uint32 ms; }; + + struct Attr { - /* - * Initialize libSDL window - */ - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - error("SDL_Init failed (", Genode::Cstring(SDL_GetError()), ")"); - throw Sdl_init_failed(); + Area initial_size; + + double fps; /* frames per second */ + unsigned idle; /* disable capturing after 'idle' frames of no progress */ + + static Attr from_xml(Xml_node const &node) + { + return { + .initial_size = { .w = node.attribute_value("width", 1024u), + .h = node.attribute_value("height", 768u) }, + .fps = node.attribute_value("fps", 60.0), + .idle = node.attribute_value("idle", 3U) + }; } - SDL_ShowCursor(0); + Ticks period() const + { + return { (fps > 0) ? unsigned(1000.0/fps) : 20u }; + } + }; + + Attr const _attr; + + /* fatal exceptions */ + struct Init_failed : Exception { }; + struct Createthread_failed : Exception { }; + struct Videodriver_not_supported : Exception { }; + struct Createwindow_failed : Exception { }; + struct Createrenderer_failed : Exception { }; + struct Creatergbsurface_failed : Exception { }; + struct Createtexture_failed : Exception { }; + + void _thread(); + + static int _entry(void *data_ptr) + { + ((Sdl *)data_ptr)->_thread(); + return 0; } - bool const _sdl_initialized = ( _init_sdl(), true ); + SDL_Thread &_init_thread() + { + SDL_Thread *ptr = SDL_CreateThread(_entry, "SDL", this); + if (ptr) + return *ptr; - struct Sdl_window + throw Createthread_failed(); + } + + SDL_Thread &_sdl_thread = _init_thread(); + + struct Window { Area const _initial_size; - SDL_Renderer &_sdl_renderer = _init_sdl_renderer(); + SDL_Renderer &renderer = _init_renderer(); - SDL_Renderer &_init_sdl_renderer() + SDL_Renderer &_init_renderer() { unsigned const window_flags = 0; - SDL_Window *window_ptr = SDL_CreateWindow("fb_sdl", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, _initial_size.w, _initial_size.h, window_flags); + SDL_Window * const window_ptr = + SDL_CreateWindow("fb_sdl", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, + _initial_size.w, _initial_size.h, window_flags); if (!window_ptr) { - error("SDL_CreateWindow failed (", Genode::Cstring(SDL_GetError()), ")"); - throw Sdl_createwindow_failed(); + error("SDL_CreateWindow failed (", Cstring(SDL_GetError()), ")"); + throw Createwindow_failed(); } SDL_SetWindowResizable(window_ptr, SDL_TRUE); @@ -96,35 +133,30 @@ struct Fb_sdl::Main unsigned const renderer_flags = SDL_RENDERER_SOFTWARE; SDL_Renderer *renderer_ptr = SDL_CreateRenderer(window_ptr, index, renderer_flags); if (!renderer_ptr) { - error("SDL_CreateRenderer failed (", Genode::Cstring(SDL_GetError()), ")"); - throw Sdl_createrenderer_failed(); + error("SDL_CreateRenderer failed (", Cstring(SDL_GetError()), ")"); + throw Createrenderer_failed(); } return *renderer_ptr; } - Sdl_window(Area size) : _initial_size(size) { } + Window(Area size) : _initial_size(size) { } - ~Sdl_window() + ~Window() { - SDL_DestroyRenderer(&_sdl_renderer); - } - - SDL_Renderer &renderer() - { - return _sdl_renderer; + SDL_DestroyRenderer(&renderer); } }; - struct Sdl_screen + struct Screen { Area const size; SDL_Renderer &renderer; - SDL_Surface &_sdl_surface = _init_sdl_surface(); - SDL_Texture &_sdl_texture = _init_sdl_texture(); + SDL_Surface &_surface = _init_surface(); + SDL_Texture &_texture = _init_texture(); - SDL_Surface &_init_sdl_surface() + SDL_Surface &_init_surface() { unsigned const flags = 0; unsigned const bpp = 32; @@ -133,127 +165,217 @@ struct Fb_sdl::Main unsigned const blue_mask = 0x000000FF; unsigned const alpha_mask = 0xFF000000; - SDL_Surface *surface_ptr = SDL_CreateRGBSurface(flags, size.w, size.h, bpp, red_mask, green_mask, blue_mask, alpha_mask); + SDL_Surface * const surface_ptr = + SDL_CreateRGBSurface(flags, size.w, size.h, bpp, + red_mask, green_mask, blue_mask, alpha_mask); if (!surface_ptr) { - error("SDL_CreateRGBSurface failed (", Genode::Cstring(SDL_GetError()), ")"); - throw Sdl_creatergbsurface_failed(); + error("SDL_CreateRGBSurface failed (", Cstring(SDL_GetError()), ")"); + throw Creatergbsurface_failed(); } return *surface_ptr; } - SDL_Texture &_init_sdl_texture() + SDL_Texture &_init_texture() { - SDL_Texture *texture_ptr = SDL_CreateTexture(&renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, size.w, size.h); + SDL_Texture * const texture_ptr = + SDL_CreateTexture(&renderer, SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STREAMING, size.w, size.h); if (!texture_ptr) { - error("SDL_CreateTexture failed (", Genode::Cstring(SDL_GetError()), ")"); - throw Sdl_createtexture_failed(); + error("SDL_CreateTexture failed (", Cstring(SDL_GetError()), ")"); + throw Createtexture_failed(); } return *texture_ptr; } - Sdl_screen(Area size, SDL_Renderer &renderer) : size(size), renderer(renderer) { } + Screen(Area size, SDL_Renderer &renderer) : size(size), renderer(renderer) { } - ~Sdl_screen() + ~Screen() { - SDL_FreeSurface(&_sdl_surface); - SDL_DestroyTexture(&_sdl_texture); + SDL_FreeSurface(&_surface); + SDL_DestroyTexture(&_texture); } - template <typename FN> - void with_surface(FN const &fn) + void with_surface(auto const &fn) { - Surface<Pixel> surface { (Pixel *)_sdl_surface.pixels, size }; + Surface<Pixel> surface { (Pixel *)_surface.pixels, size }; fn(surface); } - void flush() + void flush(Capture::Rect const bounding_box) { - SDL_UpdateTexture(&_sdl_texture, nullptr, _sdl_surface.pixels, _sdl_surface.pitch); - SDL_RenderClear(&renderer); - SDL_RenderCopy(&renderer, &_sdl_texture, nullptr, nullptr); + SDL_Rect const rect { .x = bounding_box.at.x, + .y = bounding_box.at.y, + .w = int(bounding_box.area.w), + .h = int(bounding_box.area.h) }; + + SDL_UpdateTexture(&_texture, nullptr, _surface.pixels, _surface.pitch); + SDL_RenderCopy(&renderer, &_texture, &rect, &rect); SDL_RenderPresent(&renderer); } + + void flush_all() { flush(Rect { { 0, 0 }, size }); } }; - Constructible<Sdl_window> _sdl_window { }; - Constructible<Sdl_screen> _sdl_screen { }; - - Capture::Connection _capture { _env }; + Constructible<Window> _window { }; + Constructible<Screen> _screen { }; Constructible<Capture::Connection::Screen> _captured_screen { }; - Signal_handler<Main> _timer_handler { - _env.ep(), *this, &Main::_handle_timer }; - int _mx = 0, _my = 0; - void _handle_sdl_event(Event_batch &, SDL_Event const &); - void _handle_sdl_events(); + unsigned _capture_woken_up = 0; - void _update_sdl_screen_from_capture() + struct Previous_frame { - Affected_rects const affected = _capture.capture_at(Capture::Point(0, 0)); + Ticks timestamp; + Ticks remaining; /* remaining ticks to next frame */ + unsigned idle; /* capture attempts without progress */ - _sdl_screen->with_surface([&] (Surface<Pixel> &surface) { + Ticks age() const { return { SDL_GetTicks() - timestamp.ms }; } + }; - _captured_screen->with_texture([&] (Texture<Pixel> const &texture) { + /* if constructed, the processing of a next frame is scheduled */ + Constructible<Previous_frame> _previous_frame { }; - affected.for_each_rect([&] (Capture::Rect const rect) { + void _schedule_next_frame() + { + _previous_frame.construct( + Previous_frame { .timestamp = { SDL_GetTicks() }, + .remaining = { _attr.period() }, + .idle = { } }); + } - surface.clip(rect); + void _handle_event(Event_batch &, SDL_Event const &); - Blit_painter::paint(surface, texture, Capture::Point(0, 0)); - }); - }); + bool _update_screen_from_capture() + { + bool progress = false; + _screen->with_surface([&] (Surface<Pixel> &surface) { + + Rect const bounding_box = _captured_screen->apply_to_surface(surface); + + progress = (bounding_box.area.count() > 0); + + if (progress) + _screen->flush(bounding_box); }); - - /* flush pixels in SDL window */ - _sdl_screen->flush(); + return progress; } - void _handle_timer() + void _resize(Area const size) { - _handle_sdl_events(); + _screen.construct(size, _window->renderer); - _update_sdl_screen_from_capture(); + using Attr = Capture::Connection::Screen::Attr; + _captured_screen.construct(_capture, _rm, Attr { + .px = size, + .mm = { } }); + + _update_screen_from_capture(); + _schedule_next_frame(); } - void _resize(Area size) - { - _sdl_screen.construct(size, _sdl_window->renderer()); - _captured_screen.construct(_capture, _env.rm(), size); - _update_sdl_screen_from_capture(); - } - - Main(Env &env) : _env(env) - { - Area size = Area(_config.xml().attribute_value("width", 1024U), - _config.xml().attribute_value("height", 768U)); - _sdl_window.construct(size); - _resize(size); - - _timer.sigh(_timer_handler); - _timer.trigger_periodic(100000000 / 5994); /* 59.94Hz */ - } + /* + * Construction executed by the main thread + */ + Sdl(Event::Connection &event, Capture::Connection &capture, Region_map &rm, + Attr const attr) + : + _event(event), _capture(capture), _rm(rm), _attr(attr) + { } }; -void Fb_sdl::Main::_handle_sdl_event(Event_batch &batch, SDL_Event const &event) +void Fb_sdl::Sdl::_thread() +{ + if (SDL_Init(SDL_INIT_VIDEO) < 0) { + error("SDL_Init failed (", Cstring(SDL_GetError()), ")"); + throw Init_failed(); + } + + SDL_ShowCursor(0); + + _window.construct(_attr.initial_size); + _resize(_attr.initial_size); + + /* mainloop */ + for (;;) { + + if (_previous_frame.constructed()) + SDL_WaitEventTimeout(nullptr, _previous_frame->remaining.ms); + else + SDL_WaitEvent(nullptr); + + unsigned const orig_capture_woken_up = _capture_woken_up; + + _event.with_batch([&] (Event_batch &batch) { + SDL_Event event { }; + while (SDL_PollEvent(&event)) + _handle_event(batch, event); }); + + Ticks const period = _attr.period(); + + bool const woken_up = (_capture_woken_up != orig_capture_woken_up); + bool const frame_elapsed = _previous_frame.constructed() + && _previous_frame->age().ms >= period.ms; + + if (woken_up || frame_elapsed) { + + bool const progress = _update_screen_from_capture(); + bool const idle = !progress && !woken_up; + + if (idle) { + if (_previous_frame.constructed()) { + _previous_frame->idle++; + if (_previous_frame->idle > _attr.idle) { + _previous_frame.destruct(); + _capture.capture_stopped(); + } + } + } else { + _schedule_next_frame(); + } + + } else { + /* + * Events occurred in-between two frames. + * Update timeout for next call of 'SDL_WaitEventTimeout'. + */ + if (_previous_frame.constructed()) + _previous_frame->remaining = { + min(period.ms, period.ms - _previous_frame->age().ms) }; + } + } +} + + +void Fb_sdl::Sdl::_handle_event(Event_batch &batch, SDL_Event const &event) { using namespace Input; - if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_RESIZED) { + if (event.type == SDL_WINDOWEVENT) { - int w = event.window.data1; - int h = event.window.data2; - if (w < 0 || h < 0) { - warning("attempt to resize to negative size"); - return; + if (event.window.event == SDL_WINDOWEVENT_RESIZED) { + + int const w = event.window.data1, + h = event.window.data2; + + if (w <= 0 || h <= 0) { + warning("attempt to resize to invalid size"); + return; + } + _resize({ unsigned(w), unsigned(h) }); } - _resize(Area((unsigned)w, (unsigned)h)); + _screen->flush_all(); + return; + } + + if (event.type == SDL_USEREVENT) { + if (event.user.code == USER_EVENT_CAPTURE_WAKEUP) + _capture_woken_up++; return; } @@ -294,7 +416,6 @@ void Fb_sdl::Main::_handle_sdl_event(Event_batch &batch, SDL_Event const &event) } } - /* determine event type */ switch (event.type) { case SDL_KEYUP: @@ -323,16 +444,39 @@ void Fb_sdl::Main::_handle_sdl_event(Event_batch &batch, SDL_Event const &event) } -void Fb_sdl::Main::_handle_sdl_events() +struct Fb_sdl::Main { - SDL_Event event { }; + Env &_env; - _event.with_batch([&] (Event_batch &batch) { + Attached_rom_dataspace _config { _env, "config" }; - while (SDL_PollEvent(&event)) - _handle_sdl_event(batch, event); - }); -} + Event::Connection _event { _env }; + Capture::Connection _capture { _env }; + + void _handle_capture_wakeup() + { + SDL_Event ev { }; + ev.user = SDL_UserEvent { .type = SDL_USEREVENT, + .timestamp = SDL_GetTicks(), + .windowID = { }, + .code = USER_EVENT_CAPTURE_WAKEUP, + .data1 = { }, + .data2 = { } }; + + if (SDL_PushEvent(&ev) == 0) + warning("SDL_PushEvent failed (", Cstring(SDL_GetError()), ")"); + } + + Signal_handler<Main> _capture_wakeup_handler { + _env.ep(), *this, &Main::_handle_capture_wakeup }; + + Sdl _sdl { _event, _capture, _env.rm(), Sdl::Attr::from_xml(_config.xml()) }; + + Main(Env &env) : _env(env) + { + _capture.wakeup_sigh(_capture_wakeup_handler); + } +}; void Component::construct(Genode::Env &env) { static Fb_sdl::Main inst(env); } diff --git a/repos/os/src/driver/framebuffer/virtio/component.h b/repos/os/src/driver/framebuffer/virtio/component.h index 1ffd81c03b..1294c7daf2 100644 --- a/repos/os/src/driver/framebuffer/virtio/component.h +++ b/repos/os/src/driver/framebuffer/virtio/component.h @@ -355,7 +355,10 @@ class Virtio_fb::Driver throw Display_init_failed(); } - _captured_screen.construct(_capture, _env.rm(), _display_area); + using Attr = Capture::Connection::Screen::Attr; + _captured_screen.construct(_capture, _env.rm(), Attr { + .px = _display_area, + .mm = { } }); } void _shutdown_display() diff --git a/repos/os/src/driver/gpu/intel/main.cc b/repos/os/src/driver/gpu/intel/main.cc index 7714511528..b7763a2861 100644 --- a/repos/os/src/driver/gpu/intel/main.cc +++ b/repos/os/src/driver/gpu/intel/main.cc @@ -2515,8 +2515,7 @@ struct Main : Irq_ack_handler, Gpu_reset_handler &Main::handle_irq }; Signal_handler<Main> _config_sigh { _env.ep(), *this, &Main::_handle_config_update }; - Platform::Resources _dev { _env, _rm, _irq_dispatcher, - _config_aperture_size() }; + Platform::Resources _dev { _env, _rm, _irq_dispatcher }; Signal_handler<Main> _system_sigh { _env.ep(), *this, &Main::_system_update }; String<16> _system_state { "" }; @@ -2573,16 +2572,6 @@ struct Main : Irq_ack_handler, Gpu_reset_handler }); } - Number_of_bytes _config_aperture_size() const - { - auto aperture_size = Number_of_bytes(64ull << 20); - - if (_config_rom.valid()) - aperture_size = _config_rom.xml().attribute_value("max_framebuffer_memory", aperture_size); - - return aperture_size; - } - void _handle_config_update() { _config_rom.update(); diff --git a/repos/os/src/driver/gpu/intel/platform_session.h b/repos/os/src/driver/gpu/intel/platform_session.h index 282fe3f1d3..f4bbf6245c 100644 --- a/repos/os/src/driver/gpu/intel/platform_session.h +++ b/repos/os/src/driver/gpu/intel/platform_session.h @@ -17,6 +17,7 @@ #include <region_map/client.h> #include <rm_session/connection.h> #include <platform_session/platform_session.h> +#include <os/dynamic_rom_session.h> #include <types.h> struct Irq_ack_handler @@ -171,7 +172,8 @@ class Platform::Device_component : public Rpc_object<Device_interface, }; -class Platform::Session_component : public Rpc_object<Session> +class Platform::Session_component : public Rpc_object<Session>, + private Dynamic_rom_session::Xml_producer { private: @@ -181,6 +183,8 @@ class Platform::Session_component : public Rpc_object<Session> Gpu_reset_handler & _reset_handler; Heap _heap { _env.ram(), _env.rm() }; Device_component _device_component; + Dynamic_rom_session _rom_session { _env.ep(), _env.ram(), + _env.rm(), *this }; bool _acquired { false }; /* @@ -213,6 +217,7 @@ class Platform::Session_component : public Rpc_object<Session> Dataspace_capability gmadr_ds_cap, Range gmadr_range) : + Dynamic_rom_session::Xml_producer("devices"), _env(env), _platform(platform), _hw_ready(hw_ready), @@ -282,10 +287,105 @@ class Platform::Session_component : public Rpc_object<Session> return ret; } - Rom_session_capability devices_rom() override { - return _platform.devices_rom(); } + Rom_session_capability devices_rom() override + { + _rom_session.update(); + + return _rom_session.cap(); + } bool handle_irq() { return _device_component.handle_irq(); } + + /******************************************* + ** Dynamic_rom_session::Xml_producer API ** + *******************************************/ + + void produce_xml(Xml_generator &xml) override + { + Rom_session_client rsc(_platform.devices_rom()); + Attached_dataspace rom(_env.rm(), rsc.dataspace()); + + if (!rom.size()) + return; + + Xml_node const rom_xml(rom.local_addr<char>()); + + copy_attributes(xml, rom_xml); + + rom_xml.for_each_sub_node("device", [&](auto const &dev) { + + bool intel_dev = false; + bool graphic_dev = false; + + dev.with_optional_sub_node("pci-config", [&] (Xml_node const &node) { + intel_dev = node.attribute_value("vendor_id", 0u) == 0x8086; + graphic_dev = node.attribute_value("class", 0u) == 0x30000; + }); + + if (!intel_dev) + return; + + if (!graphic_dev) { + copy_node(xml, dev); + return; + } + + xml.node("device", [&]() { + copy_attributes(xml, dev); + + dev.for_each_sub_node([&] (Xml_node const &node) { + if (!node.has_type("io_mem")) { + copy_node(xml, node); + return; + } + + auto const pci_bar = node.attribute_value("pci_bar", ~0U); + + xml.node("io_mem", [&]() { + node.for_each_attribute([&](auto const &attr){ + String<16> value { }; + attr.value(value); + + if (pci_bar == 2 && attr.has_type("size")) { + Range r = { }; + _device_component.io_mem(1, r); + + value = String<16>(Hex(r.size)); + } + + xml.attribute(attr.name().string(), + value.string()); + }); + }); + }); + }); + }); + } + + void copy_attributes(Xml_generator &xml, Xml_node const &from) + { + using Value = String<64>; + from.for_each_attribute([&] (Xml_attribute const &attr) { + Value value { }; + attr.value(value); + xml.attribute(attr.name().string(), value); + }); + } + + struct Xml_max_depth { unsigned value; }; + + void copy_node(Xml_generator &xml, Xml_node const &from, + Xml_max_depth max_depth = { 5 }) + { + if (!max_depth.value) + return; + + xml.node(from.type().string(), [&] { + copy_attributes(xml, from); + from.for_each_sub_node([&] (Xml_node const &sub_node) { + copy_node(xml, sub_node, { max_depth.value - 1 }); }); + }); + } }; @@ -366,51 +466,48 @@ class Platform::Resources : Noncopyable, public Hw_ready_state }); } - Number_of_bytes _sanitized_aperture_size(Number_of_bytes memory) const + Number_of_bytes _sanitized_aperture_size() const { /* - * Ranges of global GTT (ggtt) are handed in page granularity (4k) - * to the platform client (intel display driver). - * 512 page table entries a 4k fit into one page, which adds up to - * 2M virtual address space. + * Always try to reserve 32 MiB for the multiplexer itself but + * we also make sure that 32 MiB are available for the display + * driver (or at least all of the available aperture). We + * prioritize a working display over having the GPU service + * available because investigating the later is futil without + * the former. */ - auto constexpr shift_2mb = 21ull; - auto constexpr MIN_MEMORY_FOR_MULTIPLEXER = 4ull << shift_2mb; + auto constexpr GPU_SERVICE_APERTURE = (32ull << 20); + auto constexpr DISPLAY_MIN_APERTURE = (32ull << 20); - /* align requests to 2M and enforce 2M as minimum */ - memory = memory & _align_mask(shift_2mb); - if (memory < (1ull << shift_2mb)) - memory = 1ull << shift_2mb; + if (_gmadr->size() <= DISPLAY_MIN_APERTURE) + return _gmadr->size(); - if (_gmadr->size() >= MIN_MEMORY_FOR_MULTIPLEXER) { - if (memory > _gmadr->size() - MIN_MEMORY_FOR_MULTIPLEXER) - memory = _gmadr->size() - MIN_MEMORY_FOR_MULTIPLEXER; - } else { - /* paranoia case, should never trigger */ - memory = _gmadr->size() / 2; - error("aperture smaller than ", MIN_MEMORY_FOR_MULTIPLEXER, - " will not work properly"); - } + /* guard against non 2^x aperture size */ + if ((_gmadr->size() - GPU_SERVICE_APERTURE) < DISPLAY_MIN_APERTURE) + return DISPLAY_MIN_APERTURE; - log("Maximum aperture size ", Number_of_bytes(_gmadr->size())); - log(" - available framebuffer memory for display driver: ", memory); - - return memory; + return _gmadr->size() - GPU_SERVICE_APERTURE; } public: - Resources(Env &env, Rm_connection &rm, Signal_context_capability irq, - Number_of_bytes const &aperture) + Resources(Env &env, Rm_connection &rm, Signal_context_capability irq) : _env(env), _irq_cap(irq), - _aperture_reserved(_sanitized_aperture_size(aperture)), + _aperture_reserved(_sanitized_aperture_size()), _rm_gttmm(rm.create(_mmio->size())), _rm_gmadr(rm.create(aperture_reserved())), _range_gttmm(1ul << 30, _mmio->size()), _range_gmadr(1ul << 29, aperture_reserved()) { + log("Aperture max: ", Number_of_bytes(_gmadr->size()), + " display: ", Number_of_bytes(_aperture_reserved)); + + /* reserved space is used to calculate vGPU available */ + if (_gmadr->size() == _aperture_reserved) + warning("GPU service not usable due to insufficient aperture space"); + _irq->sigh(_irq_cap); /* GTT starts at half of the mmio memory */ diff --git a/repos/os/src/driver/platform/common.h b/repos/os/src/driver/platform/common.h index 411cce8b90..f640937d44 100644 --- a/repos/os/src/driver/platform/common.h +++ b/repos/os/src/driver/platform/common.h @@ -20,6 +20,7 @@ #include <root.h> #include <device_owner.h> #include <io_mmu.h> +#include <irq_controller.h> #include <device_pd.h> namespace Driver { class Common; }; @@ -43,6 +44,9 @@ class Driver::Common : Device_reporter, Io_mmu_devices _io_mmu_devices { }; Registry<Io_mmu_factory> _io_mmu_factories { }; + Registry<Irq_controller> _irq_controller_registry { }; + Registry<Irq_controller_factory> _irq_controller_factories { }; + Driver::Root _root; Constructible<Expanding_reporter> _cfg_reporter { }; @@ -68,9 +72,16 @@ class Driver::Common : Device_reporter, Io_mmu_devices & io_mmu_devices() { return _io_mmu_devices; } + Xml_node platform_info() { + return _platform_info.xml(); } + + Registry<Irq_controller_factory> & irq_controller_factories() { + return _irq_controller_factories; } + void announce_service(); void handle_config(Xml_node config); void acquire_io_mmu_devices(); + void acquire_irq_controller(); void report_resume(); @@ -158,11 +169,30 @@ void Driver::Common::acquire_io_mmu_devices() } +void Driver::Common::acquire_irq_controller() +{ + _irq_controller_factories.for_each([&] (Irq_controller_factory & factory) { + + _devices.for_each([&] (Device & dev) { + if (dev.owner().valid()) + return; + + if (factory.matches(dev)) { + dev.acquire(*this); + factory.create(_heap, _irq_controller_registry, dev); + } + }); + + }); +} + + void Driver::Common::_handle_devices() { _devices_rom.update(); _devices.update(_devices_rom.xml(), _root); acquire_io_mmu_devices(); + acquire_irq_controller(); update_report(); _root.update_policy(); } @@ -203,6 +233,10 @@ void Driver::Common::disable_device(Device const & device) if (io_mmu.name() == device.name()) destroy(_heap, &io_mmu); }); + _irq_controller_registry.for_each([&] (Irq_controller & irq_controller) { + if (irq_controller.name() == device.name()) + destroy(_heap, &irq_controller); + }); } @@ -240,7 +274,8 @@ Driver::Common::Common(Genode::Env & env, _env(env), _rom_name(config_rom.xml().attribute_value("devices_rom", String<64>("devices"))), - _root(_env, _sliced_heap, config_rom, _devices, _io_mmu_devices, _iommu()) + _root(_env, _sliced_heap, config_rom, _devices, _io_mmu_devices, + _irq_controller_registry, _iommu()) { _devices_rom.sigh(_dev_handler); _handle_devices(); diff --git a/repos/os/src/driver/platform/device.h b/repos/os/src/driver/platform/device.h index 873198e644..b76330e77f 100644 --- a/repos/os/src/driver/platform/device.h +++ b/repos/os/src/driver/platform/device.h @@ -379,6 +379,12 @@ class Driver::Device : private List_model<Device>::Element fn(idx++, ipr.range, ipr.bar); }); } + template <typename FN> void for_each_property(FN const & fn) const + { + _property_list.for_each([&] (Property const & p) { + fn(p.name, p.value); }); + } + template <typename FN> void for_pci_config(FN const & fn) const { /* diff --git a/repos/os/src/driver/platform/device_component.cc b/repos/os/src/driver/platform/device_component.cc index 5f7bccb6e3..ac598eebf8 100644 --- a/repos/os/src/driver/platform/device_component.cc +++ b/repos/os/src/driver/platform/device_component.cc @@ -26,17 +26,43 @@ void Driver::Device_component::_release_resources() destroy(_session.heap(), &iomem); }); _irq_registry.for_each([&] (Irq & irq) { - destroy(_session.heap(), &irq); }); + + /* unmap IRQ from corresponding remapping table */ + if (irq.type == Irq_session::TYPE_LEGACY) { + _session.irq_controller_registry().for_each([&] (Irq_controller & controller) { + if (!controller.handles_irq(irq.number)) return; + + _session.with_io_mmu(controller.iommu(), [&] (Driver::Io_mmu & io_mmu_dev) { + io_mmu_dev.unmap_irq(controller.bdf(), irq.remapped_nbr); + }); + }); + } else { + _io_mmu_registry.for_each([&] (Io_mmu & io_mmu) { + if (_pci_config.constructed()) + _session.with_io_mmu(io_mmu.name, [&] (Driver::Io_mmu & io_mmu_dev) { + io_mmu_dev.unmap_irq(_pci_config->bdf, irq.remapped_nbr); }); + }); + } + + destroy(_session.heap(), &irq); + }); _io_port_range_registry.for_each([&] (Io_port_range & iop) { destroy(_session.heap(), &iop); }); - /* remove reserved memory ranges from IOMMU domains */ - _session.domain_registry().for_each_domain( - [&] (Driver::Io_mmu::Domain & domain) { - _reserved_mem_registry.for_each([&] (Io_mem & iomem) { - domain.remove_range(iomem.range); - }); + _io_mmu_registry.for_each([&] (Io_mmu & io_mmu) { + _session.domain_registry().with_domain(io_mmu.name, + [&] (Driver::Io_mmu::Domain & domain) { + + /* remove reserved memory ranges from IOMMU domains */ + _reserved_mem_registry.for_each([&] (Io_mem & iomem) { + domain.remove_range(iomem.range); }); + + }, + [&] () {} /* no match */ + ); + + destroy(_session.heap(), &io_mmu); }); _reserved_mem_registry.for_each([&] (Io_mem & iomem) { @@ -93,38 +119,100 @@ Device_component::io_mem(unsigned idx, Range &range) Genode::Irq_session_capability Device_component::irq(unsigned idx) { + using Irq_config = Irq_controller::Irq_config; + Irq_session_capability cap; - _irq_registry.for_each([&] (Irq & irq) + auto remapped_irq = [&] (Device::Name const & iommu_name, + Pci::Bdf const & bdf, + Irq & irq, + Irq_session::Info const & info, + Irq_config const & config) { - if (irq.idx != idx) - return; + using Irq_info = Driver::Io_mmu::Irq_info; + Irq_info remapped_irq { Irq_info::DIRECT, info, irq.number }; - if (!irq.shared && !irq.irq.constructed()) { - addr_t pci_cfg_addr = 0; - if (irq.type != Irq_session::TYPE_LEGACY) { - if (_pci_config.constructed()) pci_cfg_addr = _pci_config->addr; - else - error("MSI(-x) detected for device without pci-config!"); + auto map_fn = [&] (Device::Name const & name) { + _session.with_io_mmu(name, [&] (Driver::Io_mmu & io_mmu) { + remapped_irq = io_mmu.map_irq(bdf, remapped_irq, config); + }); + }; - irq.irq.construct(_env, irq.number, pci_cfg_addr, irq.type); - } else - irq.irq.construct(_env, irq.number, irq.mode, irq.polarity); - - Irq_session::Info info = irq.irq->info(); - if (pci_cfg_addr && info.type == Irq_session::Info::MSI) - pci_msi_enable(_env, *this, pci_cfg_addr, info, irq.type); - } - - if (irq.shared && !irq.sirq.constructed()) - _device_model.with_shared_irq(irq.number, - [&] (Shared_interrupt & sirq) { - irq.sirq.construct(_env.ep().rpc_ep(), sirq, - irq.mode, irq.polarity); + /* for legacy IRQs, take IOMMU referenced by IOAPIC */ + if (iommu_name != "") + map_fn(iommu_name); + else + _io_mmu_registry.for_each([&] (Io_mmu const & io_mmu) { + map_fn(io_mmu.name); }); - cap = irq.shared ? irq.sirq->cap() : irq.irq->cap(); - }); + /* store remapped number at irq object */ + irq.remapped_nbr = remapped_irq.irq_number; + + return remapped_irq; + }; + + try { + _irq_registry.for_each([&] (Irq & irq) + { + if (irq.idx != idx) + return; + + if (!irq.shared && !irq.irq.constructed()) { + addr_t pci_cfg_addr = 0; + Pci::Bdf bdf { 0, 0, 0 }; + if (irq.type != Irq_session::TYPE_LEGACY) { + if (_pci_config.constructed()) { + pci_cfg_addr = _pci_config->addr; + bdf = _pci_config->bdf; + } else + error("MSI(-x) detected for device without pci-config!"); + + irq.irq.construct(_env, irq.number, pci_cfg_addr, irq.type, + Pci::Bdf::rid(_pci_config->bdf)); + } else + irq.irq.construct(_env, irq.number, irq.mode, irq.polarity); + + /** + * Core/Kernel is and remains in control of the IRQ controller. When + * IRQ remapping is enabled, however, we need to modify the upper 32bit + * of the corresponding redirection table entry. This is save for + * base-hw as it never touches the upper 32bit after the initial setup. + */ + Irq_session::Info info = irq.irq->info(); + if (pci_cfg_addr && info.type == Irq_session::Info::MSI) + pci_msi_enable(_env, *this, pci_cfg_addr, + remapped_irq("", bdf, irq, info, Irq_config::Invalid()).session_info, + irq.type); + else + _session.irq_controller_registry().for_each([&] (Irq_controller & controller) { + if (!controller.handles_irq(irq.number)) return; + + remapped_irq(controller.iommu(), controller.bdf(), irq, info, + controller.irq_config(irq.number)); + controller.remap_irq(irq.number, irq.remapped_nbr); + }); + } + + if (irq.shared && !irq.sirq.constructed()) + _device_model.with_shared_irq(irq.number, + [&] (Shared_interrupt & sirq) { + irq.sirq.construct(_env.ep().rpc_ep(), sirq, + irq.mode, irq.polarity); + + _session.irq_controller_registry().for_each([&] (Irq_controller & controller) { + if (!controller.handles_irq(irq.number)) return; + + remapped_irq(controller.iommu(), controller.bdf(), irq, + { Irq_session::Info::INVALID, 0, 0 }, + controller.irq_config(irq.number)); + controller.remap_irq(irq.number, irq.remapped_nbr); + }); + }); + + cap = irq.shared ? irq.sirq->cap() : irq.irq->cap(); + }); + } catch (Service_denied) { error("irq could not be setup ", _device); } return cap; } @@ -218,7 +306,8 @@ Device_component::Device_component(Registry<Device_component> & registry, _ram_quota += Io_mem_session::RAM_QUOTA; session.cap_quota_guard().withdraw(Cap_quota{Io_mem_session::CAP_QUOTA}); _cap_quota += Io_mem_session::CAP_QUOTA; - _pci_config.construct(cfg.addr); + Pci::Bdf bdf { cfg.bus_num, cfg.dev_num, cfg.func_num }; + _pci_config.construct(cfg.addr, bdf); }); device.for_each_reserved_memory([&] (unsigned idx, Range range) @@ -249,7 +338,10 @@ Device_component::Device_component(Registry<Device_component> & registry, [&] (Driver::Device::Io_mmu const &io_mmu) { session.domain_registry().with_domain(io_mmu.name, add_range_fn, - default_domain_fn); }, + [&] () { }); + /* save IOMMU names for this device */ + new (session.heap()) Io_mmu(_io_mmu_registry, io_mmu.name); + }, /* empty list fn */ default_domain_fn diff --git a/repos/os/src/driver/platform/device_component.h b/repos/os/src/driver/platform/device_component.h index 5c2f5894ba..c18a619f67 100644 --- a/repos/os/src/driver/platform/device_component.h +++ b/repos/os/src/driver/platform/device_component.h @@ -40,6 +40,7 @@ class Driver::Device_component : public Rpc_object<Platform::Device_interface, { unsigned idx; unsigned number; + unsigned remapped_nbr; Irq_session::Type type; Irq_session::Polarity polarity; Irq_session::Trigger mode; @@ -56,7 +57,7 @@ class Driver::Device_component : public Rpc_object<Platform::Device_interface, bool shared) : Registry<Irq>::Element(registry, *this), - idx(idx), number(number), type(type), + idx(idx), number(number), remapped_nbr(number), type(type), polarity(polarity), mode(mode), shared(shared) {} }; @@ -96,11 +97,22 @@ class Driver::Device_component : public Rpc_object<Platform::Device_interface, idx(idx), range(range) {} }; + struct Io_mmu : Registry<Io_mmu>::Element + { + Device::Name name; + + Io_mmu(Registry<Io_mmu> & registry, Device::Name const & name) + : + Registry<Io_mmu>::Element(registry, *this), + name(name) {} + }; + struct Pci_config { - addr_t addr; + addr_t addr; + Pci::Bdf bdf; - Pci_config(addr_t addr) : addr(addr) {} + Pci_config(addr_t addr, Pci::Bdf bdf) : addr(addr), bdf(bdf) {} }; Device_component(Registry<Device_component> & registry, @@ -136,6 +148,7 @@ class Driver::Device_component : public Rpc_object<Platform::Device_interface, Registry<Io_mem> _io_mem_registry {}; Registry<Io_port_range> _io_port_range_registry {}; Registry<Io_mem> _reserved_mem_registry {}; + Registry<Io_mmu> _io_mmu_registry {}; Constructible<Pci_config> _pci_config {}; void _release_resources(); diff --git a/repos/os/src/driver/platform/io_mmu.h b/repos/os/src/driver/platform/io_mmu.h index 33201e6584..ad2158c0df 100644 --- a/repos/os/src/driver/platform/io_mmu.h +++ b/repos/os/src/driver/platform/io_mmu.h @@ -22,6 +22,7 @@ /* local includes */ #include <device.h> #include <dma_allocator.h> +#include <irq_controller.h> namespace Driver { @@ -38,7 +39,14 @@ class Driver::Io_mmu : private Io_mmu_devices::Element { public: - using Range = Platform::Device_interface::Range; + using Range = Platform::Device_interface::Range; + using Irq_config = Irq_controller::Irq_config; + + struct Irq_info { + enum { DIRECT, REMAPPED } remapped; + Irq_session::Info session_info; + unsigned irq_number; + }; class Domain : private Registry<Domain>::Element { @@ -147,6 +155,11 @@ class Driver::Io_mmu : private Io_mmu_devices::Element /* interface for completing default mappings (enabled IOMMU) */ virtual void default_mappings_complete() { } + /* interface for mapping/unmapping interrupts */ + virtual void unmap_irq(Pci::Bdf const &, unsigned) { } + virtual Irq_info map_irq(Pci::Bdf const &, Irq_info const & info, Irq_config const &) { + return info; } + Device::Name const & name() const { return _name; } bool domain_owner(Domain const & domain) const { diff --git a/repos/os/src/driver/platform/irq_controller.h b/repos/os/src/driver/platform/irq_controller.h new file mode 100644 index 0000000000..7e405ab43d --- /dev/null +++ b/repos/os/src/driver/platform/irq_controller.h @@ -0,0 +1,102 @@ +/* + * \brief Platform driver - IRQ controller interface + * \author Johannes Schlatow + * \date 2024-03-20 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _SRC__DRIVERS__PLATFORM__IRQ_CONTROLLER_H_ +#define _SRC__DRIVERS__PLATFORM__IRQ_CONTROLLER_H_ + +/* Genode includes */ +#include <base/registry.h> +#include <pci/types.h> + +/* local includes */ +#include <device.h> + +namespace Driver +{ + using namespace Genode; + + class Irq_controller; + class Irq_controller_factory; +} + + +class Driver::Irq_controller : private Registry<Irq_controller>::Element +{ + private: + + Device::Name _name; + Device::Name _iommu_name; + Pci::Bdf _bdf; + + public: + + struct Irq_config + { + enum Mode { INVALID, + PHYSICAL, + LOGICAL } mode; + Irq_session::Trigger trigger; + unsigned vector; + unsigned destination; + + static Irq_config Invalid() { + return { Mode::INVALID, Irq_session::TRIGGER_UNCHANGED, 0, 0 }; } + }; + + Device::Name const & name() const { return _name; } + Device::Name const & iommu() const { return _iommu_name; } + Pci::Bdf const & bdf() const { return _bdf;} + + virtual void remap_irq(unsigned from, unsigned to) = 0; + virtual bool handles_irq(unsigned) = 0; + + virtual Irq_config irq_config(unsigned) = 0; + + Irq_controller(Registry<Irq_controller> & registry, + Device::Name const & name, + Device::Name const & iommu_name, + Pci::Bdf const & bdf) + : Registry<Irq_controller>::Element(registry, *this), + _name(name), _iommu_name(iommu_name), _bdf(bdf) + { } + + virtual ~Irq_controller() { } +}; + + +class Driver::Irq_controller_factory : private Genode::Registry<Irq_controller_factory>::Element +{ + protected: + + Device::Type _type; + + public: + + Irq_controller_factory(Registry<Irq_controller_factory> & registry, + Device::Type const & type) + : Registry<Irq_controller_factory>::Element(registry, *this), + _type(type) + { } + + virtual ~Irq_controller_factory() { } + + bool matches(Device const & dev) { + return dev.type() == _type; } + + virtual void create(Allocator &, + Registry<Irq_controller> &, + Device const &) = 0; +}; + + +#endif /* _SRC__DRIVERS__PLATFORM__IRQ_CONTROLLER_H_ */ diff --git a/repos/os/src/driver/platform/root.cc b/repos/os/src/driver/platform/root.cc index 092566f4d7..3edefd4a31 100644 --- a/repos/os/src/driver/platform/root.cc +++ b/repos/os/src/driver/platform/root.cc @@ -43,6 +43,7 @@ Driver::Session_component * Driver::Root::_create_session(const char *args) sc = new (md_alloc()) Session_component(_env, _config, _devices, _sessions, _io_mmu_devices, + _irq_controller_registry, label, session_resources_from_args(args), session_diag_from_args(args), @@ -111,8 +112,11 @@ Driver::Root::Root(Env & env, Attached_rom_dataspace const & config, Device_model & devices, Io_mmu_devices & io_mmu_devices, + Registry<Irq_controller> & irq_controller_registry, bool const kernel_iommu) : Root_component<Session_component>(env.ep(), sliced_heap), _env(env), _config(config), _devices(devices), - _io_mmu_devices(io_mmu_devices), _kernel_iommu(kernel_iommu) + _io_mmu_devices(io_mmu_devices), + _irq_controller_registry(irq_controller_registry), + _kernel_iommu(kernel_iommu) { } diff --git a/repos/os/src/driver/platform/root.h b/repos/os/src/driver/platform/root.h index d9f2bb6c3d..17f1855e92 100644 --- a/repos/os/src/driver/platform/root.h +++ b/repos/os/src/driver/platform/root.h @@ -34,6 +34,7 @@ class Driver::Root : public Root_component<Session_component>, Attached_rom_dataspace const & config, Device_model & devices, Io_mmu_devices & io_mmu_devices, + Registry<Irq_controller> & irq_controller_registry, bool const kernel_iommu); void update_policy(); @@ -69,6 +70,7 @@ class Driver::Root : public Root_component<Session_component>, Attached_rom_dataspace const & _config; Device_model & _devices; Io_mmu_devices & _io_mmu_devices; + Registry<Irq_controller> & _irq_controller_registry; bool _io_mmu_present { false }; bool const _kernel_iommu; Registry<Session_component> _sessions {}; diff --git a/repos/os/src/driver/platform/session_component.cc b/repos/os/src/driver/platform/session_component.cc index 2de8cb521a..21d45eeb09 100644 --- a/repos/os/src/driver/platform/session_component.cc +++ b/repos/os/src/driver/platform/session_component.cc @@ -218,6 +218,12 @@ Driver::Io_mmu_domain_registry & Session_component::domain_registry() } +Genode::Registry<Driver::Irq_controller> & Session_component::irq_controller_registry() +{ + return _irq_controller_registry; +} + + void Session_component::update_devices_rom() { _rom_session.trigger_update(); @@ -418,6 +424,7 @@ Session_component::Session_component(Env & env, Device_model & devices, Session_registry & registry, Io_mmu_devices & io_mmu_devices, + Registry<Irq_controller> & irq_controller_registry, Label const & label, Resources const & resources, Diag const & diag, @@ -430,7 +437,9 @@ Session_component::Session_component(Env & env, Session_registry::Element(registry, *this), Dynamic_rom_session::Xml_producer("devices"), _env(env), _config(config), _devices(devices), - _io_mmu_devices(io_mmu_devices), _info(info), _version(version), + _io_mmu_devices(io_mmu_devices), + _irq_controller_registry(irq_controller_registry), + _info(info), _version(version), _dma_allocator(_md_alloc, dma_remapping) { /* diff --git a/repos/os/src/driver/platform/session_component.h b/repos/os/src/driver/platform/session_component.h index 8d1d96b245..79287b5cb2 100644 --- a/repos/os/src/driver/platform/session_component.h +++ b/repos/os/src/driver/platform/session_component.h @@ -28,6 +28,7 @@ #include <device_owner.h> #include <io_mmu.h> #include <io_mmu_domain_registry.h> +#include <irq_controller.h> namespace Driver { class Session_component; @@ -52,6 +53,7 @@ class Driver::Session_component Device_model & devices, Session_registry & registry, Io_mmu_devices & io_mmu_devices, + Registry<Irq_controller> & irq_controller_registry, Label const & label, Resources const & resources, Diag const & diag, @@ -62,8 +64,18 @@ class Driver::Session_component ~Session_component(); - Heap & heap(); - Io_mmu_domain_registry & domain_registry(); + Heap & heap(); + Io_mmu_domain_registry & domain_registry(); + Registry<Irq_controller> & irq_controller_registry(); + + template <typename FN> + void with_io_mmu(Device::Name const & name, FN && fn) + { + _io_mmu_devices.for_each([&] (Io_mmu & io_mmu) { + if (io_mmu.name() == name) + fn(io_mmu); + }); + } void enable_dma_remapping() { _dma_allocator.enable_remapping(); } @@ -107,6 +119,7 @@ class Driver::Session_component Device_model & _devices; Io_mmu_devices & _io_mmu_devices; + Registry<Irq_controller> & _irq_controller_registry; Device::Owner _owner_id { *this }; Constrained_ram_allocator _env_ram { _env.pd(), _ram_quota_guard(), diff --git a/repos/os/src/lib/genode_c_api/usb.cc b/repos/os/src/lib/genode_c_api/usb.cc index d09963995c..3645f88a9a 100644 --- a/repos/os/src/lib/genode_c_api/usb.cc +++ b/repos/os/src/lib/genode_c_api/usb.cc @@ -112,6 +112,15 @@ struct Reg_list fn(e->_object); } } + + void apply(auto const &condition, auto const & fn) + { + for (Element *e = _elements.first(); e; e = e->next()) + if (condition(e->_object)) { + fn(e->_object); + return; + } + } }; @@ -907,8 +916,11 @@ Device_component::_handle_request(Constructible<Packet_descriptor> &cpd, granted = true; break; case P::SET_INTERFACE: - _interfaces.for_each([&] (Interface_component & ic) { - if (ic._iface_idx == cpd->index) granted = true; }); + _interfaces.apply( + [&] (Interface_component & ic) { + return ic._iface_idx == cpd->index; + }, + [&] (Interface_component &) { granted = true; }); if (granted) break; [[fallthrough]]; default: granted = _controls; @@ -947,8 +959,10 @@ void Device_component::release_interface(Interface_capability cap) if (!cap.valid()) return; - _interfaces.for_each([&] (Interface_component & ic) { - if (cap.local_name() == ic.cap().local_name()) + _interfaces.apply( + [&] (Interface_component & ic) { + return cap.local_name() == ic.cap().local_name(); }, + [&] (Interface_component & ic) { destroy(_heap, &ic); }); } @@ -958,8 +972,10 @@ bool Device_component::request(genode_usb_req_callback_t const callback, { bool ret = false; - _interfaces.for_each([&] (Interface_component & ic) { - if (ic.request(callback, opaque_data)) ret = true; }); + _interfaces.apply( + [&] (Interface_component & ic) { + return ic.request(callback, opaque_data); }, + [&] (Interface_component &) { ret = true; }); return ret ? ret : Base::request(callback, opaque_data); } @@ -1003,10 +1019,11 @@ Device_component::handle_response(genode_usb_request_handle_t handle, [&] (Packet_error) {}); if (!ret) - _interfaces.for_each([&] (Interface_component & ic) { - if (ret) return; - if (ic.handle_response(handle, value, actual_sizes)) ret = true; - }); + _interfaces.apply( + [&] (Interface_component & ic) { + return ic.handle_response(handle, value, actual_sizes); }, + [&] (Interface_component &) { + ret = true; }); return ret; } @@ -1143,12 +1160,13 @@ void Session_component::_release(Device_component &dc) genode_usb_device::Label name = dc._device_label; destroy(_heap, &dc); - _devices.for_each([&] (genode_usb_device & device) { - if (device.label() != name) - return; - _sessions.for_each([&] (Session_component &sc) { - if (sc._matches(device)) sc.update_devices_rom(); }); - _root.report(); + _devices.apply( + [&] (genode_usb_device & device) { + return device.label() == name; }, + [&] (genode_usb_device & device) { + _sessions.for_each([&] (Session_component &sc) { + if (sc._matches(device)) sc.update_devices_rom(); }); + _root.report(); }); } @@ -1157,22 +1175,24 @@ void Session_component::set_interface(genode_usb_device::Label label, uint16_t num, uint16_t alt) { bool changed = false; - _devices.for_each([&] (genode_usb_device & d) { - if (d.label() != label) - return; - d.configs.for_each([&] (genode_usb_configuration & c) { - if (!c.active) - return; - c.interfaces.for_each([&] (genode_usb_interface & i) { - if (i.desc.number != num) - return; - - if (i.active != (i.desc.alt_settings == alt)) { - i.active = (i.desc.alt_settings == alt); - changed = true; - } + _devices.apply( + [&] (genode_usb_device & d) { + return d.label() == label; }, + [&] (genode_usb_device & d) { + d.configs.apply( + [&] (genode_usb_configuration & c) { + return c.active; }, + [&] (genode_usb_configuration & c) { + c.interfaces.apply( + [&] (genode_usb_interface & i) { + return i.desc.number == num; }, + [&] (genode_usb_interface & i) { + if (i.active != (i.desc.alt_settings == alt)) { + i.active = (i.desc.alt_settings == alt); + changed = true; + } + }); }); - }); }); if (changed) { @@ -1186,15 +1206,17 @@ void Session_component::set_configuration(genode_usb_device::Label label, uint16_t num) { bool changed = false; - _devices.for_each([&] (genode_usb_device & d) { - if (d.label() != label) - return; - d.configs.for_each([&] (genode_usb_configuration & c) { - if (c.active != (c.desc.config_value == num)) { - c.active = (c.desc.config_value == num); - changed = true; - } - }); + _devices.apply( + [&] (genode_usb_device & d) { + return d.label() == label; }, + [&] (genode_usb_device & d) { + d.configs.apply( + [&] (genode_usb_configuration & c) { + return c.active != (c.desc.config_value == num); }, + [&] (genode_usb_configuration & c) { + c.active = (c.desc.config_value == num); + changed = true; + }); }); if (changed) { @@ -1211,18 +1233,19 @@ bool Session_component::matches(genode_usb_device::Label label, uint8_t iface) * all interfaces are allowed, otherwise check for the iface number */ bool ret = false; - _devices.for_each([&] (genode_usb_device const & d) { - if (d.label() != label) - return; - _device_policy(d, [&] (Xml_node dev_node) { - if (!dev_node.has_sub_node("interface")) - ret = true; - else - dev_node.for_each_sub_node("interface", [&] (Xml_node & node) { - if (node.attribute_value<uint8_t>("number", 255) == iface) - ret = true; - }); - }); + _devices.apply( + [&] (genode_usb_device const & d) { + return d.label() == label; }, + [&] (genode_usb_device const & d) { + _device_policy(d, [&] (Xml_node dev_node) { + if (!dev_node.has_sub_node("interface")) + ret = true; + else + dev_node.for_each_sub_node("interface", [&] (Xml_node & node) { + if (node.attribute_value<uint8_t>("number", 255) == iface) + ret = true; + }); + }); }); return ret; } @@ -1232,17 +1255,21 @@ template <typename FN> void Session_component::for_each_ep(genode_usb_device::Label label, uint8_t iface_idx, FN const & fn) { - _devices.for_each([&] (genode_usb_device const & d) { - if (d.label() != label) - return; - d.configs.for_each([&] (genode_usb_configuration const & cfg) { - if (!cfg.active) - return; - cfg.interfaces.for_each([&] (genode_usb_interface const & iface) { - if (iface.desc.number == iface_idx) - iface.endpoints.for_each(fn); + _devices.apply( + [&] (genode_usb_device const & d) { + return d.label() == label; }, + [&] (genode_usb_device & d) { + d.configs.apply( + [&] (genode_usb_configuration const & cfg) { + return cfg.active; }, + [&] (genode_usb_configuration & cfg) { + cfg.interfaces.apply( + [&] (genode_usb_interface const & iface) { + return iface.desc.number == iface_idx; }, + [&] (genode_usb_interface const & iface) { + iface.endpoints.for_each(fn); + }); }); - }); }); } @@ -1255,11 +1282,12 @@ void Session_component::announce_device(genode_usb_device const & device) void Session_component::discontinue_device(genode_usb_device const & device) { - _device_sessions.for_each([&] (Device_component & dc) { - if (dc._device_label != device.label()) - return; - dc.disconnect(); - update_devices_rom(); + _device_sessions.apply( + [&] (Device_component & dc) { + return dc._device_label == device.label(); }, + [&] (Device_component & dc) { + dc.disconnect(); + update_devices_rom(); }); } @@ -1267,13 +1295,14 @@ void Session_component::discontinue_device(genode_usb_device const & device) void Session_component::update_policy() { _device_sessions.for_each([&] (Device_component & dc) { - _devices.for_each([&] (genode_usb_device const & device) { - if (device.label() != dc._device_label) - return; - if (!_matches(device)) { - dc.disconnect(); - _release_fn(device.bus, device.dev); - } + _devices.apply( + [&] (genode_usb_device const & device) { + return device.label() == dc._device_label; }, + [&] (genode_usb_device const & device) { + if (!_matches(device)) { + dc.disconnect(); + _release_fn(device.bus, device.dev); + } }); }); update_devices_rom(); @@ -1298,8 +1327,11 @@ bool Session_component::acquired(genode_usb_device const &dev) return false; bool ret = false; - _device_sessions.for_each([&] (Device_component & dc) { - if (dc._device_label == dev.label()) ret = dc.connected(); }); + _device_sessions.apply( + [&] (Device_component & dc) { + return dc._device_label == dev.label(); }, + [&] (Device_component & dc) { + ret = dc.connected(); }); return ret; } @@ -1309,10 +1341,11 @@ bool Session_component::request(genode_usb_device const &dev, void *opaque_data) { bool ret = false; - _device_sessions.for_each([&] (Device_component & dc) { - if (dc._device_label == dev.label()) - if (dc.request(callback, opaque_data)) ret = true; - }); + _device_sessions.apply( + [&] (Device_component & dc) { + return dc._device_label == dev.label(); }, + [&] (Device_component & dc) { + if (dc.request(callback, opaque_data)) ret = true; }); return ret; } @@ -1323,8 +1356,10 @@ Session_component::handle_response(genode_usb_request_handle_t handle, uint32_t *actual_sizes) { bool handled = false; - _device_sessions.for_each([&] (Device_component & dc) { - if (!handled) handled = dc.handle_response(handle, v, actual_sizes); }); + _device_sessions.apply( + [&] (Device_component & dc) { + return dc.handle_response(handle, v, actual_sizes); }, + [&] (Device_component &) { handled = true; }); return handled; } @@ -1341,23 +1376,27 @@ Device_capability Session_component::acquire_device(Device_name const &name) Device_capability cap; bool found = false; - _devices.for_each([&] (genode_usb_device & device) { - if (device.label() != name || !_matches(device)) - return; + _devices.apply( + [&] (genode_usb_device & device) { + return device.label() == name && _matches(device); }, - found = true; - _sessions.for_each([&] (Session_component &sc) { - if (sc.acquired(device)) found = false; }); + [&] (genode_usb_device & device) { + found = true; + _sessions.apply( + [&] (Session_component &sc) { + return sc.acquired(device); }, + [&] (Session_component &) { + found = false; }); - if (!found) { - warning("USB device ", name, - "already acquired by another session"); - } + if (!found) { + warning("USB device ", name, + "already acquired by another session"); + } - cap = _acquire(device.label(), true); - _sessions.for_each([&] (Session_component &sc) { - if (sc._matches(device)) sc.update_devices_rom(); }); - _root.report(); + cap = _acquire(device.label(), true); + _sessions.for_each([&] (Session_component &sc) { + if (sc._matches(device)) sc.update_devices_rom(); }); + _root.report(); }); if (!found) @@ -1371,21 +1410,25 @@ Device_capability Session_component::acquire_device(Device_name const &name) Device_capability Session_component::acquire_single_device() { Device_capability cap; - _devices.for_each([&] (genode_usb_device & device) { - if (cap.valid() || !_matches(device)) - return; + _devices.apply( + [&] (genode_usb_device & device) { + return !cap.valid() && _matches(device); }, + [&] (genode_usb_device & device) { - bool acquired = false; - _sessions.for_each([&] (Session_component &sc) { - if (sc.acquired(device)) acquired = true; }); + bool acquired = false; + _sessions.apply( + [&] (Session_component &sc) { + return sc.acquired(device); }, + [&] (Session_component &) { + acquired = true; }); - if (acquired) - return; + if (acquired) + return; - cap = _acquire(device.label(), true); - _sessions.for_each([&] (Session_component &sc) { - if (sc._matches(device)) sc.update_devices_rom(); }); - _root.report(); + cap = _acquire(device.label(), true); + _sessions.for_each([&] (Session_component &sc) { + if (sc._matches(device)) sc.update_devices_rom(); }); + _root.report(); }); return cap; } @@ -1396,8 +1439,10 @@ void Session_component::release_device(Device_capability cap) if (!cap.valid()) return; - _device_sessions.for_each([&] (Device_component & dc) { - if (cap.local_name() == dc.cap().local_name()) + _device_sessions.apply( + [&] (Device_component & dc) { + return cap.local_name() == dc.cap().local_name(); }, + [&] (Device_component & dc) { _release(dc); }); } @@ -1409,8 +1454,10 @@ void Session_component::produce_xml(Xml_generator &xml) return; bool acquired_by_other_session = false; - _sessions.for_each([&] (Session_component &sc) { - if (sc.acquired(device) && &sc != this) + _sessions.apply( + [&] (Session_component &sc) { + return sc.acquired(device) && &sc != this; }, + [&] (Session_component &) { acquired_by_other_session = true; }); if (acquired_by_other_session) @@ -1458,8 +1505,10 @@ Session_component::~Session_component() { _state = IN_DESTRUCTION; _device_sessions.for_each([&] (Device_component & dc) { - _devices.for_each([&] (genode_usb_device & device) { - if (device.label() == dc._device_label) + _devices.apply( + [&] (genode_usb_device & device) { + return device.label() == dc._device_label; }, + [&] (genode_usb_device & device) { _release_fn(device.bus, device.dev); }); _release(dc); @@ -1472,18 +1521,13 @@ Session_component * ::Root::_create_session(const char * args, { Session_component * sc = nullptr; try { - Session_label const label { session_label_from_args(args) }; - Session_policy const policy { label, _config.xml() }; + Session_label const label { session_label_from_args(args) }; sc = new (md_alloc()) Session_component(_env, *this, _sessions, _devices, _config, _sigh_cap, _alloc_fn, _free_fn, _release_fn, label, session_resources_from_args(args), session_diag_from_args(args)); - } catch (Session_policy::No_policy_defined) { - error("Invalid session request, no matching policy for ", - "'", label_from_args(args).string(), "'"); - throw Service_denied(); } catch (...) { if (sc) { Genode::destroy(md_alloc(), sc); } throw; @@ -1507,8 +1551,11 @@ void ::Root::report() _device_reporter->generate([&] (Reporter::Xml_generator &xml) { _devices.for_each([&] (genode_usb_device & d) { bool acquired = false; - _sessions.for_each([&] (Session_component &sc) { - if (sc.acquired(d)) acquired = true; }); + _sessions.apply( + [&] (Session_component &sc) { + return sc.acquired(d); }, + [&] (Session_component &) { + acquired = true; }); d.generate(xml, acquired); }); }); @@ -1627,23 +1674,23 @@ void ::Root::announce_device(genode_usb_bus_num_t bus, void ::Root::discontinue_device(genode_usb_bus_num_t bus, genode_usb_dev_num_t dev) { - _devices.for_each([&] (genode_usb_device & device) - { - if (device.bus != bus || device.dev != dev) - return; + _devices.apply( + [&] (genode_usb_device & device) { + return device.bus == bus && device.dev == dev; }, - _sessions.for_each([&] (Session_component & sc) { - sc.discontinue_device(device); }); + [&] (genode_usb_device & device) { + _sessions.for_each([&] (Session_component & sc) { + sc.discontinue_device(device); }); - device.configs.for_each([&] (genode_usb_configuration & cfg) { - cfg.interfaces.for_each([&] (genode_usb_interface & iface) { - iface.endpoints.for_each([&] (genode_usb_endpoint & endp) { - Genode::destroy(_heap, &endp); }); - Genode::destroy(_heap, &iface); + device.configs.for_each([&] (genode_usb_configuration & cfg) { + cfg.interfaces.for_each([&] (genode_usb_interface & iface) { + iface.endpoints.for_each([&] (genode_usb_endpoint & endp) { + Genode::destroy(_heap, &endp); }); + Genode::destroy(_heap, &iface); + }); + Genode::destroy(_heap, &cfg); }); - Genode::destroy(_heap, &cfg); - }); - Genode::destroy(_heap, &device); + Genode::destroy(_heap, &device); }); report(); } @@ -1652,10 +1699,15 @@ void ::Root::discontinue_device(genode_usb_bus_num_t bus, bool ::Root::acquired(genode_usb_bus_num_t bus, genode_usb_dev_num_t dev) { bool ret = false; - _devices.for_each([&] (genode_usb_device & device) { - if (device.bus == bus && device.dev == dev) - _sessions.for_each([&] (Session_component & sc) { - if (sc.acquired(device)) ret = true; }); + _devices.apply( + [&] (genode_usb_device & device) { + return device.bus == bus && device.dev == dev; }, + [&] (genode_usb_device & device) { + _sessions.apply( + [&] (Session_component & sc) { + return sc.acquired(device); }, + [&] (Session_component &) { + ret = true; }); }); return ret; } @@ -1667,13 +1719,15 @@ bool ::Root::request(genode_usb_bus_num_t bus, void *opaque_data) { bool ret = false; - _devices.for_each([&] (genode_usb_device & device) - { - if (device.bus != bus || device.dev != dev) - return; + _devices.apply( + [&] (genode_usb_device & device) { + return device.bus == bus && device.dev == dev; }, - _sessions.for_each([&] (Session_component & sc) { - if (sc.request(device, callback, opaque_data)) ret = true; }); + [&] (genode_usb_device & device) { + _sessions.apply( + [&] (Session_component & sc) { + return sc.request(device, callback, opaque_data); }, + [&] (Session_component &) { ret = true; }); }); return ret; } @@ -1683,10 +1737,10 @@ void ::Root::handle_response(genode_usb_request_handle_t id, genode_usb_request_ret_t ret, uint32_t *actual_sizes) { - bool handled = false; - _sessions.for_each([&] (Session_component & sc) { - if (!handled) handled = sc.handle_response(id, ret, actual_sizes); - }); + _sessions.apply( + [&] (Session_component & sc) { + return sc.handle_response(id, ret, actual_sizes); }, + [&] (Session_component &) { }); } diff --git a/repos/os/src/lib/sandbox/child.cc b/repos/os/src/lib/sandbox/child.cc index 666c902b0e..2b2a8b5fa3 100644 --- a/repos/os/src/lib/sandbox/child.cc +++ b/repos/os/src/lib/sandbox/child.cc @@ -247,7 +247,7 @@ void Sandbox::Child::_apply_resource_upgrade(QUOTA &assigned, QUOTA const config assigned.value += transfer.value; - ref_pd().transfer_quota(_child.pd_session_cap(), transfer); + ref_account().transfer_quota(_child.pd_session_cap(), transfer); /* wake up child that blocks on a resource request */ if (_requested_resources.constructed()) { @@ -304,7 +304,7 @@ void Sandbox::Child::_apply_resource_downgrade(QUOTA &assigned, QUOTA const conf QUOTA const transfer { min(avail - preserved.value, decrement.value) }; try { - _child.pd().transfer_quota(ref_pd_cap(), transfer); + _child.pd().transfer_quota(ref_account_cap(), transfer); assigned.value -= transfer.value; break; } catch (...) { } diff --git a/repos/os/src/lib/sandbox/child.h b/repos/os/src/lib/sandbox/child.h index 9755453a6f..9af64ff87b 100644 --- a/repos/os/src/lib/sandbox/child.h +++ b/repos/os/src/lib/sandbox/child.h @@ -50,8 +50,22 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup */ struct Id { unsigned value; }; - struct Default_route_accessor : Interface { virtual Xml_node default_route() = 0; }; - struct Default_caps_accessor : Interface { virtual Cap_quota default_caps() = 0; }; + using With_xml = Callable<void, Xml_node const &>; + + struct Default_route_accessor : Interface + { + virtual void _with_default_route(With_xml::Ft const &) = 0; + + void with_default_route(auto const &fn) + { + _with_default_route(With_xml::Fn { fn }); + } + }; + + struct Default_caps_accessor : Interface + { + virtual Cap_quota default_caps() = 0; + }; template <typename QUOTA> struct Resource_limit_accessor : Interface @@ -74,27 +88,14 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup enum class Sample_state_result { CHANGED, UNCHANGED }; - /* - * Helper for passing lambda functions as 'Pd_intrinsics::Fn' - */ - using Pd_intrinsics = Genode::Sandbox::Pd_intrinsics; - template <typename PD_SESSION, typename FN> + template <typename PD_SESSION> static void with_pd_intrinsics(Pd_intrinsics &pd_intrinsics, Capability<Pd_session> cap, PD_SESSION &pd, - FN const &fn) + auto const &fn) { - struct Impl : Pd_intrinsics::Fn - { - using Intrinsics = Pd_intrinsics::Intrinsics; - - FN const &_fn; - Impl(FN const &fn) : _fn(fn) { } - void call(Intrinsics &intrinsics) const override { _fn(intrinsics); } - }; - - pd_intrinsics.with_intrinsics(cap, pd, Impl { fn }); + pd_intrinsics.with_intrinsics(cap, pd, Pd_intrinsics::With_intrinsics::Fn { fn }); } private: @@ -153,8 +154,10 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup start.with_sub_node("route", [&] (Xml_node const &route) { _route_model.construct(_alloc, route); }, - [&] () { - _route_model.construct(_alloc, _default_route_accessor.default_route()); }); + [&] { + _default_route_accessor.with_default_route([&] (Xml_node const &node) { + _route_model.construct(_alloc, node); }); + }); } /* @@ -306,8 +309,7 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup Pd_intrinsics &_pd_intrinsics; - template <typename FN> - void _with_pd_intrinsics(FN const &fn) + void _with_pd_intrinsics(auto const &fn) { with_pd_intrinsics(_pd_intrinsics, _child.pd_session_cap(), _child.pd(), fn); } @@ -715,15 +717,15 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup Child_policy::Name name() const override { return _unique_name; } - Pd_session &ref_pd() override + Pd_account &ref_account() override { - Pd_session *_ref_pd_ptr = nullptr; + Pd_account *_ref_account_ptr = nullptr; _with_pd_intrinsics([&] (Pd_intrinsics::Intrinsics &intrinsics) { - _ref_pd_ptr = &intrinsics.ref_pd; }); - return *_ref_pd_ptr; + _ref_account_ptr = &intrinsics.ref_pd; }); + return *_ref_account_ptr; } - Pd_session_capability ref_pd_cap() const override { return _ref_pd_cap; } + Capability<Pd_account> ref_account_cap() const override { return _ref_pd_cap; } Ram_allocator &session_md_ram() override { return _env.ram(); } diff --git a/repos/os/src/lib/sandbox/library.cc b/repos/os/src/lib/sandbox/library.cc index 9bad5ee66b..06f863f680 100644 --- a/repos/os/src/lib/sandbox/library.cc +++ b/repos/os/src/lib/sandbox/library.cc @@ -189,10 +189,10 @@ struct Genode::Sandbox::Library : ::Sandbox::State_reporter::Producer, /** * Default_route_accessor interface */ - Xml_node default_route() override + void _with_default_route(Child::With_xml::Ft const &fn) override { - return _default_route.constructed() ? _default_route->xml() - : Xml_node("<empty/>"); + if (_default_route.constructed()) + fn(_default_route->xml()); } /** @@ -259,13 +259,14 @@ struct Genode::Sandbox::Library : ::Sandbox::State_reporter::Producer, { Env &_env; - void with_intrinsics(Capability<Pd_session>, Pd_session &pd, Fn const &fn) override + void with_intrinsics(Capability<Pd_session>, Pd_session &pd, + With_intrinsics::Ft const &fn) override { Region_map_client region_map(pd.address_space()); Intrinsics intrinsics { _env.pd(), _env.pd_session_cap(), _env.cpu(), _env.cpu_session_cap(), region_map }; - fn.call(intrinsics); + fn(intrinsics); } void start_initial_thread(Capability<Cpu_thread> cap, addr_t ip) override @@ -520,7 +521,7 @@ void Genode::Sandbox::Library::apply_config(Xml_node const &config) ** Sandbox::Local_service_base ** *********************************/ -void Genode::Sandbox::Local_service_base::_for_each_requested_session(Request_fn &fn) +void Genode::Sandbox::Local_service_base::_for_each_requested_session(With_request::Ft const &fn) { _server_id_space.for_each<Session_state>([&] (Session_state &session) { @@ -528,7 +529,7 @@ void Genode::Sandbox::Local_service_base::_for_each_requested_session(Request_fn Request request(session); - fn.with_requested_session(request); + fn(request); bool wakeup_client = false; @@ -551,7 +552,7 @@ void Genode::Sandbox::Local_service_base::_for_each_requested_session(Request_fn } -void Genode::Sandbox::Local_service_base::_for_each_upgraded_session(Upgrade_fn &fn) +void Genode::Sandbox::Local_service_base::_for_each_upgraded_session(With_upgrade::Ft const &fn) { _server_id_space.for_each<Session_state>([&] (Session_state &session) { @@ -566,7 +567,7 @@ void Genode::Sandbox::Local_service_base::_for_each_upgraded_session(Upgrade_fn Session::Resources const amount { session.ram_upgrade, session.cap_upgrade }; - switch (fn.with_upgraded_session(*session.local_ptr, amount)) { + switch (fn(*session.local_ptr, amount)) { case Upgrade_response::CONFIRMED: session.phase = Session_state::CAP_HANDED_OUT; @@ -583,7 +584,7 @@ void Genode::Sandbox::Local_service_base::_for_each_upgraded_session(Upgrade_fn } -void Genode::Sandbox::Local_service_base::_for_each_session_to_close(Close_fn &close_fn) +void Genode::Sandbox::Local_service_base::_for_each_session_to_close(With_close::Ft const &fn) { /* * Collection of closed sessions to be destructed via callback @@ -605,7 +606,7 @@ void Genode::Sandbox::Local_service_base::_for_each_session_to_close(Close_fn &c if (session.local_ptr == nullptr) return; - switch (close_fn.close_session(*session.local_ptr)) { + switch (fn(*session.local_ptr)) { case Close_response::CLOSED: diff --git a/repos/os/src/lib/sandbox/server.cc b/repos/os/src/lib/sandbox/server.cc index c8e7a36136..c557d237be 100644 --- a/repos/os/src/lib/sandbox/server.cc +++ b/repos/os/src/lib/sandbox/server.cc @@ -316,11 +316,12 @@ void Sandbox::Server::_handle_upgrade_session_request(Xml_node request, { _client_id_space.apply<Session_state>(id, [&] (Session_state &session) { + if (session.phase == Session_state::UPGRADE_REQUESTED) + return; + Ram_quota const ram_quota { request.attribute_value("ram_quota", 0UL) }; Cap_quota const cap_quota { request.attribute_value("cap_quota", 0UL) }; - session.phase = Session_state::UPGRADE_REQUESTED; - try { Ram_transfer::Remote_account env_ram_account(_env.pd(), _env.pd_session_cap()); Cap_transfer::Remote_account env_cap_account(_env.pd(), _env.pd_session_cap()); @@ -338,6 +339,7 @@ void Sandbox::Server::_handle_upgrade_session_request(Xml_node request, return; } + session.phase = Session_state::UPGRADE_REQUESTED; session.increase_donated_quota(ram_quota, cap_quota); session.service().initiate_request(session); session.service().wakeup(); diff --git a/repos/os/src/lib/sandbox/service.h b/repos/os/src/lib/sandbox/service.h index b8ea878b3f..250003fe20 100644 --- a/repos/os/src/lib/sandbox/service.h +++ b/repos/os/src/lib/sandbox/service.h @@ -118,7 +118,7 @@ class Sandbox::Routed_service : public Async_service, public Abandonable /** * Ram_transfer::Account interface */ - Ram_transfer_result transfer(Pd_session_capability to, Ram_quota amount) override + Ram_transfer_result transfer(Capability<Pd_account> to, Ram_quota amount) override { return to.valid() ? _pd_accessor.pd().transfer_quota(to, amount) : Ram_transfer_result::OK; @@ -127,7 +127,7 @@ class Sandbox::Routed_service : public Async_service, public Abandonable /** * Ram_transfer::Account interface */ - Pd_session_capability cap(Ram_quota) const override + Capability<Pd_account> cap(Ram_quota) const override { return _pd_accessor.pd_cap(); } @@ -135,7 +135,7 @@ class Sandbox::Routed_service : public Async_service, public Abandonable /** * Cap_transfer::Account interface */ - Cap_transfer_result transfer(Pd_session_capability to, Cap_quota amount) override + Cap_transfer_result transfer(Capability<Pd_account> to, Cap_quota amount) override { return to.valid() ? _pd_accessor.pd().transfer_quota(to, amount) : Cap_transfer_result::OK; @@ -144,7 +144,7 @@ class Sandbox::Routed_service : public Async_service, public Abandonable /** * Cap_transfer::Account interface */ - Pd_session_capability cap(Cap_quota) const override + Capability<Pd_account> cap(Cap_quota) const override { return _pd_accessor.pd_cap(); } diff --git a/repos/os/src/lib/vfs/capture/plugin.cc b/repos/os/src/lib/vfs/capture/plugin.cc index f4bb061438..abe27cf2bd 100644 --- a/repos/os/src/lib/vfs/capture/plugin.cc +++ b/repos/os/src/lib/vfs/capture/plugin.cc @@ -121,7 +121,7 @@ class Vfs_capture::Data_file_system : public Single_file_system } catch (Genode::Service_denied) { return OPEN_ERR_UNACCESSIBLE; } - _capture->buffer(_capture_area); + _capture->buffer({ .px = _capture_area, .mm = { } }); _capture_ds.construct(_env.rm(), _capture->dataspace()); } diff --git a/repos/os/src/monitor/gdb_command.h b/repos/os/src/monitor/gdb_command.h index f72b5cfa65..44bb397920 100644 --- a/repos/os/src/monitor/gdb_command.h +++ b/repos/os/src/monitor/gdb_command.h @@ -14,6 +14,7 @@ #ifndef _GDB_COMMAND_H_ #define _GDB_COMMAND_H_ +#include <util/callable.h> #include <base/registry.h> #include <monitor/string.h> #include <types.h> @@ -47,23 +48,13 @@ struct Monitor::Gdb::Command : private Commands::Element, Interface with_skipped_prefix(bytes, name, match_remainder_fn); } - struct With_args_fn : Interface - { - virtual void call(Const_byte_range_ptr const &args) const = 0; - }; + using With_args = Callable<void, Const_byte_range_ptr const &>; - virtual void _with_args(Const_byte_range_ptr const &, With_args_fn const &) const = 0; + virtual void _with_args(Const_byte_range_ptr const &, With_args::Ft const &) const = 0; void with_args(Const_byte_range_ptr const &command_bytes, auto const &fn) const { - using Fn = typeof(fn); - struct Impl : With_args_fn - { - Fn const &_fn; - Impl(Fn const &fn) : _fn(fn) { } - void call(Const_byte_range_ptr const &args) const override { _fn(args); } - }; - _with_args(command_bytes, Impl(fn)); + _with_args(command_bytes, With_args::Fn { fn }); } virtual void execute(State &, Const_byte_range_ptr const &args, Output &) const = 0; @@ -190,11 +181,11 @@ struct Monitor::Gdb::Command_with_separator : Command } void _with_args(Const_byte_range_ptr const &bytes, - With_args_fn const &fn) const override + With_args::Ft const &fn) const override { _match_name(bytes, [&] (Const_byte_range_ptr const &bytes) { _match_separator(bytes, [&] (Const_byte_range_ptr const &args) { - fn.call(args); }); }); + fn(args); }); }); } }; @@ -204,10 +195,10 @@ struct Monitor::Gdb::Command_without_separator : Command using Command::Command; void _with_args(Const_byte_range_ptr const &bytes, - With_args_fn const &fn) const override + With_args::Ft const &fn) const override { _match_name(bytes, [&] (Const_byte_range_ptr const &args) { - fn.call(args); }); + fn(args); }); } }; diff --git a/repos/os/src/monitor/monitored_pd.h b/repos/os/src/monitor/monitored_pd.h index d2249e81f2..25fa8df021 100644 --- a/repos/os/src/monitor/monitored_pd.h +++ b/repos/os/src/monitor/monitored_pd.h @@ -44,38 +44,38 @@ struct Monitor::Monitored_pd_session : Monitored_rpc_object<Pd_session> ** Pd_session interface ** **************************/ - Ref_account_result ref_account(Capability<Pd_session> pd_cap) override + Ref_account_result ref_account(Capability<Pd_account> ref) override { Ref_account_result result = Ref_account_result::INVALID_SESSION; - _with_pd_arg(pd_cap, + _with_pd_arg(static_cap_cast<Pd_session>(ref), [&] (Monitored_pd_session &pd) { result = _real.call<Rpc_ref_account>(pd._real); }, [&] { - result = _real.call<Rpc_ref_account>(pd_cap); }); + result = _real.call<Rpc_ref_account>(ref); }); return result; } - Transfer_cap_quota_result transfer_quota(Capability<Pd_session> pd_cap, - Cap_quota amount) override + Transfer_result transfer_quota(Capability<Pd_account> to, + Cap_quota amount) override { - Transfer_cap_quota_result result = Transfer_cap_quota_result::INVALID_SESSION; - _with_pd_arg(pd_cap, + Transfer_result result = Transfer_result::INVALID; + _with_pd_arg(static_cap_cast<Pd_session>(to), [&] (Monitored_pd_session &pd) { result = _real.call<Rpc_transfer_cap_quota>(pd._real, amount); }, [&] { - result = _real.call<Rpc_transfer_cap_quota>(pd_cap, amount); }); + result = _real.call<Rpc_transfer_cap_quota>(to, amount); }); return result; } - Transfer_ram_quota_result transfer_quota(Pd_session_capability pd_cap, - Ram_quota amount) override + Transfer_result transfer_quota(Capability<Pd_account> to, + Ram_quota amount) override { - Transfer_ram_quota_result result = Transfer_ram_quota_result::INVALID_SESSION; - _with_pd_arg(pd_cap, + Transfer_result result = Transfer_result::INVALID; + _with_pd_arg(static_cap_cast<Pd_session>(to), [&] (Monitored_pd_session &pd) { result = _real.call<Rpc_transfer_ram_quota>(pd._real, amount); }, [&] { - result = _real.call<Rpc_transfer_ram_quota>(pd_cap, amount); }); + result = _real.call<Rpc_transfer_ram_quota>(to, amount); }); return result; } }; diff --git a/repos/os/src/monitor/monitored_vm.h b/repos/os/src/monitor/monitored_vm.h index 89eca6ba4d..000743676c 100644 --- a/repos/os/src/monitor/monitored_vm.h +++ b/repos/os/src/monitor/monitored_vm.h @@ -48,7 +48,7 @@ struct Monitor::Monitored_vm_session : Monitored_rpc_object<Vm_session, Monitore _real.call<Rpc_attach_pic>(vm_addr); } - Capability<Native_vcpu> create_vcpu(Thread_capability thread_cap) + Capability<Native_vcpu> create_vcpu(Thread_capability thread_cap) override { Capability<Native_vcpu> result { }; diff --git a/repos/os/src/monitor/pd_intrinsics.h b/repos/os/src/monitor/pd_intrinsics.h index c374ff3b66..4750def845 100644 --- a/repos/os/src/monitor/pd_intrinsics.h +++ b/repos/os/src/monitor/pd_intrinsics.h @@ -86,7 +86,8 @@ struct Monitor::Pd_intrinsics : Sandbox::Pd_intrinsics } _monitored_ref_cpu { _env.ep(), _env.cpu_session_cap(), Session::Label { } }; - void with_intrinsics(Capability<Pd_session> pd_cap, Pd_session &pd, Fn const &fn) override + void with_intrinsics(Capability<Pd_session> pd_cap, Pd_session &pd, + With_intrinsics::Ft const &fn) override { /* * Depending on the presence of the PD session in our local entrypoint, @@ -111,7 +112,7 @@ struct Monitor::Pd_intrinsics : Sandbox::Pd_intrinsics .ref_cpu = _monitored_ref_cpu, .ref_cpu_cap = _monitored_ref_cpu.cap(), .address_space = inferior_pd._address_space }; - fn.call(intrinsics); + fn(intrinsics); }, [&] /* PD session not intercepted */ { @@ -122,7 +123,7 @@ struct Monitor::Pd_intrinsics : Sandbox::Pd_intrinsics .ref_cpu = _env.cpu(), .ref_cpu_cap = _env.cpu_session_cap(), .address_space = region_map }; - fn.call(intrinsics); + fn(intrinsics); } ); } diff --git a/repos/os/src/server/black_hole/capture.h b/repos/os/src/server/black_hole/capture.h index 601c9f6333..7e8e7e5b92 100644 --- a/repos/os/src/server/black_hole/capture.h +++ b/repos/os/src/server/black_hole/capture.h @@ -67,14 +67,21 @@ class Capture::Session_component : public Session_object<Capture::Session> void screen_size_sigh(Signal_context_capability) override { } - void buffer(Area size) override + void wakeup_sigh(Signal_context_capability) override { } + + Buffer_result buffer(Buffer_attr attr) override { - if (size.count() == 0) { + if (attr.px.count() == 0) { _buffer.destruct(); - return; + return Buffer_result::OK; } - _buffer.construct(_ram, _env.rm(), buffer_bytes(size)); + try { + _buffer.construct(_ram, _env.rm(), buffer_bytes(attr.px)); + } + catch (Out_of_ram) { return Buffer_result::OUT_OF_RAM; } + catch (Out_of_caps) { return Buffer_result::OUT_OF_CAPS; } + return Buffer_result::OK; } Dataspace_capability dataspace() override @@ -89,6 +96,8 @@ class Capture::Session_component : public Session_object<Capture::Session> { return Affected_rects(); } + + void capture_stopped() override { } }; diff --git a/repos/os/src/server/fs_rom/main.cc b/repos/os/src/server/fs_rom/main.cc index 609f73bc32..1389600ea8 100644 --- a/repos/os/src/server/fs_rom/main.cc +++ b/repos/os/src/server/fs_rom/main.cc @@ -258,7 +258,7 @@ class Fs_rom::Rom_session_component : public Rpc_object<Rom_session> return false; } } else { - memset(_file_ds.local_addr<char>(), 0x00, _file_ds.size()); + _file_ds.clear(); } /* omit read if file is empty */ @@ -304,7 +304,13 @@ class Fs_rom::Rom_session_component : public Rpc_object<Rom_session> catch (Watch_failed) { } try { return _read_dataspace(update_only); } - catch (Lookup_failed) { /* missing but may appear anytime soon */ } + catch (Lookup_failed) { + if (_file_size > 0) { + _file_ds.clear(); + _file_size = 0; + Signal_transmitter(_sigh).submit(); + } + } catch (Invalid_handle) { warning(_file_path, ": invalid handle"); } catch (Invalid_name) { warning(_file_path, ": invalid name"); } catch (Permission_denied) { warning(_file_path, ": permission denied"); } @@ -333,7 +339,7 @@ class Fs_rom::Rom_session_component : public Rpc_object<Rom_session> /* notify if the file is removed */ catch (File_system::Lookup_failed) { if (_file_size > 0) { - memset(_file_ds.local_addr<char>(), 0x00, (size_t)_file_size); + _file_ds.clear(); _file_size = 0; Signal_transmitter(_sigh).submit(); } diff --git a/repos/os/src/server/gui_fb/main.cc b/repos/os/src/server/gui_fb/main.cc index db02a179cb..6f0565f66e 100644 --- a/repos/os/src/server/gui_fb/main.cc +++ b/repos/os/src/server/gui_fb/main.cc @@ -20,18 +20,18 @@ #include <base/attached_rom_dataspace.h> #include <base/component.h> -namespace Nit_fb { +namespace Gui_fb { + using namespace Genode; + + struct View_updater; struct Main; - using Genode::Static_root; - using Genode::Signal_handler; - using Genode::Xml_node; - using Genode::size_t; + using Point = Gui::Point; + using Area = Gui::Area; + using Rect = Gui::Rect; - using Point = Genode::Surface_base::Point; - using Area = Genode::Surface_base::Area; - using Rect = Genode::Surface_base::Rect; + static ::Input::Event translate_event(::Input::Event, Point, Area); } @@ -42,16 +42,14 @@ namespace Nit_fb { /** * Translate input event */ -static Input::Event translate_event(Input::Event ev, - Nit_fb::Point const input_origin, - Nit_fb::Area const boundary) +static Input::Event Gui_fb::translate_event(Input::Event ev, + Point const input_origin, + Area const boundary) { - using Nit_fb::Point; - /* function to clamp point to bounday */ auto clamp = [boundary] (Point p) { - return Point(Genode::min((int)boundary.w - 1, Genode::max(0, p.x)), - Genode::min((int)boundary.h - 1, Genode::max(0, p.y))); }; + return Point(min((int)boundary.w - 1, max(0, p.x)), + min((int)boundary.h - 1, max(0, p.y))); }; /* function to translate point to 'input_origin' */ auto translate = [input_origin] (Point p) { return p - input_origin; }; @@ -70,7 +68,7 @@ static Input::Event translate_event(Input::Event ev, } -struct View_updater : Genode::Interface +struct Gui_fb::View_updater : Genode::Interface { virtual void update_view() = 0; }; @@ -80,18 +78,23 @@ struct View_updater : Genode::Interface ** Virtualized framebuffer ** *****************************/ -namespace Framebuffer { struct Session_component; } +namespace Framebuffer { + + using namespace Gui_fb; + + struct Session_component; +} struct Framebuffer::Session_component : Genode::Rpc_object<Framebuffer::Session> { - Genode::Pd_session const &_pd; + Pd_session const &_pd; Gui::Connection &_gui; - Genode::Signal_context_capability _mode_sigh { }; + Signal_context_capability _mode_sigh { }; - Genode::Signal_context_capability _sync_sigh { }; + Signal_context_capability _sync_sigh { }; View_updater &_view_updater; @@ -101,7 +104,7 @@ struct Framebuffer::Session_component : Genode::Rpc_object<Framebuffer::Session> */ Framebuffer::Mode _next_mode; - using size_t = Genode::size_t; + bool _mode_sigh_pending = false; /* * Number of bytes used for backing the current virtual framebuffer at @@ -123,18 +126,25 @@ struct Framebuffer::Session_component : Genode::Rpc_object<Framebuffer::Session> { /* calculation in bytes */ size_t const used = _buffer_num_bytes, - needed = Gui::Session::ram_quota(mode, false), + needed = Gui::Session::ram_quota(mode), usable = _pd.avail_ram().value, preserved = 64*1024; return used + usable > needed + preserved; } + void _update_view() + { + if (_dataspace_is_new) { + _view_updater.update_view(); + _dataspace_is_new = false; + } + } /** * Constructor */ - Session_component(Genode::Pd_session const &pd, + Session_component(Pd_session const &pd, Gui::Connection &gui, View_updater &view_updater, Framebuffer::Mode initial_mode) @@ -149,17 +159,19 @@ struct Framebuffer::Session_component : Genode::Rpc_object<Framebuffer::Session> if (Gui::Area(_next_mode.area.w, _next_mode.area.h) == size) return; - Framebuffer::Mode const mode { .area = size }; + Framebuffer::Mode const mode { .area = size, .alpha = false }; if (!_ram_suffices_for_mode(mode)) { - Genode::warning("insufficient RAM for mode ", mode); + warning("insufficient RAM for mode ", mode); return; } _next_mode = mode; if (_mode_sigh.valid()) - Genode::Signal_transmitter(_mode_sigh).submit(); + Signal_transmitter(_mode_sigh).submit(); + else + _mode_sigh_pending = true; } Gui::Area size() const @@ -172,13 +184,12 @@ struct Framebuffer::Session_component : Genode::Rpc_object<Framebuffer::Session> ** Framebuffer::Session interface ** ************************************/ - Genode::Dataspace_capability dataspace() override + Dataspace_capability dataspace() override { - _gui.buffer(_active_mode, false); + _gui.buffer(_active_mode); _buffer_num_bytes = - Genode::max(_buffer_num_bytes, - Gui::Session::ram_quota(_active_mode, false)); + max(_buffer_num_bytes, Gui::Session::ram_quota(_active_mode)); /* * We defer the update of the view until the client calls refresh the @@ -196,22 +207,36 @@ struct Framebuffer::Session_component : Genode::Rpc_object<Framebuffer::Session> return _active_mode; } - void mode_sigh(Genode::Signal_context_capability sigh) override + void mode_sigh(Signal_context_capability sigh) override { _mode_sigh = sigh; - } - void refresh(int x, int y, int w, int h) override - { - if (_dataspace_is_new) { - _view_updater.update_view(); - _dataspace_is_new = false; + /* notify mode change that happened just before 'mode_sigh' */ + if (_mode_sigh.valid() && _mode_sigh_pending) { + Signal_transmitter(_mode_sigh).submit(); + _mode_sigh_pending = false; } - - _gui.framebuffer.refresh(x, y, w, h); } - void sync_sigh(Genode::Signal_context_capability sigh) override + void refresh(Rect rect) override + { + _update_view(); + _gui.framebuffer.refresh(rect); + } + + Blit_result blit(Blit_batch const &batch) override + { + _update_view(); + return _gui.framebuffer.blit(batch); + } + + void panning(Point pos) override + { + _update_view(); + _gui.framebuffer.panning(pos); + } + + void sync_sigh(Signal_context_capability sigh) override { /* * Keep a component-local copy of the signal capability. Otherwise, @@ -223,6 +248,8 @@ struct Framebuffer::Session_component : Genode::Rpc_object<Framebuffer::Session> _gui.framebuffer.sync_sigh(sigh); } + + void sync_source(Session_label const &) override { } }; @@ -230,21 +257,30 @@ struct Framebuffer::Session_component : Genode::Rpc_object<Framebuffer::Session> ** Main program ** ******************/ -struct Nit_fb::Main : View_updater +struct Gui_fb::Main : View_updater, Input::Session_component::Action { - Genode::Env &env; + Env &_env; - Genode::Attached_rom_dataspace config_rom { env, "config" }; + Attached_rom_dataspace _config_rom { _env, "config" }; - Gui::Connection gui { env }; + Gui::Connection _gui { _env }; - Point position { 0, 0 }; + Point _position { 0, 0 }; - unsigned refresh_rate = 0; + unsigned _refresh_rate = 0; - Gui::Top_level_view const view { gui }; + Gui::Top_level_view const _view { _gui }; - Genode::Attached_dataspace input_ds { env.rm(), gui.input.dataspace() }; + Attached_dataspace _input_ds { _env.rm(), _gui.input.dataspace() }; + + Gui::Rect _gui_window() + { + return _gui.window().convert<Gui::Rect>( + [&] (Gui::Rect rect) { return rect; }, + [&] (Gui::Undefined) { return _gui.panorama().convert<Gui::Rect>( + [&] (Gui::Rect rect) { return rect; }, + [&] (Gui::Undefined) { return Gui::Rect { { }, { 1, 1 } }; }); }); + } struct Initial_size { @@ -253,47 +289,95 @@ struct Nit_fb::Main : View_updater bool set { false }; - Initial_size(Genode::Xml_node config) + Initial_size(Xml_node config) : _width (config.attribute_value("initial_width", 0L)), _height(config.attribute_value("initial_height", 0L)) { } - unsigned width(Framebuffer::Mode const &mode) const + unsigned width(Gui::Area const &gui_area) const { if (_width > 0) return (unsigned)_width; - if (_width < 0) return (unsigned)(mode.area.w + _width); - return mode.area.w; + if (_width < 0) return (unsigned)(gui_area.w + _width); + return gui_area.w; } - unsigned height(Framebuffer::Mode const &mode) const + unsigned height(Gui::Area const &gui_area) const { if (_height > 0) return (unsigned)_height; - if (_height < 0) return (unsigned)(mode.area.h + _height); - return mode.area.h; + if (_height < 0) return (unsigned)(gui_area.h + _height); + return gui_area.h; } bool valid() const { return _width != 0 && _height != 0; } - } _initial_size { config_rom.xml() }; + } _initial_size { _config_rom.xml() }; Framebuffer::Mode _initial_mode() { - return Framebuffer::Mode { .area = { _initial_size.width (gui.mode()), - _initial_size.height(gui.mode()) } }; + Gui::Area const gui_area = _gui_window().area; + return { + .area = { _initial_size.width (gui_area), + _initial_size.height(gui_area) }, + .alpha = false + }; } /* * Input and framebuffer sessions provided to our client */ - Input::Session_component input_session { env, env.ram() }; - Framebuffer::Session_component fb_session { env.pd(), gui, *this, _initial_mode() }; + Input::Session_component _input_session { _env.ep(), _env.ram(), _env.rm(), *this }; + + /** + * Input::Session_component::Action interface + */ + void exclusive_input_requested(bool enabled) override + { + _gui.input.exclusive(enabled); + } + + Framebuffer::Session_component _fb_session { _env.pd(), _gui, *this, _initial_mode() }; + + struct Input_root : Static_root<Input::Session> + { + Main &_main; + + Input_root(Main &main) + : + Static_root<Input::Session>(main._input_session.cap()), + _main(main) + { } + + void close(Capability<Session>) override + { + _main._input_session.sigh(Signal_context_capability()); + } + }; + + Input_root _input_root { *this }; /* * Attach root interfaces to the entry point */ - Static_root<Input::Session> input_root { env.ep().manage(input_session) }; - Static_root<Framebuffer::Session> fb_root { env.ep().manage(fb_session) }; + + struct Fb_root : Static_root<Framebuffer::Session> + { + Main &_main; + + Fb_root(Main &main) + : + Static_root<Framebuffer::Session>(main._env.ep().manage(main._fb_session)), + _main(main) + { } + + void close(Capability<Session>) override + { + _main._fb_session.sync_sigh(Signal_context_capability()); + _main._fb_session.mode_sigh(Signal_context_capability()); + } + }; + + Fb_root _fb_root { *this }; /** * View_updater interface @@ -301,28 +385,28 @@ struct Nit_fb::Main : View_updater void update_view() override { using Command = Gui::Session::Command; - gui.enqueue<Command::Geometry>(view.id(), Rect(position, fb_session.size())); - gui.enqueue<Command::Front>(view.id()); - gui.execute(); + _gui.enqueue<Command::Geometry>(_view.id(), Rect(_position, _fb_session.size())); + _gui.enqueue<Command::Front>(_view.id()); + _gui.execute(); } /** * Return screen-coordinate origin, depening on the config and screen mode */ - static Point _coordinate_origin(Framebuffer::Mode mode, Xml_node config) + static Point _coordinate_origin(Gui::Area gui_area, Xml_node config) { char const * const attr = "origin"; if (!config.has_attribute(attr)) return Point(0, 0); - using Value = Genode::String<32>; + using Value = String<32>; Value const value = config.attribute_value(attr, Value()); if (value == "top_left") return Point(0, 0); - if (value == "top_right") return Point(mode.area.w, 0); - if (value == "bottom_left") return Point(0, mode.area.h); - if (value == "bottom_right") return Point(mode.area.w, mode.area.h); + if (value == "top_right") return Point(gui_area.w, 0); + if (value == "bottom_left") return Point(0, gui_area.h); + if (value == "bottom_right") return Point(gui_area.w, gui_area.h); warning("unsupported ", attr, " attribute value '", value, "'"); return Point(0, 0); @@ -330,30 +414,27 @@ struct Nit_fb::Main : View_updater void _update_size() { - Xml_node const config = config_rom.xml(); + Xml_node const config = _config_rom.xml(); - Framebuffer::Mode const gui_mode = gui.mode(); + Gui::Area const gui_area = _gui_window().area; - position = _coordinate_origin(gui_mode, config) + Point::from_xml(config); + _position = _coordinate_origin(gui_area, config) + Point::from_xml(config); bool const attr = config.has_attribute("width") || config.has_attribute("height"); if (_initial_size.valid() && attr) { - Genode::warning("setting both inital and normal attributes not " - " supported, ignore initial size"); + warning("setting both inital and normal attributes not " + " supported, ignore initial size"); /* force initial to disable check below */ _initial_size.set = true; } - unsigned const gui_width = gui_mode.area.w; - unsigned const gui_height = gui_mode.area.h; - - long width = config.attribute_value("width", (long)gui_mode.area.w), - height = config.attribute_value("height", (long)gui_mode.area.h); + long width = config.attribute_value("width", long(gui_area.w)), + height = config.attribute_value("height", long(gui_area.h)); if (!_initial_size.set && _initial_size.valid()) { - width = _initial_size.width (gui_mode); - height = _initial_size.height(gui_mode); + width = _initial_size.width (gui_area); + height = _initial_size.height(gui_area); _initial_size.set = true; } else { @@ -362,43 +443,40 @@ struct Nit_fb::Main : View_updater * If configured width / height values are negative, the effective * width / height is deduced from the screen size. */ - if (width < 0) width = gui_width + width; - if (height < 0) height = gui_height + height; + if (width < 0) width = gui_area.w + width; + if (height < 0) height = gui_area.h + height; } - fb_session.size(Area((unsigned)width, (unsigned)height)); + _fb_session.size(Area((unsigned)width, (unsigned)height)); } - void handle_config_update() + void _handle_config_update() { - config_rom.update(); + _config_rom.update(); _update_size(); update_view(); } - Signal_handler<Main> config_update_handler = - { env.ep(), *this, &Main::handle_config_update }; + Signal_handler<Main> _config_update_handler = + { _env.ep(), *this, &Main::_handle_config_update }; - void handle_mode_update() + void _handle_mode_update() { _update_size(); } + + Signal_handler<Main> _mode_update_handler = + { _env.ep(), *this, &Main::_handle_mode_update }; + + void _handle_input() { - _update_size(); - } + Input::Event const * const events = _input_ds.local_addr<Input::Event>(); - Signal_handler<Main> mode_update_handler = - { env.ep(), *this, &Main::handle_mode_update }; - - void handle_input() - { - Input::Event const * const events = input_ds.local_addr<Input::Event>(); - - unsigned const num = gui.input.flush(); + unsigned const num = _gui.input.flush(); bool update = false; for (unsigned i = 0; i < num; i++) { update |= events[i].focus_enter(); - input_session.submit(translate_event(events[i], position, fb_session.size())); + _input_session.submit(translate_event(events[i], _position, _fb_session.size())); } /* get to front if we got input focus */ @@ -406,36 +484,35 @@ struct Nit_fb::Main : View_updater update_view(); } - Signal_handler<Main> input_handler = - { env.ep(), *this, &Main::handle_input }; + Signal_handler<Main> _input_handler { _env.ep(), *this, &Main::_handle_input }; /** * Constructor */ - Main(Genode::Env &env) : env(env) + Main(Env &env) : _env(env) { - input_session.event_queue().enabled(true); + _input_session.event_queue().enabled(true); /* * Announce services */ - env.parent().announce(env.ep().manage(fb_root)); - env.parent().announce(env.ep().manage(input_root)); + _env.parent().announce(_env.ep().manage(_fb_root)); + _env.parent().announce(_env.ep().manage(_input_root)); /* * Apply initial configuration */ - handle_config_update(); + _handle_config_update(); /* * Register signal handlers */ - config_rom.sigh(config_update_handler); - gui.mode_sigh(mode_update_handler); - gui.input.sigh(input_handler); + _config_rom.sigh(_config_update_handler); + _gui.info_sigh(_mode_update_handler); + _gui.input.sigh(_input_handler); } }; -void Component::construct(Genode::Env &env) { static Nit_fb::Main inst(env); } +void Component::construct(Genode::Env &env) { static Gui_fb::Main inst(env); } diff --git a/repos/os/src/server/nic_router/domain.h b/repos/os/src/server/nic_router/domain.h index 1067d6c9e9..7bc4be1baa 100644 --- a/repos/os/src/server/nic_router/domain.h +++ b/repos/os/src/server/nic_router/domain.h @@ -232,7 +232,7 @@ class Net::Domain : public List<Domain>::Element, dhcp_server_fn(*_dhcp_server_ptr); } - void with_dhcp_server(auto const &fn) { with_dhcp_server(fn, []{}); } + void with_optional_dhcp_server(auto const &fn) { with_dhcp_server(fn, []{}); } /********* ** log ** diff --git a/repos/os/src/server/nic_router/interface.cc b/repos/os/src/server/nic_router/interface.cc index ce58bc84f3..7247865402 100644 --- a/repos/os/src/server/nic_router/interface.cc +++ b/repos/os/src/server/nic_router/interface.cc @@ -1734,7 +1734,7 @@ void Interface::_continue_handle_eth(Packet_descriptor const &pkt) void Interface::_destroy_dhcp_allocation(Dhcp_allocation &allocation, Domain &local_domain) { - local_domain.with_dhcp_server([&] (Dhcp_server &srv) { + local_domain.with_optional_dhcp_server([&] (Dhcp_server &srv) { srv.free_ip(allocation.ip()); }); destroy(_alloc, &allocation); } @@ -2035,6 +2035,18 @@ void Interface::_update_dhcp_allocations(Domain &old_domain, Domain &new_domain) { bool dhcp_clients_outdated { false }; + + auto dismiss_all_fn = [&] () { + dhcp_clients_outdated = true; + while (Dhcp_allocation *allocation = _dhcp_allocations.first()) { + if (_config_ptr->verbose()) + log("[", new_domain, "] dismiss DHCP allocation: ", + *allocation, " (other/no DHCP server)"); + _dhcp_allocations.remove(*allocation); + _destroy_dhcp_allocation(*allocation, old_domain); + } + }; + old_domain.with_dhcp_server([&] (Dhcp_server &old_dhcp_srv) { new_domain.with_dhcp_server([&] (Dhcp_server &new_dhcp_srv) { if (old_dhcp_srv.config_equal_to_that_of(new_dhcp_srv)) { @@ -2054,18 +2066,16 @@ void Interface::_update_dhcp_allocations(Domain &old_domain, }); } else { /* dismiss all DHCP allocations */ - dhcp_clients_outdated = true; - while (Dhcp_allocation *allocation = _dhcp_allocations.first()) { - if (_config_ptr->verbose()) - log("[", new_domain, "] dismiss DHCP allocation: ", - *allocation, " (other/no DHCP server)"); - _dhcp_allocations.remove(*allocation); - _destroy_dhcp_allocation(*allocation, old_domain); - } + dismiss_all_fn(); } - if (dhcp_clients_outdated) - _reset_and_refetch_domain_ready_state(); - });}); + }, + /* no DHCP server on new domain */ + [&] () { dismiss_all_fn(); }); }, + /* no DHCP server on old domain */ + [&] () { dismiss_all_fn(); }); + + if (dhcp_clients_outdated) + _reset_and_refetch_domain_ready_state(); } diff --git a/repos/os/src/server/nic_router/session_env.h b/repos/os/src/server/nic_router/session_env.h index e83c800521..98dbd3ddbc 100644 --- a/repos/os/src/server/nic_router/session_env.h +++ b/repos/os/src/server/nic_router/session_env.h @@ -104,6 +104,18 @@ class Genode::Session_env : public Ram_allocator, _cap_guard { cap_quota } { } + /* + * The Ram_allocator interface is Noncopyable, but this + * implementation is safe to copy. + */ + Session_env(Session_env const &session) + : + _env { session._env }, + _shared_quota { session._shared_quota }, + _ram_guard { session._ram_guard }, + _cap_guard { session._cap_guard } + { } + Entrypoint &ep() { return _env.ep(); } diff --git a/repos/os/src/server/nitpicker/README b/repos/os/src/server/nitpicker/README index d9cb871626..9d40acf086 100644 --- a/repos/os/src/server/nitpicker/README +++ b/repos/os/src/server/nitpicker/README @@ -242,6 +242,49 @@ The 'keystate' attribute enables the reporting of the currently pressed keys. The 'clicked' attribute enables the reporting of the last clicked-on unfocused client. This report is useful for a focus-managing component to implement a focus-on-click policy. +The 'panorama' attribute enables the reporting of the panorama of displays +described below. + + +Multi-monitor support +~~~~~~~~~~~~~~~~~~~~~ + +Display drivers obtain pixel data from the nitpicker GUI server using +nitpicker's capture service. For each connected monitor, the driver creates a +distinct capture session labeled after the name of the connector. Therefore, +from nitpicker's perspective, each monitor corresponds to one capture client. +Each capture client can have a different size, which corresponds to the +respective display resolution. Together, all capture clients span a panorama, +which is the bounding box of all capture clients. Each capture client shows a +part of the panorama. + +By default, when configuring nitpicker with an empty '<capture/>' node, the +top-left corner of each capture client corresponds to the coordinate origin +(0, 0) of the panorama. Hence, each client obtains a mirror of the panorama. +This default policy can be overridden by explicit rules as follows: + +! <capture> +! <policy label="intel_fb -> eDP-1" width_mm="160" height_mm="90" /> +! <policy label="intel_fb -> HDMI-A-1" xpos="1024" ypos="0" +! width="1280" height="800"/> +! <default-policy/> +! </capture> + +The policy for the 'eDP-1' connector merely overrides the physical dimensions +of the display as reported by the driver. This is useful in situations where +the display's EDID information are incorrect. Apart from that tweak, the +client obtains the default part of the panorama at the coordinate origin. + +The policy for the HDMI-A-1 connector dictates an explicit placement within +the panorama. So a data projector connected via HDMI shows a mere window of +the panorama where the top-left corner corresponds to the panorama position +(1024, 0). The client won't observe any pixels outside the specified window. +It is possible to specify only a subset of attributes. E.g., by only +specifying the 'xpos', the width and height remain unconstrained. + +The default policy tells nitpicker to regard any other capture client as a +mirror of the panorama's coordinate origin. If absent, a client with no +policy, won't obtain any picture. Cascaded usage scenarios diff --git a/repos/os/src/server/nitpicker/buffer.h b/repos/os/src/server/nitpicker/buffer.h index e6c0d4bf33..e00f976a78 100644 --- a/repos/os/src/server/nitpicker/buffer.h +++ b/repos/os/src/server/nitpicker/buffer.h @@ -25,33 +25,22 @@ namespace Nitpicker { class Buffer; } -class Nitpicker::Buffer +struct Nitpicker::Buffer : private Attached_ram_dataspace { - private: + /** + * Constructor - allocate and map dataspace for virtual frame buffer + * + * \throw Out_of_ram + * \throw Out_of_caps + * \throw Region_map::Region_conflict + */ + Buffer(Ram_allocator &ram, Region_map &rm, size_t num_bytes) + : + Attached_ram_dataspace(ram, rm, num_bytes) + { } - Area _size; - Attached_ram_dataspace _ram_ds; - - public: - - /** - * Constructor - allocate and map dataspace for virtual frame buffer - * - * \throw Out_of_ram - * \throw Out_of_caps - * \throw Region_map::Region_conflict - */ - Buffer(Ram_allocator &ram, Region_map &rm, Area size, size_t bytes) - : - _size(size), _ram_ds(ram, rm, bytes) - { } - - /** - * Accessors - */ - Ram_dataspace_capability ds_cap() const { return _ram_ds.cap(); } - Area size() const { return _size; } - void *local_addr() const { return _ram_ds.local_addr<void>(); } + using Attached_ram_dataspace::bytes; + using Attached_ram_dataspace::cap; }; @@ -61,11 +50,15 @@ namespace Nitpicker { struct Buffer_provider; } /** * Interface for triggering the re-allocation of a virtual framebuffer * - * Used by 'Framebuffer::Session_component', * implemented by 'Gui_session' + * Used by 'Framebuffer::Session_component', implemented by 'Gui_session' */ struct Nitpicker::Buffer_provider : Interface { - virtual Dataspace_capability realloc_buffer(Framebuffer::Mode mode, bool use_alpha) = 0; + virtual Dataspace_capability realloc_buffer(Framebuffer::Mode) = 0; + + virtual void blit(Rect from, Point to) = 0; + + virtual void panning(Point) = 0; }; #endif /* _BUFFER_H_ */ diff --git a/repos/os/src/server/nitpicker/capture_session.h b/repos/os/src/server/nitpicker/capture_session.h index 66490249c6..b591506358 100644 --- a/repos/os/src/server/nitpicker/capture_session.h +++ b/repos/os/src/server/nitpicker/capture_session.h @@ -32,6 +32,58 @@ class Nitpicker::Capture_session : public Session_object<Capture::Session> * present capture buffers. */ virtual void capture_buffer_size_changed() = 0; + + virtual void capture_requested(Label const &) = 0; + }; + + struct Policy + { + template <typename T> + struct Attr + { + bool _defined { }; + T _value { }; + + Attr() { } + + Attr(T value) : _defined(true), _value(value) { } + + Attr(Xml_node const node, auto const &attr) + { + if (node.has_attribute(attr)) { + _value = node.attribute_value(attr, T { }); + _defined = true; + } + } + + /** + * Return defined attribute value, or default value + */ + T or_default(T def) const { return _defined ? _value : def; } + }; + + Attr<int> x, y; /* placement within panorama */ + Attr<unsigned> w, h; /* capture contraints */ + Attr<unsigned> w_mm, h_mm; /* physical size overrides */ + + static Policy from_xml(Xml_node const &policy) + { + return { .x = { policy, "xpos" }, + .y = { policy, "ypos" }, + .w = { policy, "width" }, + .h = { policy, "height" }, + .w_mm = { policy, "width_mm" }, + .h_mm = { policy, "height_mm" } }; + } + + static Policy unconstrained() { return { }; } + + static Policy blocked() + { + Policy result { }; + result.w = 0, result.h = 0; + return result; + } }; private: @@ -44,16 +96,44 @@ class Nitpicker::Capture_session : public Session_object<Capture::Session> View_stack const &_view_stack; - Area _buffer_size { }; + Policy _policy = Policy::blocked(); + + bool _policy_changed = false; + + Buffer_attr _buffer_attr { }; Constructible<Attached_ram_dataspace> _buffer { }; Signal_context_capability _screen_size_sigh { }; + Signal_context_capability _wakeup_sigh { }; + + bool _stopped = false; + using Dirty_rect = Genode::Dirty_rect<Rect, Affected_rects::NUM_RECTS>; Dirty_rect _dirty_rect { }; + void _wakeup_if_needed() + { + if (_stopped && !_dirty_rect.empty() && _wakeup_sigh.valid()) { + Signal_transmitter(_wakeup_sigh).submit(); + _stopped = false; + } + } + + Point _anchor_point() const + { + return { .x = _policy.x.or_default(0), + .y = _policy.y.or_default(0) }; + } + + Area _area_bounds() const + { + return { .w = _policy.w.or_default(_buffer_attr.px.w), + .h = _policy.h.or_default(_buffer_attr.px.h) }; + } + public: Capture_session(Env &env, @@ -69,7 +149,7 @@ class Nitpicker::Capture_session : public Session_object<Capture::Session> _handler(handler), _view_stack(view_stack) { - _dirty_rect.mark_as_dirty(Rect(Point(0, 0), view_stack.size())); + _dirty_rect.mark_as_dirty(view_stack.bounding_box()); } ~Capture_session() { } @@ -79,48 +159,93 @@ class Nitpicker::Capture_session : public Session_object<Capture::Session> ** Interface used by 'Nitpicker::Main' ** *****************************************/ - Area buffer_size() const { return _buffer_size; } + /** + * Geometry within the panorama, depending on policy and client buffer + */ + Rect bounding_box() const { return { _anchor_point(), _area_bounds() }; } void mark_as_damaged(Rect rect) { - _dirty_rect.mark_as_dirty(rect); + _dirty_rect.mark_as_dirty(Rect::intersect(rect, bounding_box())); } + void process_damage() { _wakeup_if_needed(); } + void screen_size_changed() { if (_screen_size_sigh.valid()) Signal_transmitter(_screen_size_sigh).submit(); } + void apply_policy(Policy const &policy) + { + _policy = policy; + _policy_changed = true; + } + + void gen_capture_attr(Xml_generator &xml, Rect const domain_panorama) const + { + xml.attribute("name", label()); + + gen_attr(xml, Rect::intersect(domain_panorama, bounding_box())); + + unsigned const w_mm = _policy.w_mm.or_default(_buffer_attr.mm.w), + h_mm = _policy.h_mm.or_default(_buffer_attr.mm.h); + + if (w_mm) xml.attribute("width_mm", w_mm); + if (h_mm) xml.attribute("height_mm", h_mm); + } + /******************************* ** Capture session interface ** *******************************/ - Area screen_size() const override { return _view_stack.size(); } + Area screen_size() const override + { + Rect const panorama = _view_stack.bounding_box(); + Rect const policy { _anchor_point(), + { .w = _policy.w.or_default(panorama.w()), + .h = _policy.h.or_default(panorama.h()) } }; + + return Rect::intersect(panorama, policy).area; + } void screen_size_sigh(Signal_context_capability sigh) override { _screen_size_sigh = sigh; } - void buffer(Area size) override + void wakeup_sigh(Signal_context_capability sigh) override { - _buffer_size = Area { }; + _wakeup_sigh = sigh; + _wakeup_if_needed(); + } - if (size.count() == 0) { + Buffer_result buffer(Buffer_attr const attr) override + { + Buffer_result result = Buffer_result::OK; + + _buffer_attr = { }; + + if (!attr.px.valid()) { _buffer.destruct(); - return; + return result; } try { - _buffer.construct(_ram, _env.rm(), buffer_bytes(size)); - _buffer_size = size; - _handler.capture_buffer_size_changed(); - } catch (...) { - _handler.capture_buffer_size_changed(); - throw; + _buffer.construct(_ram, _env.rm(), buffer_bytes(attr.px)); + _buffer_attr = attr; } + catch (Out_of_ram) { result = Buffer_result::OUT_OF_RAM; } + catch (Out_of_caps) { result = Buffer_result::OUT_OF_CAPS; } + + _handler.capture_buffer_size_changed(); + + /* report complete buffer as dirty on next call of 'capture_at' */ + mark_as_damaged({ _anchor_point(), attr.px }); + + return result; } Dataspace_capability dataspace() override @@ -131,16 +256,27 @@ class Nitpicker::Capture_session : public Session_object<Capture::Session> return Dataspace_capability(); } - Affected_rects capture_at(Point pos) override + Affected_rects capture_at(Point const pos) override { + _handler.capture_requested(label()); + if (!_buffer.constructed()) return Affected_rects { }; - using Pixel = Pixel_rgb888; + Point const anchor = _anchor_point() + pos; - Canvas<Pixel> canvas = { _buffer->local_addr<Pixel>(), pos, _buffer_size }; + Canvas<Pixel_rgb888> canvas { _buffer->local_addr<Pixel_rgb888>(), + anchor, _buffer_attr.px }; - Rect const buffer_rect(Point(0, 0), _buffer_size); + if (_policy_changed) { + canvas.draw_box({ anchor, canvas.size() }, Color::rgb(0, 0, 0)); + _dirty_rect.mark_as_dirty({ anchor, canvas.size() }); + _policy_changed = false; + } + + canvas.clip(Rect::intersect(bounding_box(), _view_stack.bounding_box())); + + Rect const buffer_rect { { }, _buffer_attr.px }; Affected_rects affected { }; unsigned i = 0; @@ -149,7 +285,7 @@ class Nitpicker::Capture_session : public Session_object<Capture::Session> _view_stack.draw(canvas, rect); if (i < Affected_rects::NUM_RECTS) { - Rect const translated(rect.p1() - pos, rect.area); + Rect const translated(rect.p1() - anchor, rect.area); Rect const clipped = Rect::intersect(translated, buffer_rect); affected.rects[i++] = clipped; } @@ -157,6 +293,14 @@ class Nitpicker::Capture_session : public Session_object<Capture::Session> return affected; } + + void capture_stopped() override + { + _stopped = true; + + /* dirty pixels may be pending */ + _wakeup_if_needed(); + } }; #endif /* _CAPTURE_SESSION_H_ */ diff --git a/repos/os/src/server/nitpicker/chunky_texture.h b/repos/os/src/server/nitpicker/chunky_texture.h index 6b39d4c274..04427c8a61 100644 --- a/repos/os/src/server/nitpicker/chunky_texture.h +++ b/repos/os/src/server/nitpicker/chunky_texture.h @@ -14,6 +14,9 @@ #ifndef _CHUNKY_TEXTURE_H_ #define _CHUNKY_TEXTURE_H_ +/* Genode includes */ +#include <blit/painter.h> + /* local includes */ #include <buffer.h> @@ -21,53 +24,80 @@ namespace Nitpicker { template <typename> class Chunky_texture; } template <typename PT> -class Nitpicker::Chunky_texture : public Buffer, public Texture<PT> +class Nitpicker::Chunky_texture : Buffer, public Texture<PT> { private: + Framebuffer::Mode const _mode; + /** * Return base address of alpha channel or 0 if no alpha channel exists */ - unsigned char *_alpha_base(Area size, bool use_alpha) + static uint8_t *_alpha_base(Buffer &buffer, Framebuffer::Mode mode) { - if (!use_alpha) return 0; + uint8_t *result = nullptr; + mode.with_alpha_bytes(buffer, [&] (Byte_range_ptr const &bytes) { + result = (uint8_t *)bytes.start; }); + return result; + } - /* alpha values come right after the pixel values */ - return (unsigned char *)local_addr() + calc_num_bytes(size, false); + void _with_alpha_texture(auto const &fn) const + { + Buffer const &buffer = *this; + _mode.with_alpha_bytes(buffer, [&] (Byte_range_ptr const &bytes) { + Texture<Pixel_alpha8> texture { (Pixel_alpha8 *)bytes.start, nullptr, _mode.area }; + fn(texture); }); + } + + void _with_input_texture(auto const &fn) const + { + Buffer const &buffer = *this; + _mode.with_input_bytes(buffer, [&] (Byte_range_ptr const &bytes) { + Texture<Pixel_input8> texture { (Pixel_input8 *)bytes.start, nullptr, _mode.area }; + fn(texture); }); + } + + template <typename T> + void _blit_channel(Surface<T> &surface, Texture<T> const &texture, + Rect const from, Point const to) + { + surface.clip({ to, from.area }); + Blit_painter::paint(surface, texture, to - from.p1()); } public: - /** - * Constructor - */ - Chunky_texture(Ram_allocator &ram, Region_map &rm, Area size, bool use_alpha) - : - Buffer(ram, rm, size, calc_num_bytes(size, use_alpha)), - Texture<PT>((PT *)local_addr(), - _alpha_base(size, use_alpha), size) { } + using Buffer::cap; - static size_t calc_num_bytes(Area size, bool use_alpha) + Chunky_texture(Ram_allocator &ram, Region_map &rm, Framebuffer::Mode mode) + : + Buffer(ram, rm, mode.num_bytes()), + Texture<PT>((PT *)Buffer::bytes().start, _alpha_base(*this, mode), mode.area), + _mode(mode) + { } + + void with_input_mask(auto const &fn) const { - /* - * If using an alpha channel, the alpha buffer follows the - * pixel buffer. The alpha buffer is followed by an input - * mask buffer. Hence, we have to account one byte per - * alpha value and one byte for the input mask value. - */ - size_t bytes_per_pixel = sizeof(PT) + (use_alpha ? 2 : 0); - return bytes_per_pixel*size.count(); + Buffer const &buffer = *this; + _mode.with_input_bytes(buffer, [&] (Byte_range_ptr const &bytes) { + Const_byte_range_ptr const_bytes { bytes.start, bytes.num_bytes }; + fn(const_bytes); }); } - unsigned char const *input_mask_buffer() const + void blit(Rect from, Point to) { - if (!Texture<PT>::alpha()) return 0; + Buffer &buffer = *this; - Area const size = Texture<PT>::size(); + _mode.with_pixel_surface(buffer, [&] (Surface<Pixel_rgb888> &surface) { + _blit_channel(surface, *this, from, to); }); - /* input-mask values come right after the alpha values */ - return (unsigned char const *)local_addr() + calc_num_bytes(size, false) - + size.count(); + _mode.with_alpha_surface(buffer, [&] (Surface<Pixel_alpha8> &surface) { + _with_alpha_texture([&] (Texture<Pixel_alpha8> &texture) { + _blit_channel(surface, texture, from, to); }); }); + + _mode.with_input_surface(buffer, [&] (Surface<Pixel_input8> &surface) { + _with_input_texture([&] (Texture<Pixel_input8> &texture) { + _blit_channel(surface, texture, from, to); }); }); } }; diff --git a/repos/os/src/server/nitpicker/domain_registry.h b/repos/os/src/server/nitpicker/domain_registry.h index 3d20ce40cf..5f68a580a7 100644 --- a/repos/os/src/server/nitpicker/domain_registry.h +++ b/repos/os/src/server/nitpicker/domain_registry.h @@ -64,17 +64,16 @@ class Nitpicker::Domain_registry _origin(origin), _layer(layer), _offset(offset), _area(area) { } - Point _corner(Area const screen_area) const + Point _corner(Rect const rect) const { switch (_origin) { - case Origin::POINTER: return Point(0, 0); - case Origin::TOP_LEFT: return Point(0, 0); - case Origin::TOP_RIGHT: return Point(screen_area.w, 0); - case Origin::BOTTOM_LEFT: return Point(0, screen_area.h); - case Origin::BOTTOM_RIGHT: return Point(screen_area.w, - screen_area.h); + case Origin::POINTER: return { 0, 0 }; + case Origin::TOP_LEFT: return { rect.x1(), rect.y1() }; + case Origin::TOP_RIGHT: return { rect.x2(), rect.y1() }; + case Origin::BOTTOM_LEFT: return { rect.x1(), rect.y2() }; + case Origin::BOTTOM_RIGHT: return { rect.x2(), rect.y2() }; } - return Point(0, 0); + return { 0, 0 }; } public: @@ -95,22 +94,22 @@ class Nitpicker::Domain_registry bool focus_transient() const { return _focus == Focus::TRANSIENT; } bool origin_pointer() const { return _origin == Origin::POINTER; } - Point phys_pos(Point pos, Area screen_area) const + Point phys_pos(Point pos, Rect panorama) const { - return pos + _corner(screen_area) + _offset; + return pos + _corner(panorama) + _offset; } - Area screen_area(Area phys_screen_area) const + Rect screen_rect(Rect const panorama) const { - int const w = _area.x > 0 - ? _area.x - : max(0, (int)phys_screen_area.w + _area.x); + /* align value to zero or to limit, depending on its sign */ + auto aligned = [&] (unsigned limit, int v) + { + return unsigned((v > 0) ? v : max(0, int(limit) + v)); + }; - int const h = _area.y > 0 - ? _area.y - : max(0, (int)phys_screen_area.h + _area.y); - - return Area(w, h); + return { .at = _offset + panorama.at, + .area = { .w = aligned(panorama.w(), _area.x), + .h = aligned(panorama.h(), _area.y) } }; } }; diff --git a/repos/os/src/server/nitpicker/framebuffer_session.h b/repos/os/src/server/nitpicker/framebuffer_session.h index bc6a0e6ec8..72628a13ff 100644 --- a/repos/os/src/server/nitpicker/framebuffer_session.h +++ b/repos/os/src/server/nitpicker/framebuffer_session.h @@ -38,27 +38,33 @@ class Framebuffer::Session_component : public Rpc_object<Session> Session_component(Session_component const &); Session_component &operator = (Session_component const &); + Entrypoint &_ep; View_stack &_view_stack; Nitpicker::Gui_session &_session; Buffer_provider &_buffer_provider; Signal_context_capability _mode_sigh { }; Signal_context_capability _sync_sigh { }; Framebuffer::Mode _mode { }; - bool _alpha = false; public: /** * Constructor */ - Session_component(View_stack &view_stack, + Session_component(Entrypoint &ep, + View_stack &view_stack, Nitpicker::Gui_session &session, Buffer_provider &buffer_provider) : + _ep(ep), _view_stack(view_stack), _session(session), _buffer_provider(buffer_provider) - { } + { + _ep.manage(*this); + } + + ~Session_component() { _ep.dissolve(*this); } /** * Change virtual framebuffer mode @@ -71,10 +77,9 @@ class Framebuffer::Session_component : public Rpc_object<Session> * client calls 'dataspace' the next time, the new mode becomes * effective. */ - void notify_mode_change(Framebuffer::Mode mode, bool alpha) + void notify_mode_change(Framebuffer::Mode mode) { - _mode = mode; - _alpha = alpha; + _mode = mode; if (_mode_sigh.valid()) Signal_transmitter(_mode_sigh).submit(); @@ -93,7 +98,7 @@ class Framebuffer::Session_component : public Rpc_object<Session> Dataspace_capability dataspace() override { - return _buffer_provider.realloc_buffer(_mode, _alpha); + return _buffer_provider.realloc_buffer(_mode); } Mode mode() const override { return _mode; } @@ -108,7 +113,13 @@ class Framebuffer::Session_component : public Rpc_object<Session> _sync_sigh = sigh; } - void refresh(int x, int y, int w, int h) override; + void sync_source(Session_label const &) override { } + + void refresh(Rect) override; + + Blit_result blit(Blit_batch const &) override; + + void panning(Point) override; }; #endif /* _FRAMEBUFFER_SESSION_COMPONENT_H_ */ diff --git a/repos/os/src/server/nitpicker/gui_session.cc b/repos/os/src/server/nitpicker/gui_session.cc index 5b1bd1ce69..6516e1c0bd 100644 --- a/repos/os/src/server/nitpicker/gui_session.cc +++ b/repos/os/src/server/nitpicker/gui_session.cc @@ -64,7 +64,7 @@ void Gui_session::_execute_command(Command const &command) /* transpose position of top-level views by vertical session offset */ if (view.top_level()) - pos = _phys_pos(pos, _view_stack.size()); + pos = _phys_pos(pos, _view_stack.bounding_box()); _view_stack.geometry(view, Rect(pos, args.rect.area)); }); @@ -155,7 +155,10 @@ void Gui_session::_destroy_view(View &view) _view_stack.default_background(_builtin_background); _view_stack.remove_view(view); - _env.ep().dissolve(view); + if (view.cap().valid()) { + _env.ep().dissolve(view); + replenish(Cap_quota { 1 }); + } _view_list.remove(&view); destroy(_view_alloc, &view); } @@ -172,7 +175,7 @@ void Gui_session::submit_input_event(Input::Event e) { using namespace Input; - Point const origin_offset = _phys_pos(Point(0, 0), _view_stack.size()); + Point const origin_offset = _phys_pos({ 0, 0 }, _view_stack.bounding_box()); /* * Transpose absolute coordinates by session-specific vertical offset. @@ -194,7 +197,6 @@ void Gui_session::_adopt_new_view(View &view) view.apply_origin_policy(_pointer_origin); _view_list.insert(&view); - _env.ep().manage(view); } @@ -342,8 +344,17 @@ Gui_session::associate(View_id id, View_capability view_cap) Gui_session::View_capability_result Gui_session::view_capability(View_id id) { return _with_view(id, - [&] (View &view) { return view.cap(); }, - [&] /* view does not exist */ { return View_capability(); }); + [&] (View &view) -> View_capability_result + { + if (!view.cap().valid()) { + if (!try_withdraw(Cap_quota { 1 })) + return View_capability_error::OUT_OF_CAPS; + + _env.ep().manage(view); + } + return view.cap(); + }, + [&] () -> View_capability_result { return View_capability(); }); } @@ -364,30 +375,17 @@ void Gui_session::execute() } -Framebuffer::Mode Gui_session::mode() -{ - Area const screen = screen_area(_view_stack.size()); - - /* - * Return at least a size of 1x1 to spare the clients the need to handle - * the special case of 0x0, which can happen at boot time before the - * framebuffer driver is running. - */ - return { .area = { max(screen.w, 1u), max(screen.h, 1u) } }; -} - - -Gui_session::Buffer_result Gui_session::buffer(Framebuffer::Mode mode, bool use_alpha) +Gui_session::Buffer_result Gui_session::buffer(Framebuffer::Mode mode) { /* check if the session quota suffices for the specified mode */ - if (_buffer_size + _ram_quota_guard().avail().value < ram_quota(mode, use_alpha)) + if (_buffer_size + _ram_quota_guard().avail().value < ram_quota(mode)) return Buffer_result::OUT_OF_RAM; /* buffer re-allocation may consume new dataspace capability if buffer is new */ if (_cap_quota_guard().avail().value < 1) - throw Buffer_result::OUT_OF_CAPS; + return Buffer_result::OUT_OF_CAPS; - _framebuffer_session_component.notify_mode_change(mode, use_alpha); + _framebuffer_session_component.notify_mode_change(mode); return Buffer_result::OK; } @@ -407,9 +405,9 @@ void Gui_session::focus(Capability<Gui::Session> session_cap) } -Dataspace_capability Gui_session::realloc_buffer(Framebuffer::Mode mode, bool use_alpha) +Dataspace_capability Gui_session::realloc_buffer(Framebuffer::Mode mode) { - Ram_quota const next_buffer_size { Chunky_texture<Pixel>::calc_num_bytes(mode.area, use_alpha) }; + Ram_quota const next_buffer_size { mode.num_bytes() }; Ram_quota const orig_buffer_size { _buffer_size }; /* @@ -428,15 +426,13 @@ Dataspace_capability Gui_session::realloc_buffer(Framebuffer::Mode mode, bool us } _buffer_size = 0; - _uses_alpha = false; - _input_mask = nullptr; Ram_quota const temporary_ram_upgrade = _texture.valid() ? next_buffer_size : Ram_quota{0}; _ram_quota_guard().upgrade(temporary_ram_upgrade); - if (!_texture.try_construct_next(_env.ram(), _env.rm(), mode.area, use_alpha)) { + if (!_texture.try_construct_next(_env.ram(), _env.rm(), mode)) { _texture.release_current(); replenish(orig_buffer_size); _ram_quota_guard().try_downgrade(temporary_ram_upgrade); @@ -459,8 +455,16 @@ Dataspace_capability Gui_session::realloc_buffer(Framebuffer::Mode mode, bool us } _buffer_size = next_buffer_size.value; - _uses_alpha = use_alpha; - _input_mask = _texture.input_mask_buffer(); return _texture.dataspace(); } + + +void Gui_session::produce_xml(Xml_generator &xml) +{ + Rect const domain_panorama = + _domain ? _domain->screen_rect(_view_stack.bounding_box()) + : Rect { }; + + _action.gen_capture_info(xml, domain_panorama); +} diff --git a/repos/os/src/server/nitpicker/gui_session.h b/repos/os/src/server/nitpicker/gui_session.h index 1235b51475..a1e2caa09c 100644 --- a/repos/os/src/server/nitpicker/gui_session.h +++ b/repos/os/src/server/nitpicker/gui_session.h @@ -20,8 +20,7 @@ #include <base/heap.h> #include <os/session_policy.h> #include <os/reporter.h> -#include <os/pixel_rgb888.h> -#include <blit/painter.h> +#include <os/dynamic_rom_session.h> #include <gui_session/gui_session.h> /* local includes */ @@ -44,8 +43,22 @@ namespace Nitpicker { class Nitpicker::Gui_session : public Session_object<Gui::Session>, public View_owner, public Buffer_provider, - private Session_list::Element + private Session_list::Element, + private Dynamic_rom_session::Xml_producer, + private Input::Session_component::Action { + public: + + struct Action : Interface + { + /* + * \param rect domain-specific panorama rectangle + */ + virtual void gen_capture_info(Xml_generator &xml, Rect rect) const = 0; + + virtual void exclusive_input_changed() = 0; + }; + private: struct View_ref : Gui::View_ref @@ -87,7 +100,8 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>, Gui_session(Gui_session const &); Gui_session &operator = (Gui_session const &); - Env &_env; + Env &_env; + Action &_action; Constrained_ram_allocator _ram; @@ -96,19 +110,7 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>, Domain_registry::Entry const *_domain = nullptr; View *_background = nullptr; - /* - * The input mask buffer containing a byte value per texture pixel, - * which describes the policy of handling user input referring to the - * pixel. If set to zero, the input is passed through the view such - * that it can be handled by one of the subsequent views in the view - * stack. If set to one, the input is consumed by the view. If - * 'input_mask' is a null pointer, user input is unconditionally - * consumed by the view. - */ - unsigned char const *_input_mask = nullptr; - - bool _uses_alpha = false; - bool _visible = true; + bool _visible = true; Sliced_heap _session_alloc; @@ -117,14 +119,14 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>, bool const _input_session_accounted = ( withdraw(Ram_quota{Input::Session_component::ev_ds_size()}), true ); - Input::Session_component _input_session_component { _env }; + Input::Session_component _input_session_component { _env, *this }; View_stack &_view_stack; Focus_updater &_focus_updater; Hover_updater &_hover_updater; - Signal_context_capability _mode_sigh { }; + Constructible<Dynamic_rom_session> _info_rom { }; View &_pointer_origin; @@ -132,13 +134,20 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>, List<Session_view_list_elem> _view_list { }; - Tslab<View, 4000> _view_alloc { &_session_alloc }; + /* + * Slab allocator that includes an initial block as member + */ + template <size_t BLOCK_SIZE> + struct Initial_slab_block { uint8_t buf[BLOCK_SIZE]; }; + template <typename T, size_t BLOCK_SIZE> + struct Slab : private Initial_slab_block<BLOCK_SIZE>, Tslab<T, BLOCK_SIZE> + { + Slab(Allocator &block_alloc) + : Tslab<T, BLOCK_SIZE>(block_alloc, Initial_slab_block<BLOCK_SIZE>::buf) { }; + }; - Tslab<View_ref, 4000> _view_ref_alloc { &_session_alloc }; - - /* capabilities for sub sessions */ - Framebuffer::Session_capability _framebuffer_session_cap; - Input::Session_capability _input_session_cap; + Slab<View, 4000> _view_alloc { _session_alloc }; + Slab<View_ref, 4000> _view_ref_alloc { _session_alloc }; bool const _provides_default_bg; @@ -160,14 +169,14 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>, Gui_session *_forwarded_focus = nullptr; /** - * Calculate session-local coordinate to physical screen position + * Calculate session-local coordinate to position within panorama * - * \param pos coordinate in session-local coordinate system - * \param screen_area session-local screen size + * \param pos coordinate in session-local coordinate system + * \param rect geometry within panorama */ - Point _phys_pos(Point pos, Area screen_area) const + Point _phys_pos(Point pos, Rect panorama) const { - return _domain ? _domain->phys_pos(pos, screen_area) : Point(0, 0); + return _domain ? _domain->phys_pos(pos, panorama) : Point(0, 0); } void _execute_command(Command const &); @@ -190,9 +199,28 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>, [&] /* ID does not exist */ { return missing_fn(); }); } + /** + * Dynamic_rom_session::Xml_producer interface + */ + void produce_xml(Xml_generator &) override; + + bool _exclusive_input_requested = false; + + /** + * Input::Session_component::Action interface + */ + void exclusive_input_requested(bool const requested) override + { + bool const orig = _exclusive_input_requested; + _exclusive_input_requested = requested; + if (orig != requested) + _action.exclusive_input_changed(); + } + public: Gui_session(Env &env, + Action &action, Resources const &resources, Label const &label, Diag const &diag, @@ -205,25 +233,21 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>, Reporter &focus_reporter) : Session_object(env.ep(), resources, label, diag), - _env(env), + Xml_producer("panorama"), + _env(env), _action(action), _ram(env.ram(), _ram_quota_guard(), _cap_quota_guard()), _session_alloc(_ram, env.rm()), - _framebuffer_session_component(view_stack, *this, *this), + _framebuffer_session_component(env.ep(), view_stack, *this, *this), _view_stack(view_stack), _focus_updater(focus_updater), _hover_updater(hover_updater), _pointer_origin(pointer_origin), _builtin_background(builtin_background), - _framebuffer_session_cap(_env.ep().manage(_framebuffer_session_component)), - _input_session_cap(_env.ep().manage(_input_session_component)), _provides_default_bg(provides_default_bg), _focus_reporter(focus_reporter) { } ~Gui_session() { - _env.ep().dissolve(_framebuffer_session_component); - _env.ep().dissolve(_input_session_component); - while (_view_ids.apply_any<View_ref>([&] (View_ref &view_ref) { destroy(_view_ref_alloc, &view_ref); })); @@ -284,7 +308,7 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>, View const *background() const override { return _background; } - bool uses_alpha() const override { return _texture.valid() && _uses_alpha; } + bool uses_alpha() const override { return _texture.alpha(); } unsigned layer() const override { return _domain ? _domain->layer() : ~0U; } @@ -293,20 +317,28 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>, /** * Return input mask value at specified buffer position */ - unsigned char input_mask_at(Point p) const override + bool input_mask_at(Point const p) const override { - if (!_input_mask || !_texture.valid()) return 0; + bool result = false; + _texture.with_input_mask([&] (Const_byte_range_ptr const &bytes) { - /* check boundaries */ - if ((unsigned)p.x >= _texture.size().w - || (unsigned)p.y >= _texture.size().h) - return 0; + unsigned const x = p.x % _texture.size().w, + y = p.y % _texture.size().h; - return _input_mask[p.y*_texture.size().w + p.x]; + size_t const offset = y*_texture.size().w + x; + if (offset < bytes.num_bytes) + result = bytes.start[offset]; + }); + return result; } void submit_input_event(Input::Event e) override; + bool exclusive_input_requested() const override + { + return _exclusive_input_requested; + } + void report(Xml_generator &xml) const override { xml.attribute("label", _label); @@ -328,16 +360,6 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>, */ void visible(bool visible) { _visible = visible; } - /** - * Return session-local screen area - * - * \param phys_pos size of physical screen - */ - Area screen_area(Area phys_area) const - { - return _domain ? _domain->screen_area(phys_area) : Area(0, 0); - } - void reset_domain() { _domain = nullptr; } /** @@ -355,8 +377,8 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>, */ void notify_mode_change() { - if (_mode_sigh.valid()) - Signal_transmitter(_mode_sigh).submit(); + if (_info_rom.constructed()) + _info_rom->trigger_update(); } /** @@ -373,16 +395,42 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>, _forwarded_focus = nullptr; } + Point panning() const { return _texture.panning; } + /*************************** ** GUI session interface ** ***************************/ Framebuffer::Session_capability framebuffer() override { - return _framebuffer_session_cap; } + return _framebuffer_session_component.cap(); } Input::Session_capability input() override { - return _input_session_cap; } + return _input_session_component.cap(); } + + Info_result info() override + { + if (!_info_rom.constructed()) { + Cap_quota const needed_caps { 2 }; + if (!try_withdraw(needed_caps)) + return Info_error::OUT_OF_CAPS; + + bool out_of_caps = false, out_of_ram = false; + try { + Dynamic_rom_session::Content_producer &rom_producer = *this; + _info_rom.construct(_env.ep(), _ram, _env.rm(), rom_producer); + } + catch (Out_of_ram) { out_of_ram = true; } + catch (Out_of_caps) { out_of_caps = true; } + + if (out_of_ram || out_of_ram) { + replenish(needed_caps); + if (out_of_ram) return Info_error::OUT_OF_RAM; + if (out_of_caps) return Info_error::OUT_OF_CAPS; + } + } + return _info_rom->cap(); + } View_result view(View_id, View_attr const &attr) override; @@ -400,11 +448,7 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>, void execute() override; - Framebuffer::Mode mode() override; - - void mode_sigh(Signal_context_capability sigh) override { _mode_sigh = sigh; } - - Buffer_result buffer(Framebuffer::Mode, bool) override; + Buffer_result buffer(Framebuffer::Mode) override; void focus(Capability<Gui::Session>) override; @@ -413,7 +457,11 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>, ** Buffer_provider interface ** *******************************/ - Dataspace_capability realloc_buffer(Framebuffer::Mode mode, bool use_alpha) override; + Dataspace_capability realloc_buffer(Framebuffer::Mode mode) override; + + void blit(Rect from, Point to) override { _texture.blit(from, to); } + + void panning(Point pos) override { _texture.panning = pos; } }; #endif /* _GUI_SESSION_H_ */ diff --git a/repos/os/src/server/nitpicker/input_session.h b/repos/os/src/server/nitpicker/input_session.h index 02712db8d0..796d06686d 100644 --- a/repos/os/src/server/nitpicker/input_session.h +++ b/repos/os/src/server/nitpicker/input_session.h @@ -32,6 +32,11 @@ class Input::Session_component : public Rpc_object<Session> { public: + struct Action : Interface + { + virtual void exclusive_input_requested(bool) = 0; + }; + enum { MAX_EVENTS = 200 }; static size_t ev_ds_size() { @@ -39,6 +44,9 @@ class Input::Session_component : public Rpc_object<Session> private: + Entrypoint &_ep; + Action &_action; + /* * Exported event buffer dataspace */ @@ -56,10 +64,15 @@ class Input::Session_component : public Rpc_object<Session> public: - Session_component(Env &env) + Session_component(Env &env, Action &action) : + _ep(env.ep()), _action(action), _ev_ram_ds(env.ram(), env.rm(), ev_ds_size()) - { } + { + _ep.manage(*this); + } + + ~Session_component() { _ep.dissolve(*this); } /** * Wake up client @@ -107,6 +120,11 @@ class Input::Session_component : public Rpc_object<Session> } void sigh(Signal_context_capability sigh) override { _sigh = sigh; } + + void exclusive(bool requested) override + { + _action.exclusive_input_requested(requested); + } }; #endif /* _INPUT_SESSION_COMPONENT_H_ */ diff --git a/repos/os/src/server/nitpicker/main.cc b/repos/os/src/server/nitpicker/main.cc index 36f099d7b7..f9749135a3 100644 --- a/repos/os/src/server/nitpicker/main.cc +++ b/repos/os/src/server/nitpicker/main.cc @@ -54,14 +54,33 @@ extern char _binary_default_tff_start[]; ** Framebuffer::Session_component ** ************************************/ -void Framebuffer::Session_component::refresh(int x, int y, int w, int h) +void Framebuffer::Session_component::refresh(Rect rect) { - Rect const rect(Point(x, y), Area(w, h)); - _view_stack.mark_session_views_as_dirty(_session, rect); } +Framebuffer::Session::Blit_result +Framebuffer::Session_component::blit(Blit_batch const &batch) +{ + for (Transfer const &transfer : batch.transfer) { + if (transfer.valid(_mode)) { + _buffer_provider.blit(transfer.from, transfer.to); + Rect const to_rect { transfer.to, transfer.from.area }; + _view_stack.mark_session_views_as_dirty(_session, to_rect); + } + } + return Blit_result::OK; +} + + +void Framebuffer::Session_component::panning(Point pos) +{ + _buffer_provider.panning(pos); + _view_stack.mark_session_views_as_dirty(_session, { { 0, 0 }, _mode.area }); +} + + /*************************************** ** Implementation of the GUI service ** ***************************************/ @@ -71,6 +90,7 @@ class Nitpicker::Gui_root : public Root_component<Gui_session> private: Env &_env; + Gui_session::Action &_action; Attached_rom_dataspace const &_config; Session_list &_session_list; Domain_registry const &_domain_registry; @@ -91,9 +111,16 @@ class Nitpicker::Gui_root : public Root_component<Gui_session> bool const provides_default_bg = (label == "backdrop"); + Genode::Session::Resources resources = session_resources_from_args(args); + + /* account caps for input and framebuffer RPC objects */ + if (resources.cap_quota.value < 2) + throw Insufficient_cap_quota(); + resources.cap_quota.value -= 2; + Gui_session *session = new (md_alloc()) - Gui_session(_env, - session_resources_from_args(args), label, + Gui_session(_env, _action, + resources, label, session_diag_from_args(args), _view_stack, _focus_updater, _hover_updater, _pointer_origin, _builtin_background, provides_default_bg, @@ -144,6 +171,7 @@ class Nitpicker::Gui_root : public Root_component<Gui_session> * Constructor */ Gui_root(Env &env, + Gui_session::Action &action, Attached_rom_dataspace const &config, Session_list &session_list, Domain_registry const &domain_registry, @@ -158,7 +186,7 @@ class Nitpicker::Gui_root : public Root_component<Gui_session> Hover_updater &hover_updater) : Root_component<Gui_session>(&env.ep().rpc_ep(), &md_alloc), - _env(env), _config(config), _session_list(session_list), + _env(env), _action(action), _config(config), _session_list(session_list), _domain_registry(domain_registry), _global_keys(global_keys), _view_stack(view_stack), _user_state(user_state), _pointer_origin(pointer_origin), @@ -175,27 +203,38 @@ class Nitpicker::Gui_root : public Root_component<Gui_session> class Nitpicker::Capture_root : public Root_component<Capture_session> { + public: + + struct Action : Interface + { + virtual void capture_client_appeared_or_disappeared() = 0; + }; + private: using Sessions = Registry<Registered<Capture_session>>; Env &_env; + Action &_action; Sessions _sessions { }; View_stack const &_view_stack; Capture_session::Handler &_handler; - Area _fallback_bounding_box { 0, 0 }; + Rect _fallback_bounding_box { }; protected: Capture_session *_create_session(const char *args) override { - return new (md_alloc()) + Capture_session &session = *new (md_alloc()) Registered<Capture_session>(_sessions, _env, session_resources_from_args(args), session_label_from_args(args), session_diag_from_args(args), _handler, _view_stack); + + _action.capture_client_appeared_or_disappeared(); + return &session; } void _upgrade_session(Capture_session *s, const char *args) override @@ -211,12 +250,11 @@ class Nitpicker::Capture_root : public Root_component<Capture_session> * mode switches when the only capture client temporarily * disappears (driver restart). */ - _fallback_bounding_box = session->buffer_size(); + _fallback_bounding_box = session->bounding_box(); Genode::destroy(md_alloc(), session); - /* shrink screen according to the remaining output back ends */ - _handler.capture_buffer_size_changed(); + _action.capture_client_appeared_or_disappeared(); } public: @@ -225,26 +263,80 @@ class Nitpicker::Capture_root : public Root_component<Capture_session> * Constructor */ Capture_root(Env &env, + Action &action, Allocator &md_alloc, View_stack const &view_stack, Capture_session::Handler &handler) : Root_component<Capture_session>(&env.ep().rpc_ep(), &md_alloc), - _env(env), _view_stack(view_stack), _handler(handler) + _env(env), _action(action), _view_stack(view_stack), _handler(handler) { } - /** - * Determine the size of the bounding box of all capture pixel buffers - */ - Area bounding_box() const + void apply_config(Xml_node const &config) { - Area result = { 0, 0 }; - bool any_session_present = false; - _sessions.for_each([&] (Capture_session const &session) { - any_session_present = true; - result = max_area(result, session.buffer_size()); }); + using Policy = Capture_session::Policy; - return any_session_present ? result : _fallback_bounding_box; + if (config.num_sub_nodes() == 0) { + + /* if no policies are defined, mirror with no constraints */ + _sessions.for_each([&] (Capture_session &session) { + session.apply_policy(Policy::unconstrained()); }); + + } else { + + /* apply constraits per session */ + _sessions.for_each([&] (Capture_session &session) { + with_matching_policy(session.label(), config, + [&] (Xml_node const &policy) { + session.apply_policy(Policy::from_xml(policy)); + }, + [&] { session.apply_policy(Policy::blocked()); }); }); + } + + _sessions.for_each([&] (Capture_session &session) { + session.screen_size_changed(); }); + } + + /** + * Determine the bounding box of all capture clients + */ + Rect bounding_box() const + { + Rect bb { }; + _sessions.for_each([&] (Capture_session const &session) { + bb = Rect::compound(bb, session.bounding_box()); }); + + return bb.valid() ? bb : _fallback_bounding_box; + } + + /** + * Return true if specified position is suited as pointer position + */ + bool visible(Pointer const pointer) const + { + bool result = false; + pointer.with_result( + [&] (Point const p) { + _sessions.for_each([&] (Capture_session const &session) { + if (!result && session.bounding_box().contains(p)) + result = true; }); + if (!result) + result = _fallback_bounding_box.contains(p); + }, + [&] (Nowhere) { }); + return result; + } + + /** + * Return position suitable for the initial pointer position + */ + Pointer any_visible_pointer_position() const + { + Pointer result = Nowhere { }; + _sessions.for_each([&] (Capture_session const &session) { + if (session.bounding_box().valid()) + result = session.bounding_box().center({ 1, 1 }); }); + return result; } /** @@ -262,24 +354,17 @@ class Nitpicker::Capture_root : public Root_component<Capture_session> session.mark_as_damaged(rect); }); } - void report_displays(Xml_generator &xml) const + void process_damage() { - bool any_session_present = false; - _sessions.for_each([&] (Capture_session const &) { - any_session_present = true; }); + _sessions.for_each([&] (Capture_session &session) { + session.process_damage(); }); + } - if (!any_session_present) - return; - - Area const size = bounding_box(); - - if (size.count() == 0) - return; - - xml.node("display", [&] () { - xml.attribute("width", size.w); - xml.attribute("height", size.h); - }); + void report_panorama(Xml_generator &xml, Rect const domain_panorama) const + { + gen_attr(xml, domain_panorama); + _sessions.for_each([&] (Capture_session const &capture) { + xml.node("capture", [&] { capture.gen_capture_attr(xml, domain_panorama); }); }); } }; @@ -335,63 +420,133 @@ class Nitpicker::Event_root : public Root_component<Event_session> struct Nitpicker::Main : Focus_updater, Hover_updater, View_stack::Damage, Capture_session::Handler, - Event_session::Handler + Event_session::Handler, + Capture_root::Action, + User_state::Action, + Gui_session::Action + { Env &_env; Timer::Connection _timer { _env }; - Signal_handler<Main> _timer_handler = { _env.ep(), *this, &Main::_handle_period }; + struct Ticks { uint64_t ms; }; - unsigned long _timer_period_ms = 10; + Ticks _now() { return { .ms = _timer.curr_time().trunc_to_plain_ms().value }; } - Constructible<Framebuffer::Connection> _framebuffer { }; - - struct Input_connection + struct Input_connection : Noncopyable { - Input::Connection connection; + Env &_env; + Main &_main; - Attached_dataspace ev_ds; + Input::Connection _connection { _env }; - Input_connection(Env &env) - : connection(env), ev_ds(env.rm(), connection.dataspace()) { } + Attached_dataspace _ev_ds { _env.rm(), _connection.dataspace() }; + + void _handle() + { + size_t const max_events = _ev_ds.size() / sizeof(Input::Event); + + User_state::Input_batch const batch { + .events = _ev_ds.local_addr<Input::Event>(), + .count = min(max_events, (size_t)_connection.flush()) }; + + _main.handle_input_events(batch); + } + + Signal_handler<Input_connection> _handler { + _env.ep(), *this, &Input_connection::_handle }; + + Input_connection(Env &env, Main &main) : _env(env), _main(main) + { + _connection.sigh(_handler); + } + + ~Input_connection() + { + _connection.sigh(Signal_context_capability()); + } }; Constructible<Input_connection> _input { }; using PT = Pixel_rgb888; /* physical pixel type */ - /* - * Initialize framebuffer - * - * The framebuffer is encapsulated in a volatile object to allow its - * reconstruction at runtime as a response to resolution changes. + /** + * Framebuffer connection used when operating in 'request_framebuffer' mode */ struct Framebuffer_screen { - Framebuffer::Session &framebuffer; + Env &_env; + Main &_main; - Framebuffer::Mode const mode = framebuffer.mode(); + Framebuffer::Connection _fb { _env, { } }; - Attached_dataspace fb_ds; + Framebuffer::Mode const _mode = _fb.mode(); - Canvas<PT> screen = { fb_ds.local_addr<PT>(), Point(0, 0), mode.area }; + Attached_dataspace _fb_ds { _env.rm(), _fb.dataspace() }; - Area size = screen.size(); + Canvas<PT> _screen { _fb_ds.local_addr<PT>(), Point(0, 0), _mode.area }; + + Rect const _rect { { 0, 0 }, _screen.size() }; using Dirty_rect = Genode::Dirty_rect<Rect, 3>; - Dirty_rect dirty_rect { }; + Dirty_rect _dirty_rect { }; - /** - * Constructor - */ - Framebuffer_screen(Region_map &rm, Framebuffer::Session &fb) - : - framebuffer(fb), fb_ds(rm, framebuffer.dataspace()) + Ticks _previous_sync { }; + + Signal_handler<Framebuffer_screen> _sync_handler { + _env.ep(), *this, &Framebuffer_screen::_handle_sync }; + + void _handle_sync() { - dirty_rect.mark_as_dirty(Rect(Point(0, 0), size)); + /* call 'Dirty_rect::flush' on a copy to preserve the state */ + Dirty_rect dirty_rect = _dirty_rect; + dirty_rect.flush([&] (Rect const &rect) { + _main._view_stack.draw(_screen, rect); }); + + bool const any_pixels_refreshed = !_dirty_rect.empty(); + + /* flush pixels to the framebuffer, reset dirty_rect */ + _dirty_rect.flush([&] (Rect const &rect) { + _fb.refresh(rect); }); + + /* deliver framebuffer synchronization events */ + for (Gui_session *s = _main._session_list.first(); s; s = s->next()) + s->submit_sync(); + + if (any_pixels_refreshed) + _previous_sync = _main._now(); } + + Framebuffer_screen(Env &env, Main &main) : _env(env), _main(main) + { + _fb.mode_sigh(_main._fb_screen_mode_handler); + _fb.sync_sigh(_sync_handler); + mark_as_dirty(_rect); + } + + ~Framebuffer_screen() + { + _fb.mode_sigh(Signal_context_capability()); + _fb.sync_sigh(Signal_context_capability()); + } + + void mark_as_dirty(Rect rect) + { + _dirty_rect.mark_as_dirty(rect); + } + + void process_damage() + { + if (_main._now().ms - _previous_sync.ms > 40) + _handle_sync(); + } + + bool visible(Point p) const { return _rect.contains(p); } + + Point anywhere() const { return _rect.center({ 1, 1 }); }; }; bool _request_framebuffer = false; @@ -399,10 +554,33 @@ struct Nitpicker::Main : Focus_updater, Hover_updater, Constructible<Framebuffer_screen> _fb_screen { }; - void _handle_fb_mode(); - void _report_displays(); + bool _visible_at_fb_screen(Pointer pointer) const + { + return pointer.convert<bool>( + [&] (Point p) { return _fb_screen.constructed() && _fb_screen->visible(p); }, + [&] (Nowhere) { return false; }); + } - Signal_handler<Main> _fb_mode_handler = { _env.ep(), *this, &Main::_handle_fb_mode }; + Pointer _anywhere_at_fb_screen() const + { + return _fb_screen.constructed() ? Pointer { _fb_screen->anywhere() } + : Pointer { Nowhere { } }; + } + + Signal_handler<Main> _fb_screen_mode_handler { + _env.ep(), *this, &Main::_reconstruct_fb_screen }; + + void _reconstruct_fb_screen() + { + _fb_screen.destruct(); + + if (_request_framebuffer) + _fb_screen.construct(_env, *this); + + capture_buffer_size_changed(); + } + + void _report_panorama(); /* * User-input policy @@ -426,7 +604,7 @@ struct Nitpicker::Main : Focus_updater, Hover_updater, Focus _focus { }; View_stack _view_stack { _focus, _font, *this }; - User_state _user_state { _focus, _global_keys, _view_stack }; + User_state _user_state { *this, _focus, _global_keys, _view_stack }; View_owner _global_view_owner { }; @@ -447,18 +625,26 @@ struct Nitpicker::Main : Focus_updater, Hover_updater, Reporter _focus_reporter = { _env, "focus" }; Reporter _keystate_reporter = { _env, "keystate" }; Reporter _clicked_reporter = { _env, "clicked" }; - Reporter _displays_reporter = { _env, "displays" }; + Reporter _panorama_reporter = { _env, "panorama" }; Attached_rom_dataspace _config_rom { _env, "config" }; Constructible<Attached_rom_dataspace> _focus_rom { }; - Gui_root _gui_root { _env, _config_rom, _session_list, *_domain_registry, + Gui_root _gui_root { _env, *this, _config_rom, _session_list, *_domain_registry, _global_keys, _view_stack, _user_state, _pointer_origin, _builtin_background, _sliced_heap, _focus_reporter, *this, *this }; - Capture_root _capture_root { _env, _sliced_heap, _view_stack, *this }; + /** + * Gui_session::Action interface + */ + void gen_capture_info(Xml_generator &xml, Rect const domain_panorama) const override + { + _capture_root.report_panorama(xml, domain_panorama); + } + + Capture_root _capture_root { _env, *this, _sliced_heap, _view_stack, *this }; Event_root _event_root { _env, _sliced_heap, *this }; @@ -466,26 +652,39 @@ struct Nitpicker::Main : Focus_updater, Hover_updater, { if (_hover_reporter.enabled()) { Reporter::Xml_generator xml(_hover_reporter, [&] () { - _user_state.report_hovered_view_owner(xml, false); }); + _user_state.report_hovered_view_owner(xml, false); + _user_state.report_pointer_position(xml); + }); } } + Signal_handler<Main> _damage_handler { _env.ep(), *this, &Main::_handle_damage }; + + void _handle_damage() + { + if (_fb_screen.constructed()) + _fb_screen->process_damage(); + + _capture_root.process_damage(); + } + /** * View_stack::Damage interface */ void mark_as_damaged(Rect rect) override { - if (_fb_screen.constructed()) { - _fb_screen->dirty_rect.mark_as_dirty(rect); - } + if (_fb_screen.constructed()) + _fb_screen->mark_as_dirty(rect); _capture_root.mark_as_damaged(rect); + + _damage_handler.local_submit(); } void _update_input_connection() { - bool const output_present = (_view_stack.size().count() > 0); - _input.conditional(_request_input && output_present, _env); + bool const output_present = (_view_stack.bounding_box().valid()); + _input.conditional(_request_input && output_present, _env, *this); } /** @@ -498,33 +697,94 @@ struct Nitpicker::Main : Focus_updater, Hover_updater, * present output back ends. */ - Area new_size { 0, 0 }; + Rect new_bb { }; if (_fb_screen.constructed()) - new_size = max_area(new_size, _fb_screen->size); + new_bb = Rect::compound(new_bb, Rect { _fb_screen->_rect }); - new_size = max_area(new_size, _capture_root.bounding_box()); + new_bb = Rect::compound(new_bb, _capture_root.bounding_box()); - bool const size_changed = (new_size != _view_stack.size()); + bool const size_changed = (new_bb != _view_stack.bounding_box()); if (size_changed) { - _view_stack.size(new_size); - _user_state.sanitize_pointer_position(); + _view_stack.bounding_box(new_bb); + + if (!_user_state.pointer().ok()) + _user_state.pointer(_capture_root.any_visible_pointer_position()); + _update_pointer_position(); _capture_root.screen_size_changed(); /* redraw */ _view_stack.update_all_views(); - - /* notify clients about the change screen mode */ - for (Gui_session *s = _session_list.first(); s; s = s->next()) - s->notify_mode_change(); } - _report_displays(); + /* notify GUI clients about the mode-info change */ + for (Gui_session *s = _session_list.first(); s; s = s->next()) + s->notify_mode_change(); + + _report_panorama(); _update_input_connection(); } + /** + * Capture_session::Handler interface + */ + void capture_requested(Capture_session::Label const &) override + { + /* deliver video-sync events */ + for (Gui_session *s = _session_list.first(); s; s = s->next()) + s->submit_sync(); + } + + Pointer _any_visible_pointer_position() + { + Pointer const captured_pos = _capture_root.any_visible_pointer_position(); + + return captured_pos.ok() ? captured_pos : _anywhere_at_fb_screen(); + } + + bool _visible(Pointer const p) const + { + return _capture_root.visible(p) || _visible_at_fb_screen(p); + } + + /** + * User_state::Action interface + */ + Pointer sanitized_pointer_position(Pointer const orig_pos, Point pos) override + { + auto for_each_value = [] (int const from, int const to, auto const &fn) + { + int const step = (from < to) ? 1 : -1; + for (int i = from; i != to; i += step) + fn(i); + }; + + if (_visible(pos)) + return pos; + + /* move pointer along screen edge */ + if (orig_pos.ok()) { + Point best = orig_pos.convert<Point>( + [&] (Point p) { return p; }, + [&] (Nowhere) { return Point { }; }); + + /* panorama change may have made area around the pointer invisible */ + if (!_visible(best)) + return _any_visible_pointer_position(); + + auto try_better = [&] (Point p) { if (_visible(p)) best = p; }; + + for_each_value(best.x, pos.x, [&] (int x) { try_better({ x, best.y }); }); + for_each_value(best.y, pos.y, [&] (int y) { try_better({ best.x, y }); }); + + return best; + } + + return _any_visible_pointer_position(); + } + /** * Focus_updater interface * @@ -551,15 +811,41 @@ struct Nitpicker::Main : Focus_updater, Hover_updater, * manually to turn the initial configuration into effect. */ void _handle_config(); + void _apply_capture_config(); - Signal_handler<Main> _config_handler = { _env.ep(), *this, &Main::_handle_config }; + Signal_handler<Main> _config_handler { _env.ep(), *this, &Main::_handle_config }; + + /** + * Capture_root::Action interface + */ + void capture_client_appeared_or_disappeared() override + { + _apply_capture_config(); + capture_buffer_size_changed(); + } + + bool _exclusive_input = false; + + /** + * Input::Session_component::Action interface + */ + void exclusive_input_changed() override + { + if (_user_state.exclusive_input() != _exclusive_input) { + _exclusive_input = _user_state.exclusive_input(); + + /* toggle pointer visibility */ + _update_pointer_position(); + _view_stack.update_all_views(); + } + } /** * Signal handler for externally triggered focus changes */ void _handle_focus(); - Signal_handler<Main> _focus_handler = { _env.ep(), *this, &Main::_handle_focus }; + Signal_handler<Main> _focus_handler { _env.ep(), *this, &Main::_handle_focus }; /** * Event_session::Handler interface @@ -578,45 +864,28 @@ struct Nitpicker::Main : Focus_updater, Hover_updater, void _update_motion_and_focus_activity_reports(); /** - * Signal handler periodically invoked for the reception of user input and redraw + * Track when the user was active the last time */ - void _handle_period(); - - Signal_handler<Main> _input_period = { _env.ep(), *this, &Main::_handle_period }; + Ticks _last_button_activity { }, + _last_motion_activity { }; /** - * Counter that is incremented periodically + * Number of milliseconds since the last user interaction, after which + * we regard the user as inactive */ - unsigned _period_cnt = 0; - - /** - * Period counter when the user was active the last time - */ - unsigned _last_button_activity_period = 0, - _last_motion_activity_period = 0; - - /** - * Number of periods after the last user activity when we regard the user - * as becoming inactive - */ - unsigned const _activity_threshold = 50; - - /** - * True if the user has recently interacted with buttons or keys - * - * This state is reported as part of focus reports to allow the clipboard - * to dynamically adjust its information-flow policy to the user activity. - */ - bool _button_activity = false; - - /** - * True if the user recently moved the pointer - */ - bool _motion_activity = false; + Ticks const _activity_threshold { .ms = 500 }; void _update_pointer_position() { - _view_stack.geometry(_pointer_origin, Rect(_user_state.pointer_pos(), Area{})); + /* move pointer out of the way while a client receives exclusive input */ + if (_user_state.exclusive_input()) { + _view_stack.geometry(_pointer_origin, Rect { { -1000*1000, 0 }, { } }); + return; + } + _user_state.pointer().with_result( + [&] (Point p) { + _view_stack.geometry(_pointer_origin, Rect(p, Area{})); }, + [&] (Nowhere) { }); } Main(Env &env) : _env(env) @@ -629,9 +898,7 @@ struct Nitpicker::Main : Focus_updater, Hover_updater, _config_rom.sigh(_config_handler); _handle_config(); - _timer.sigh(_timer_handler); - - _handle_fb_mode(); + _reconstruct_fb_screen(); _env.parent().announce(_env.ep().manage(_gui_root)); @@ -641,32 +908,22 @@ struct Nitpicker::Main : Focus_updater, Hover_updater, if (_config_rom.xml().has_sub_node("event")) _env.parent().announce(_env.ep().manage(_event_root)); - /* - * Detect initial motion activity such that the first hover report - * contains the boot-time activity of the user in the very first - * report. - */ - _handle_period(); + _update_motion_and_focus_activity_reports(); - _report_displays(); + _report_panorama(); } }; void Nitpicker::Main::handle_input_events(User_state::Input_batch batch) { + Ticks const now = _now(); + User_state::Handle_input_result const result = _user_state.handle_input_events(batch); - if (result.button_activity) { - _last_button_activity_period = _period_cnt; - _button_activity = true; - } - - if (result.motion_activity) { - _last_motion_activity_period = _period_cnt; - _motion_activity = true; - } + if (result.button_activity) _last_button_activity = now; + if (result.motion_activity) _last_motion_activity = now; /* * Report information about currently pressed keys whenever the key state @@ -703,74 +960,39 @@ void Nitpicker::Main::handle_input_events(User_state::Input_batch batch) /* update pointer position */ if (result.motion_activity) _update_pointer_position(); + + _update_motion_and_focus_activity_reports(); } void Nitpicker::Main::_update_motion_and_focus_activity_reports() { - /* flag user as inactive after activity threshold is reached */ - if (_period_cnt == _last_button_activity_period + _activity_threshold) - _button_activity = false; + Ticks const now = _now(); - if (_period_cnt == _last_motion_activity_period + _activity_threshold) - _motion_activity = false; + bool const button_activity = (now.ms - _last_button_activity.ms < _activity_threshold.ms); + bool const motion_activity = (now.ms - _last_motion_activity.ms < _activity_threshold.ms); bool const hover_changed = (_reported_hover_count != _hover_count); - if (hover_changed || (_reported_motion_activity != _motion_activity)) { - Reporter::Xml_generator xml(_hover_reporter, [&] () { - _user_state.report_hovered_view_owner(xml, _motion_activity); }); + if (hover_changed || (_reported_motion_activity != motion_activity)) { + Reporter::Xml_generator xml(_hover_reporter, [&] { + _user_state.report_hovered_view_owner(xml, motion_activity); + _user_state.report_pointer_position(xml); + }); } bool const focus_changed = (_reported_focus_count != _focus_count); - if (focus_changed || (_reported_button_activity != _button_activity)) { - Reporter::Xml_generator xml(_focus_reporter, [&] () { - _user_state.report_focused_view_owner(xml, _button_activity); }); + if (focus_changed || (_reported_button_activity != button_activity)) { + Reporter::Xml_generator xml(_focus_reporter, [&] { + _user_state.report_focused_view_owner(xml, button_activity); }); } - _reported_motion_activity = _motion_activity; - _reported_button_activity = _button_activity; + _reported_motion_activity = motion_activity; + _reported_button_activity = button_activity; _reported_hover_count = _hover_count; _reported_focus_count = _focus_count; } -void Nitpicker::Main::_handle_period() -{ - _period_cnt++; - - /* handle batch of pending events */ - if (_input.constructed()) { - - size_t const max_events = _input->ev_ds.size() / sizeof(Input::Event); - - User_state::Input_batch const batch { - .events = _input->ev_ds.local_addr<Input::Event>(), - .count = min(max_events, (size_t)_input->connection.flush()) }; - - handle_input_events(batch); - } - - _update_motion_and_focus_activity_reports(); - - /* perform redraw */ - if (_framebuffer.constructed() && _fb_screen.constructed()) { - /* call 'Dirty_rect::flush' on a copy to preserve the state */ - Dirty_rect dirty_rect = _fb_screen->dirty_rect; - dirty_rect.flush([&] (Rect const &rect) { - _view_stack.draw(_fb_screen->screen, rect); }); - - /* flush pixels to the framebuffer, reset dirty_rect */ - _fb_screen->dirty_rect.flush([&] (Rect const &rect) { - _framebuffer->refresh(rect.x1(), rect.y1(), - rect.w(), rect.h()); }); - } - - /* deliver framebuffer synchronization events */ - for (Gui_session *s = _session_list.first(); s; s = s->next()) - s->submit_sync(); -} - - /** * Helper function for 'handle_config' */ @@ -809,6 +1031,15 @@ void Nitpicker::Main::_handle_focus() } +void Nitpicker::Main::_apply_capture_config() +{ + /* propagate capture policies */ + _config_rom.xml().with_optional_sub_node("capture", + [&] (Xml_node const &capture) { + _capture_root.apply_config(capture); }); +} + + void Nitpicker::Main::_handle_config() { _config_rom.update(); @@ -830,7 +1061,9 @@ void Nitpicker::Main::_handle_config() configure_reporter(config, _focus_reporter); configure_reporter(config, _keystate_reporter); configure_reporter(config, _clicked_reporter); - configure_reporter(config, _displays_reporter); + configure_reporter(config, _panorama_reporter); + + capture_client_appeared_or_disappeared(); /* update domain registry and session policies */ for (Gui_session *s = _session_list.first(); s; s = s->next()) @@ -873,13 +1106,14 @@ void Nitpicker::Main::_handle_config() /* update focus report since the domain colors might have changed */ Reporter::Xml_generator xml(_focus_reporter, [&] () { - _user_state.report_focused_view_owner(xml, _button_activity); }); + bool const button_activity = (_now().ms - _last_button_activity.ms < _activity_threshold.ms); + _user_state.report_focused_view_owner(xml, button_activity); }); /* update framebuffer output back end */ bool const request_framebuffer = config.attribute_value("request_framebuffer", false); if (request_framebuffer != _request_framebuffer) { _request_framebuffer = request_framebuffer; - _handle_fb_mode(); + _reconstruct_fb_screen(); } /* @@ -893,50 +1127,20 @@ void Nitpicker::Main::_handle_config() } -void Nitpicker::Main::_report_displays() +void Nitpicker::Main::_report_panorama() { - if (!_displays_reporter.enabled()) + if (!_panorama_reporter.enabled()) return; - Reporter::Xml_generator xml(_displays_reporter, [&] () { - if (_fb_screen.constructed()) { - xml.node("display", [&] () { - xml.attribute("width", _fb_screen->size.w); - xml.attribute("height", _fb_screen->size.h); - }); - } + Reporter::Xml_generator xml(_panorama_reporter, [&] () { + if (_fb_screen.constructed()) + xml.node("panorama", [&] { gen_attr(xml, _fb_screen->_rect); }); - _capture_root.report_displays(xml); + _capture_root.report_panorama(xml, _view_stack.bounding_box()); }); } -void Nitpicker::Main::_handle_fb_mode() -{ - if (_request_framebuffer && !_framebuffer.constructed()) { - _framebuffer.construct(_env, Framebuffer::Mode{}); - _framebuffer->mode_sigh(_fb_mode_handler); - _framebuffer->sync_sigh(_timer_handler); - _timer.trigger_periodic(0); - } - - /* reconstruct '_fb_screen' with updated mode */ - if (_request_framebuffer && _framebuffer.constructed()) - _fb_screen.construct(_env.rm(), *_framebuffer); - - if (!_request_framebuffer && _fb_screen.constructed()) - _fb_screen.destruct(); - - if (!_request_framebuffer && _framebuffer.constructed()) - _framebuffer.destruct(); - - if (!_request_framebuffer) - _timer.trigger_periodic(_timer_period_ms*1000); - - capture_buffer_size_changed(); -} - - void Component::construct(Genode::Env &env) { static Nitpicker::Main nitpicker(env); diff --git a/repos/os/src/server/nitpicker/resizeable_texture.h b/repos/os/src/server/nitpicker/resizeable_texture.h index f5b7436cbf..6f8c4a097e 100644 --- a/repos/os/src/server/nitpicker/resizeable_texture.h +++ b/repos/os/src/server/nitpicker/resizeable_texture.h @@ -14,10 +14,6 @@ #ifndef _RESIZEABLE_TEXTURE_H_ #define _RESIZEABLE_TEXTURE_H_ -/* Genode includes */ -#include <blit/painter.h> -#include <os/pixel_alpha8.h> - /* local includes */ #include <chunky_texture.h> @@ -31,17 +27,18 @@ class Nitpicker::Resizeable_texture unsigned _current = 0; - using Constructible_texture = Constructible<Chunky_texture<PT>>; + Constructible<Chunky_texture<PT>> _textures[2] { }; - struct Element : Constructible_texture + static void _with_texture(auto &obj, auto const &fn) { - Element() : Constructible_texture() { } - }; - - Element _textures[2]; + if (obj.valid()) + fn(*obj._textures[obj._current]); + } public: + Point panning { 0, 0 }; + bool valid() const { return _textures[_current].constructed(); } Area size() const @@ -50,14 +47,15 @@ class Nitpicker::Resizeable_texture : Area { }; } + bool alpha() const { return valid() && _textures[_current]->alpha(); } + void release_current() { _textures[_current].destruct(); } - bool try_construct_next(Ram_allocator &ram, Region_map &rm, - Area size, bool use_alpha) + bool try_construct_next(Ram_allocator &ram, Region_map &rm, Framebuffer::Mode mode) { try { unsigned const next = !_current; - _textures[next].construct(ram, rm, size, use_alpha); + _textures[next].construct(ram, rm, mode); return true; } catch (...) { } return false; @@ -102,22 +100,24 @@ class Nitpicker::Resizeable_texture _current = next; } - template <typename FN> - void with_texture(FN const &fn) const - { - if (valid()) - fn(*_textures[_current]); - } + void with_texture(auto const &fn) const { _with_texture(*this, fn); } + void with_texture(auto const &fn) { _with_texture(*this, fn); } Dataspace_capability dataspace() { - return valid() ? _textures[_current]->ds_cap() : Ram_dataspace_capability(); + return valid() ? _textures[_current]->cap() : Ram_dataspace_capability(); } - unsigned char const *input_mask_buffer() const + void with_input_mask(auto const &fn) const { - return valid() ? _textures[_current]->input_mask_buffer() - : nullptr; + if (valid()) + _textures[_current]->with_input_mask(fn); + } + + void blit(Rect from, Point to) + { + with_texture([&] (Chunky_texture<PT> &texture) { + texture.blit(from, to); }); } }; diff --git a/repos/os/src/server/nitpicker/types.h b/repos/os/src/server/nitpicker/types.h index c23723a6fd..2350eace1a 100644 --- a/repos/os/src/server/nitpicker/types.h +++ b/repos/os/src/server/nitpicker/types.h @@ -16,9 +16,9 @@ /* Genode includes */ #include <util/xml_node.h> +#include <util/xml_generator.h> #include <util/color.h> #include <base/allocator.h> -#include <os/pixel_rgb888.h> #include <gui_session/gui_session.h> namespace Nitpicker { @@ -40,6 +40,23 @@ namespace Nitpicker { { return Area(max(a1.w, a2.w), max(a1.h, a2.h)); } + + struct Nowhere { }; + + using Pointer = Attempt<Point, Nowhere>; + + static inline void gen_attr(Xml_generator &xml, Point const point) + { + if (point.x) xml.attribute("xpos", point.x); + if (point.y) xml.attribute("ypos", point.y); + } + + static inline void gen_attr(Xml_generator &xml, Rect const rect) + { + gen_attr(xml, rect.at); + if (rect.w()) xml.attribute("width", rect.w()); + if (rect.h()) xml.attribute("height", rect.h()); + } } #endif /* _TYPES_H_ */ diff --git a/repos/os/src/server/nitpicker/user_state.cc b/repos/os/src/server/nitpicker/user_state.cc index e36e0c01d2..c378f0bfb3 100644 --- a/repos/os/src/server/nitpicker/user_state.cc +++ b/repos/os/src/server/nitpicker/user_state.cc @@ -93,24 +93,27 @@ void User_state::_handle_input_event(Input::Event ev) _last_seq_number.construct(seq); }); /* transparently convert relative into absolute motion event */ - ev.handle_relative_motion([&] (int x, int y) { - - int const ox = _pointer_pos.x, - oy = _pointer_pos.y; - - int const ax = max(0, min((int)_view_stack.size().w - 1, ox + x)), - ay = max(0, min((int)_view_stack.size().h - 1, oy + y)); - - ev = Absolute_motion{ax, ay}; - }); + if (!exclusive_input()) + ev.handle_relative_motion([&] (int x, int y) { + _pointer.with_result( + [&] (Point orig_pos) { + Point const p = orig_pos + Point { x, y }; + ev = Absolute_motion { p.x, p.y }; }, + [&] (Nowhere) { }); }); /* respond to motion events by updating the pointer position */ ev.handle_absolute_motion([&] (int x, int y) { - _pointer_pos = Point(x, y); }); + _try_move_pointer({ x, y }); + + /* enforce sanitized position (prevent move to invisible areas) */ + _pointer.with_result( + [&] (Point p) { ev = Absolute_motion { p.x, p.y }; }, + [&] (Nowhere) { ev = { }; }); + }); /* let pointer position correspond to most recent touch position */ ev.handle_touch([&] (Input::Touch_id, float x, float y) { - _pointer_pos = Point((int)x, (int)y); }); + _try_move_pointer({ int(x), int(y) }); }); /* track key states, drop double press/release events */ { @@ -188,9 +191,11 @@ void User_state::_handle_input_event(Input::Event ev) _focused->submit_input_event(Focus_leave()); if (_hovered) { - _hovered->submit_input_event(Absolute_motion{_pointer_pos.x, - _pointer_pos.y}); - _hovered->submit_input_event(Focus_enter()); + _pointer.with_result( + [&] (Point p) { + _hovered->submit_input_event(Absolute_motion{p.x, p.y}); + _hovered->submit_input_event(Focus_enter()); }, + [&] (Nowhere) { }); } if (_hovered->has_transient_focusable_domain()) { @@ -229,8 +234,17 @@ void User_state::_handle_input_event(Input::Event ev) global_receiver = _global_keys.global_receiver(keycode); if (global_receiver) { + bool const orig_global_key_sequence = _global_key_sequence; _global_key_sequence = true; _input_receiver = global_receiver; + + /* deliver current pointer position at start of key sequence */ + if (orig_global_key_sequence != _global_key_sequence) + _pointer.with_result( + [&] (Point at) { + Absolute_motion motion { at.x, at.y }; + _input_receiver->submit_input_event(motion); }, + [&] (Nowhere) { }); } /* @@ -244,27 +258,37 @@ void User_state::_handle_input_event(Input::Event ev) /* * Deliver event to session */ - bool const forward_to_session = (ev.absolute_motion() || ev.wheel() || - ev.touch() || ev.touch_release() || - ev.seq_number()); + bool const forward_to_session = ev.absolute_motion() || ev.relative_motion() + || ev.touch() || ev.touch_release() + || ev.wheel() || ev.seq_number(); if (forward_to_session) { + View_owner *receiver = _input_receiver; + if (_key_cnt == 0) { - if (_hovered) { + auto abs_motion_receiver = [&] () -> View_owner * + { + if (!_hovered) + return nullptr; - /* - * Unless the domain of the pointed session is configured to - * always receive hover events, we deliver motion events only - * to the focused domain. - */ - if (_hovered->hover_always() - || _hovered->has_same_domain(_focused)) - _hovered->submit_input_event(ev); - } + bool const permitted = _hovered->hover_always() + || _hovered->has_same_domain(_focused); + return permitted ? _hovered : nullptr; + }; - } else if (_input_receiver) - _input_receiver->submit_input_event(ev); + if (ev.absolute_motion()) + receiver = abs_motion_receiver(); + } + + /* + * Route relative motion (exclusive input) to the focused client + */ + if (ev.relative_motion() && _focused) + receiver = _focused; + + if (receiver) + receiver->submit_input_event(ev); } /* @@ -276,7 +300,7 @@ void User_state::_handle_input_event(Input::Event ev) if (!_input_receiver) return; - if (!_mouse_button(key) + if (!_mouse_button(key) || _global_key_sequence || (_hovered && (_hovered->has_focusable_domain() || _hovered->has_same_domain(_focused)))) @@ -295,8 +319,9 @@ void User_state::_handle_input_event(Input::Event ev) update_hover(); - if (_drag && _input_receiver && (_input_receiver != _hovered)) - _input_receiver->submit_input_event(Hover_leave()); + if (_drag || _global_key_sequence) + if (_input_receiver && (_input_receiver != _hovered)) + _input_receiver->submit_input_event(Hover_leave()); _drag = false; @@ -311,7 +336,7 @@ void User_state::_handle_input_event(Input::Event ev) User_state::Handle_input_result User_state::handle_input_events(Input_batch batch) { - Point const old_pointer_pos = _pointer_pos; + Pointer const old_pointer = _pointer; View_owner * const old_hovered = _hovered; View_owner const * const old_focused = _focused; View_owner const * const old_input_receiver = _input_receiver; @@ -389,13 +414,23 @@ User_state::handle_input_events(Input_batch batch) _last_clicked_redeliver = false; } + auto pointer_changed = [&] + { + return old_pointer.convert<bool>( + [&] (Point const old) { + return _pointer.convert<bool>( + [&] (Point const p) { return p != old; }, + [&] (Nowhere) { return true; }); }, + [&] (Nowhere) { return _pointer.ok(); }); + }; + return { .hover_changed = _hovered != old_hovered, .focus_changed = (_focused != old_focused) || (_input_receiver != old_input_receiver), .key_state_affected = key_state_affected, .button_activity = button_activity, - .motion_activity = (_pointer_pos != old_pointer_pos) || touch_occurred, + .motion_activity = pointer_changed() || touch_occurred, .key_pressed = _key_pressed(), .last_clicked_changed = last_clicked_changed }; @@ -411,8 +446,8 @@ void User_state::report_keystate(Xml_generator &xml) const void User_state::report_pointer_position(Xml_generator &xml) const { - xml.attribute("xpos", _pointer_pos.x); - xml.attribute("ypos", _pointer_pos.y); + _pointer.with_result([&] (Point p) { gen_attr(xml, p); }, + [&] (Nowhere) { }); } @@ -486,9 +521,12 @@ User_state::Update_hover_result User_state::update_hover() return { .hover_changed = false }; View_owner * const old_hovered = _hovered; - View const * const pointed_view = _view_stack.find_view(_pointer_pos); - _hovered = pointed_view ? &pointed_view->owner() : nullptr; + _hovered = _pointer.convert<View_owner *>( + [&] (Point const p) { + View const * const pointed_view = _view_stack.find_view(p); + return pointed_view ? &pointed_view->owner() : nullptr; }, + [&] (Nowhere) { return nullptr; }); /* * Deliver a leave event if pointed-to session changed, notify newly @@ -499,8 +537,10 @@ User_state::Update_hover_result User_state::update_hover() old_hovered->submit_input_event(Hover_leave()); if (_hovered) - _hovered->submit_input_event(Absolute_motion{_pointer_pos.x, - _pointer_pos.y}); + _pointer.with_result( + [&] (Point p) { + _hovered->submit_input_event(Absolute_motion{p.x, p.y}); }, + [&] (Nowhere) { }); } return { .hover_changed = (_hovered != old_hovered) }; diff --git a/repos/os/src/server/nitpicker/user_state.h b/repos/os/src/server/nitpicker/user_state.h index 821017f027..7a852d4f07 100644 --- a/repos/os/src/server/nitpicker/user_state.h +++ b/repos/os/src/server/nitpicker/user_state.h @@ -29,6 +29,19 @@ namespace Nitpicker { class User_state; } class Nitpicker::User_state { + public: + + struct Action : Interface + { + /** + * Return the pointer position when attempting to move to 'pos' + * + * This policy hook enables the restriction of pointer movements + * to those areas that are captured. + */ + virtual Pointer sanitized_pointer_position(Pointer orig, Point pos) = 0; + }; + private: /* @@ -65,6 +78,8 @@ class Nitpicker::User_state */ bool _focus_via_click = true; + Action &_action; + /** * Input-focus information propagated to the view stack */ @@ -80,16 +95,10 @@ class Nitpicker::User_state */ View_stack &_view_stack; - /** - * True once the initial screen size becomes known and used as the - * initial (centered) pointer position. - */ - bool _initial_pointer_position_defined = false; - /* * Current pointer position */ - Point _pointer_pos { }; + Pointer _pointer = Nowhere { }; /* * Currently pointed-at view owner @@ -199,6 +208,11 @@ class Nitpicker::User_state } } + void _try_move_pointer(Point next) + { + _pointer = _action.sanitized_pointer_position(_pointer, next); + } + public: /** @@ -207,29 +221,16 @@ class Nitpicker::User_state * \param focus exported focus information, to be consumed by the * view stack to tailor its view drawing operations */ - User_state(Focus &focus, Global_keys &global_keys, View_stack &view_stack) + User_state(Action &action, Focus &focus, Global_keys &global_keys, + View_stack &view_stack) : - _focus(focus), _global_keys(global_keys), _view_stack(view_stack) + _action(action), _focus(focus), _global_keys(global_keys), + _view_stack(view_stack) { } - /** - * Called whenever the view-stack size has changed - */ - void sanitize_pointer_position() - { - Area const screen_size = _view_stack.size(); + void pointer(Pointer p) { _pointer = p; } - /* center pointer initially */ - if (!_initial_pointer_position_defined) { - _pointer_pos = Point(screen_size.w/2, screen_size.h/2); - _initial_pointer_position_defined = true; - } - - /* ensure that pointer remains within screen boundaries */ - if (screen_size.count() > 0) - _pointer_pos = Point(min((int)screen_size.w - 1, _pointer_pos.x), - min((int)screen_size.h - 1, _pointer_pos.y)); - } + Pointer pointer() const { return _pointer; } /**************************************** @@ -251,6 +252,12 @@ class Nitpicker::User_state Handle_input_result handle_input_events(Input_batch); + bool exclusive_input() const + { + return (_focused && _focused->exclusive_input_requested()) + || (_input_receiver && _input_receiver->exclusive_input_requested()); + } + /** * Discard all references to specified view owner */ @@ -272,8 +279,6 @@ class Nitpicker::User_state void report_focused_view_owner(Xml_generator &, bool button_active) const; void report_last_clicked_view_owner(Xml_generator &) const; - Point pointer_pos() { return _pointer_pos; } - /** * Enable/disable direct focus changes by clicking on a client */ diff --git a/repos/os/src/server/nitpicker/view.cc b/repos/os/src/server/nitpicker/view.cc index 1a580886cd..694a73e406 100644 --- a/repos/os/src/server/nitpicker/view.cc +++ b/repos/os/src/server/nitpicker/view.cc @@ -11,8 +11,6 @@ * under the terms of the GNU Affero General Public License version 3. */ -#include <os/pixel_rgb888.h> - #include <nitpicker_gfx/texture_painter.h> #include <nitpicker_gfx/box_painter.h> @@ -126,9 +124,32 @@ void Nitpicker::View::draw(Canvas_base &canvas, Font const &font, Focus const &f owner_color.g >> 1, owner_color.b >> 1); + auto for_each_tile_pos = [&] (auto const &fn) + { + int const view_w = view_rect.w(), + view_h = view_rect.h(); + + int const texture_w = int(_texture.size().w), + texture_h = int(_texture.size().h); + + if (!texture_w || !texture_h) + return; + + int off_x = (_buffer_off.x - _texture.panning.x) % texture_w; + int off_y = (_buffer_off.y - _texture.panning.y) % texture_h; + + if (off_x > 0) off_x -= texture_w; + if (off_y > 0) off_y -= texture_h; + + for (int y = off_y; y < view_h; y += texture_h) + for (int x = off_x; x < view_w; x += texture_w) + fn(Point { x, y }); + }; + _texture.with_texture([&] (Texture_base const &texture) { - canvas.draw_texture(_buffer_off + view_rect.p1(), texture, op, - mix_color, allow_alpha); }); + for_each_tile_pos([&] (Point const pos) { + canvas.draw_texture(view_rect.p1() + pos, texture, op, + mix_color, allow_alpha); }); }); if (!_texture.valid()) canvas.draw_box(view_rect, Color::black()); @@ -163,7 +184,7 @@ bool Nitpicker::View::input_response_at(Point const p) const /* if view uses an alpha channel, check the input mask */ if (_owner.content_client() && _owner.uses_alpha()) - return _owner.input_mask_at(p - view_rect.p1() - _buffer_off); + return _owner.input_mask_at(p - view_rect.p1() - _buffer_off + _texture.panning); return true; } diff --git a/repos/os/src/server/nitpicker/view_owner.h b/repos/os/src/server/nitpicker/view_owner.h index 81b57609bc..6252dfe00c 100644 --- a/repos/os/src/server/nitpicker/view_owner.h +++ b/repos/os/src/server/nitpicker/view_owner.h @@ -82,10 +82,12 @@ struct Nitpicker::View_owner : Interface /** * Return input-mask value at given position */ - virtual unsigned char input_mask_at(Point) const { return 0; } + virtual bool input_mask_at(Point) const { return false; } virtual void submit_input_event(Input::Event) { } + virtual bool exclusive_input_requested() const { return false; } + /** * Produce report with the owner's information */ diff --git a/repos/os/src/server/nitpicker/view_stack.cc b/repos/os/src/server/nitpicker/view_stack.cc index d76235655c..5012f9be34 100644 --- a/repos/os/src/server/nitpicker/view_stack.cc +++ b/repos/os/src/server/nitpicker/view_stack.cc @@ -145,7 +145,7 @@ void View_stack::_place_labels(Rect rect) Rect old = view->label_rect(), best; /* calculate best visible label position */ - Rect rect = Rect::intersect(Rect(Point(), _size), view_rect); + Rect rect = Rect::intersect(_bounding_box, view_rect); if (start) _optimize_label_rec(start, view, rect, &best); /* @@ -239,13 +239,13 @@ void View_stack::geometry(View &view, Rect const rect) * views. The 'refresh_view' function takes care to constrain the * refresh to the actual view geometry. */ - refresh_view(view, Rect(Point(), _size)); + refresh_view(view, _bounding_box); /* change geometry */ view.geometry(Rect(rect)); /* refresh new view geometry */ - refresh_view(view, Rect(Point(), _size)); + refresh_view(view, _bounding_box); Rect const compound = Rect::compound(old_outline, _outline(view)); @@ -259,7 +259,7 @@ void View_stack::buffer_offset(View &view, Point const buffer_off) { view.buffer_off(buffer_off); - refresh_view(view, Rect(Point(), _size)); + refresh_view(view, _bounding_box); } diff --git a/repos/os/src/server/nitpicker/view_stack.h b/repos/os/src/server/nitpicker/view_stack.h index bc3567ca68..510846bc12 100644 --- a/repos/os/src/server/nitpicker/view_stack.h +++ b/repos/os/src/server/nitpicker/view_stack.h @@ -32,7 +32,7 @@ class Nitpicker::View_stack private: - Area _size { }; + Rect _bounding_box { }; Focus &_focus; Font const &_font; List<View_stack_elem> _views { }; @@ -99,11 +99,11 @@ class Nitpicker::View_stack /** * Return size */ - Area size() const { return _size; } + Rect bounding_box() const { return _bounding_box; } - void size(Area size) + void bounding_box(Rect rect) { - _size = size; + _bounding_box = rect; update_all_views(); } @@ -128,10 +128,8 @@ class Nitpicker::View_stack */ void update_all_views() { - Rect const whole_screen(Point(), _size); - - _place_labels(whole_screen); - _damage.mark_as_damaged(whole_screen); + _place_labels(_bounding_box); + _damage.mark_as_damaged(_bounding_box); } /** @@ -151,7 +149,8 @@ class Nitpicker::View_stack * Determine view portion that displays the buffer portion * specified by 'rect'. */ - Point const offset = view->abs_position() + view->buffer_off(); + Point const offset = view->abs_position() + view->buffer_off() + - session.panning(); Rect const r = Rect::intersect(Rect::compound(rect.p1() + offset, rect.p2() + offset), view->abs_geometry()); diff --git a/repos/os/src/server/vfs/main.cc b/repos/os/src/server/vfs/main.cc index 6081b4b15f..5874ea161b 100644 --- a/repos/os/src/server/vfs/main.cc +++ b/repos/os/src/server/vfs/main.cc @@ -782,7 +782,8 @@ class Vfs_server::Root : public Genode::Root_component<Session_component>, void _config_update() { _config_rom.update(); - _vfs_env.root_dir().apply_config(vfs_config()); + _config_rom.xml().with_optional_sub_node("vfs", [&] (Xml_node const &config) { + _vfs_env.root_dir().apply_config(config); }); /* * The VFS configuration change may result in watch notifications diff --git a/repos/os/src/server/vmm/virtio_gpu.cc b/repos/os/src/server/vmm/virtio_gpu.cc index 9214e119ca..81f2025b17 100644 --- a/repos/os/src/server/vmm/virtio_gpu.cc +++ b/repos/os/src/server/vmm/virtio_gpu.cc @@ -43,15 +43,15 @@ void Vmm::Virtio_gpu_queue::notify(Virtio_gpu_device & dev) void Vmm::Virtio_gpu_control_request::_get_display_info() { - Framebuffer::Mode mode = _device.resize(); + Gui::Area const mode = _device.resize(); Display_info_response dir { _desc_range(1) }; memset((void*)dir.base(), 0, Display_info_response::SIZE); dir.write<Control_header::Type>(Control_header::Type::OK_DISPLAY_INFO); dir.write<Display_info_response::X>(0); dir.write<Display_info_response::Y>(0); - dir.write<Display_info_response::Width>(mode.area.w); - dir.write<Display_info_response::Height>(mode.area.h); + dir.write<Display_info_response::Width>(mode.w); + dir.write<Display_info_response::Height>(mode.h); dir.write<Display_info_response::Enabled>(1); dir.write<Display_info_response::Flags>(0); } @@ -195,9 +195,9 @@ void Vmm::Virtio_gpu_control_request::_resource_flush() uint32_t x = rf.read<Resource_flush::X>(); uint32_t y = rf.read<Resource_flush::Y>(); uint32_t w = min(rf.read<Resource_flush::Width>(), - _device._fb_mode.area.w - x); + _device._gui_win.area.w - x); uint32_t h = min(rf.read<Resource_flush::Height>(), - _device._fb_mode.area.h - y); + _device._gui_win.area.h - y); enum { BYTES_PER_PIXEL = Virtio_gpu_device::BYTES_PER_PIXEL }; @@ -218,12 +218,12 @@ void Vmm::Virtio_gpu_control_request::_resource_flush() (res.area.w * y + x) * BYTES_PER_PIXEL); void * dst = (void*)((addr_t)_device._fb_ds->local_addr<void>() + - (_device._fb_mode.area.w * y + x) * BYTES_PER_PIXEL); + (_device._gui_win.area.w * y + x) * BYTES_PER_PIXEL); uint32_t line_src = res.area.w * BYTES_PER_PIXEL; - uint32_t line_dst = _device._fb_mode.area.w * BYTES_PER_PIXEL; + uint32_t line_dst = _device._gui_win.area.w * BYTES_PER_PIXEL; blit(src, line_src, dst, line_dst, w*BYTES_PER_PIXEL, h); - _device._gui.framebuffer.refresh(x, y, w, h); + _device._gui.framebuffer.refresh({ { int(x), int(y) }, { w, h } }); }); } diff --git a/repos/os/src/server/vmm/virtio_gpu.h b/repos/os/src/server/vmm/virtio_gpu.h index 59633d77bd..c5db7da971 100644 --- a/repos/os/src/server/vmm/virtio_gpu.h +++ b/repos/os/src/server/vmm/virtio_gpu.h @@ -296,8 +296,16 @@ class Vmm::Virtio_gpu_device : public Virtio_device<Virtio_gpu_queue, 2> Gui::Connection & _gui; Cpu::Signal_handler<Virtio_gpu_device> _handler; Constructible<Attached_dataspace> _fb_ds { }; - Framebuffer::Mode _fb_mode { _gui.mode() }; - Gui::Top_level_view _view { _gui, { { }, _fb_mode.area } }; + + Gui::Rect _request_gui_window() + { + return _gui.window().convert<Gui::Rect>( + [&] (Gui::Rect rect) { return rect; }, + [&] (Gui::Undefined) { return Gui::Rect { { }, { 640, 480 } }; }); + } + + Gui::Rect _gui_win = _request_gui_window(); + Gui::Top_level_view _view { _gui, _gui_win }; using Area = Genode::Area<>; using Rect = Genode::Rect<>; @@ -446,7 +454,7 @@ class Vmm::Virtio_gpu_device : public Virtio_device<Virtio_gpu_queue, 2> _env(env), _heap(heap), _ram_ds(ram_ds), _gui(gui), _handler(cpu, env.ep(), *this, &Virtio_gpu_device::_mode_change) { - _gui.mode_sigh(_handler); + _gui.info_sigh(_handler); } void buffer_notification() @@ -454,21 +462,21 @@ class Vmm::Virtio_gpu_device : public Virtio_device<Virtio_gpu_queue, 2> _buffer_notification(); } - Framebuffer::Mode resize() + Gui::Area resize() { _fb_ds.destruct(); - _fb_mode = _gui.mode(); - _gui.buffer(_fb_mode, false); + _gui_win = _request_gui_window(); + _gui.buffer({ .area = _gui_win.area, .alpha = false }); - if (_fb_mode.area.count() > 0) + if (_gui_win.valid()) _fb_ds.construct(_env.rm(), _gui.framebuffer.dataspace()); using Command = Gui::Session::Command; - _gui.enqueue<Command::Geometry>(_view.id(), Rect(Point(0, 0), _fb_mode.area)); + _gui.enqueue<Command::Geometry>(_view.id(), _gui_win); _gui.enqueue<Command::Front>(_view.id()); _gui.execute(); - return _gui.mode(); + return _gui_win.area; } }; diff --git a/repos/os/src/test/black_hole/main.cc b/repos/os/src/test/black_hole/main.cc index 7aff1e7afb..1a14e083ec 100644 --- a/repos/os/src/test/black_hole/main.cc +++ b/repos/os/src/test/black_hole/main.cc @@ -261,7 +261,9 @@ class Black_hole_test::Capture_test Capture::Area _screen_size { 1, 1 }; Capture::Pixel _pixels[1]; Surface<Capture::Pixel> _surface { _pixels, _screen_size }; - Capture::Connection::Screen _screen { _connection, _env.rm(), _screen_size }; + Capture::Connection::Screen _screen { _connection, _env.rm(), + { .px = _screen_size, + .mm = { } } }; bool _finished { false }; public: diff --git a/repos/os/src/test/bomb/main.cc b/repos/os/src/test/bomb/main.cc index c791c4df60..e9a8948d7f 100644 --- a/repos/os/src/test/bomb/main.cc +++ b/repos/os/src/test/bomb/main.cc @@ -80,8 +80,10 @@ class Bomb_child : public Child_policy _env.pd().transfer_quota(pd_cap, _ram_quota); } - Pd_session &ref_pd() override { return _env.pd(); } - Pd_session_capability ref_pd_cap() const override { return _env.pd_session_cap(); } + Ram_allocator &session_md_ram() override { return _env.ram(); } + + Pd_account &ref_account() override { return _env.pd(); } + Capability<Pd_account> ref_account_cap() const override { return _env.pd_session_cap(); } Service &_matching_service(Service::Name const &service_name, Session_label const &label) diff --git a/repos/os/src/test/capture/main.cc b/repos/os/src/test/capture/main.cc index 915e248168..bb847c4728 100644 --- a/repos/os/src/test/capture/main.cc +++ b/repos/os/src/test/capture/main.cc @@ -66,7 +66,7 @@ struct Test::Main } } - bool _gui_buffer_init = ( _validate_mode(), _gui.buffer(_mode, false), true ); + bool _gui_buffer_init = ( _validate_mode(), _gui.buffer(_mode), true ); Attached_dataspace _fb_ds { _env.rm(), _gui.framebuffer.dataspace() }; @@ -75,7 +75,7 @@ struct Test::Main Output(Env &env, Allocator &alloc, Xml_node const &config) : _env(env), _alloc(alloc), - _mode({ .area = _area_from_xml(config, Area { }) }) + _mode({ .area = _area_from_xml(config, Area { }), .alpha = false }) { auto view_rect = [&] (Xml_node node) { @@ -113,7 +113,7 @@ struct Test::Main Capture::Connection _capture { _env, "" }; - bool _capture_buffer_init = ( _capture.buffer(_area), true ); + bool _capture_buffer_init = ( _capture.buffer({ .px = _area, .mm = { }}), true ); Attached_dataspace _capture_ds { _env.rm(), _capture.dataspace() }; @@ -164,9 +164,7 @@ struct Test::Main }); affected.for_each_rect([&] (Gui::Rect const rect) { - _output->_gui.framebuffer.refresh(rect.x1(), rect.y1(), - rect.w(), rect.h()); - }); + _output->_gui.framebuffer.refresh(rect); }); }); }); diff --git a/repos/os/src/test/fault_detection/main.cc b/repos/os/src/test/fault_detection/main.cc index 4bc527ac76..1d15d621e4 100644 --- a/repos/os/src/test/fault_detection/main.cc +++ b/repos/os/src/test/fault_detection/main.cc @@ -99,8 +99,10 @@ class Test_child : public Genode::Child_policy Binary_name binary_name() const override { return _binary_name; } - Pd_session &ref_pd() override { return _env.pd(); } - Pd_session_capability ref_pd_cap() const override { return _env.pd_session_cap(); } + Ram_allocator &session_md_ram() override { return _env.pd(); } + + Pd_account &ref_account() override { return _env.pd(); } + Capability<Pd_account> ref_account_cap() const override { return _env.pd_session_cap(); } void init(Cpu_session &cpu, Cpu_session_capability) override { @@ -110,9 +112,9 @@ class Test_child : public Genode::Child_policy void init(Pd_session &pd, Pd_session_capability pd_cap) override { - pd.ref_account(ref_pd_cap()); - ref_pd().transfer_quota(pd_cap, _cap_quota); - ref_pd().transfer_quota(pd_cap, _ram_quota); + pd.ref_account(ref_account_cap()); + ref_account().transfer_quota(pd_cap, _cap_quota); + ref_account().transfer_quota(pd_cap, _ram_quota); /* register handler for unresolvable page faults */ Region_map_client address_space(pd.address_space()); diff --git a/repos/os/src/test/fb_bench/main.cc b/repos/os/src/test/fb_bench/main.cc index 96dfe86e8c..85eea4e704 100644 --- a/repos/os/src/test/fb_bench/main.cc +++ b/repos/os/src/test/fb_bench/main.cc @@ -31,8 +31,8 @@ struct Test Timer::Connection timer { env }; Heap heap { env.ram(), env.rm() }; Framebuffer::Connection fb { env, Framebuffer::Mode { } }; - Attached_dataspace fb_ds { env.rm(), fb.dataspace() }; Framebuffer::Mode const fb_mode { fb.mode() }; + Attached_dataspace fb_ds { env.rm(), fb.dataspace() }; char *buf[2]; Test(Env &env, int id, char const *brief) : env(env), id(id) @@ -107,7 +107,7 @@ struct Blit_test : Test { unsigned kib = 0; uint64_t const start_ms = timer.elapsed_ms(); - unsigned const w = (unsigned)(fb_mode.area.w * fb_mode.bytes_per_pixel()); + unsigned const w = unsigned(fb_mode.area.w * sizeof(Pixel_rgb888)); unsigned const h = fb_mode.area.h; for (unsigned i = 0; timer.elapsed_ms() - start_ms < DURATION_MS; i++) { blit(buf[i % 2], w, fb_ds.local_addr<char>(), w, w, h); @@ -125,7 +125,7 @@ struct Unaligned_blit_test : Test { unsigned kib = 0; uint64_t const start_ms = timer.elapsed_ms(); - unsigned const w = (unsigned)(fb_mode.area.w * fb_mode.bytes_per_pixel()); + unsigned const w = unsigned(fb_mode.area.w * sizeof(Pixel_rgb888)); unsigned const h = fb_mode.area.h; for (unsigned i = 0; timer.elapsed_ms() - start_ms < DURATION_MS; i++) { blit(buf[i % 2] + 2, w, fb_ds.local_addr<char>() + 2, w, w - 2, h); diff --git a/repos/os/src/test/framebuffer/main.cc b/repos/os/src/test/framebuffer/main.cc index f924dd5585..9539906ecb 100644 --- a/repos/os/src/test/framebuffer/main.cc +++ b/repos/os/src/test/framebuffer/main.cc @@ -19,6 +19,7 @@ #include <base/log.h> #include <os/static_root.h> #include <capture_session/capture_session.h> +#include <timer_session/connection.h> #include <base/attached_ram_dataspace.h> #include <util/reconstructible.h> @@ -53,15 +54,38 @@ struct Test::Capture_session : Rpc_object<Capture::Session> State _state = STRIPES; - unsigned long _sync_cnt = 0; - - enum { FRAME_CNT = 200 }; - void _draw(); - void _draw_frame(Pixel *, Pixel, Area); - Capture_session(Env &env) : _env(env) { } + bool _dirty = false; /* true if there is data not yet delivered */ + bool _capture_stopped = false; + + Signal_context_capability _wakeup_sigh { }; + + void _wakeup_if_needed() + { + if (_capture_stopped && _dirty && _wakeup_sigh.valid()) { + Signal_transmitter(_wakeup_sigh).submit(); + _capture_stopped = false; + } + } + + Timer::Connection _timer { _env }; + + Signal_handler<Capture_session> _timer_handler { + _env.ep(), *this, &Capture_session::_handle_timer }; + + void _handle_timer() + { + _dirty = true; + _wakeup_if_needed(); + } + + Capture_session(Env &env) : _env(env) + { + _timer.sigh(_timer_handler); + _timer.trigger_periodic(1000*1000); + } /******************************** @@ -72,11 +96,22 @@ struct Test::Capture_session : Rpc_object<Capture::Session> void screen_size_sigh(Signal_context_capability) override { } - void buffer(Area size) override + void wakeup_sigh(Signal_context_capability sigh) override { _wakeup_sigh = sigh; } + + Buffer_result buffer(Buffer_attr attr) override { - _ds.construct(_env.ram(), _env.rm(), buffer_bytes(size)); - _size = size; + try { + _ds.construct(_env.ram(), _env.rm(), buffer_bytes(attr.px)); + } + catch (Out_of_ram) { return Buffer_result::OUT_OF_RAM; } + catch (Out_of_caps) { return Buffer_result::OUT_OF_CAPS; } + + _size = attr.px; + + log("screen dimension: ", _size); + _draw(); + return Buffer_result::OK; } Dataspace_capability dataspace() override @@ -87,14 +122,15 @@ struct Test::Capture_session : Rpc_object<Capture::Session> Affected_rects capture_at(Point) override { Affected_rects affected { }; - - if (_sync_cnt++ % FRAME_CNT == 0) { + if (_dirty) { _draw(); - affected.rects[0] = Rect(Point(0, 0), _size); + affected.rects[0] = Rect { { }, _size }; + _dirty = false; } - return affected; } + + void capture_stopped() override { _capture_stopped = true; } }; @@ -128,6 +164,11 @@ void Test::Capture_session::_draw_frame(Pixel *p, Pixel c, Area area) /* left and right */ for (unsigned i = 0; i < h; ++i) p[i*w] = p[i*w + w - 1] = c; + + /* 15px marker for (0,0) */ + for (unsigned i = 0; i < 15; i++) + for (unsigned j = 0; j < 15; j++) + p[i*w + j] = c; } diff --git a/repos/os/src/test/nitpicker/main.cc b/repos/os/src/test/nitpicker/main.cc index 49156c8234..d3696ad954 100644 --- a/repos/os/src/test/nitpicker/main.cc +++ b/repos/os/src/test/nitpicker/main.cc @@ -236,11 +236,11 @@ Test::Main::Main(Genode::Env &env) : _env(env) Gui::Area const size { 256, 256 }; - Framebuffer::Mode const mode { .area = size }; + Framebuffer::Mode const mode { .area = size, .alpha = _config.alpha }; log("screen is ", mode); - _gui.buffer(mode, _config.alpha); + _gui.buffer(mode); _fb_ds.construct(_env.rm(), _gui.framebuffer.dataspace()); @@ -265,6 +265,8 @@ Test::Main::Main(Genode::Env &env) : _env(env) } } + _gui.framebuffer.refresh({ { 0, 0 }, size }); + _view_stack.construct(View_stack::Input_mask_ptr { .size = size, .ptr = input_mask }); diff --git a/repos/os/src/test/resource_yield/main.cc b/repos/os/src/test/resource_yield/main.cc index 65cd46ec08..f108b66bc4 100644 --- a/repos/os/src/test/resource_yield/main.cc +++ b/repos/os/src/test/resource_yield/main.cc @@ -304,7 +304,7 @@ class Test::Parent } _config_producer { }; Dynamic_rom_session _config_session { _env.ep().rpc_ep(), - ref_pd(), _env.rm(), + _env.pd(), _env.rm(), _config_producer }; using Config_service = Genode::Local_service<Dynamic_rom_session>; @@ -323,14 +323,16 @@ class Test::Parent Binary_name binary_name() const override { return _binary_name; } - Pd_session &ref_pd() override { return _env.pd(); } - Pd_session_capability ref_pd_cap() const override { return _env.pd_session_cap(); } + Ram_allocator &session_md_ram() override { return _env.pd(); } + + Pd_account &ref_account() override { return _env.pd(); } + Capability<Pd_account> ref_account_cap() const override { return _env.pd_session_cap(); } void init(Pd_session &pd, Pd_session_capability pd_cap) override { - pd.ref_account(ref_pd_cap()); - ref_pd().transfer_quota(pd_cap, _cap_quota); - ref_pd().transfer_quota(pd_cap, _ram_quota); + pd.ref_account(ref_account_cap()); + ref_account().transfer_quota(pd_cap, _cap_quota); + ref_account().transfer_quota(pd_cap, _ram_quota); } Route resolve_session_request(Service::Name const &service_name, diff --git a/repos/os/src/test/vfs_capture/main.cc b/repos/os/src/test/vfs_capture/main.cc index 43b15f7b01..ba3c017be5 100644 --- a/repos/os/src/test/vfs_capture/main.cc +++ b/repos/os/src/test/vfs_capture/main.cc @@ -70,7 +70,7 @@ struct Test::Main } } - bool _gui_buffer_init = ( _validate_mode(), _gui.buffer(_mode, false), true ); + bool _gui_buffer_init = ( _validate_mode(), _gui.buffer(_mode), true ); Attached_dataspace _fb_ds { _env.rm(), _gui.framebuffer.dataspace() }; @@ -79,7 +79,7 @@ struct Test::Main Output(Env &env, Allocator &alloc, Xml_node const &config) : _env(env), _alloc(alloc), - _mode({ .area = _area_from_xml(config, Area { }) }) + _mode({ .area = _area_from_xml(config, Area { }), .alpha = false }) { auto view_rect = [&] (Xml_node node) { @@ -179,9 +179,7 @@ struct Test::Main }); affected.for_each_rect([&] (Gui::Rect const rect) { - _output->_gui.framebuffer.refresh(rect.x1(), rect.y1(), - rect.w(), rect.h()); - }); + _output->_gui.framebuffer.refresh(rect); }); }); }); diff --git a/repos/os/src/test/vmm_x86/component.cc b/repos/os/src/test/vmm_x86/component.cc index c7cfe8c938..3710a75e1e 100644 --- a/repos/os/src/test/vmm_x86/component.cc +++ b/repos/os/src/test/vmm_x86/component.cc @@ -120,8 +120,10 @@ class Vmm::Vcpu void force_fpu_state_transfer(Vcpu_state & state) { /* force FPU-state transfer on next entry */ - state.fpu.charge([] (Vcpu_state::Fpu::State &) { - /* don't change state */ }); + state.fpu.charge([] (Vcpu_state::Fpu::State &state) { + /* don't change state */ + return sizeof(state); + }); } /* diff --git a/repos/pc/recipes/api/pc_linux/hash b/repos/pc/recipes/api/pc_linux/hash index e49691e303..762696e3ba 100644 --- a/repos/pc/recipes/api/pc_linux/hash +++ b/repos/pc/recipes/api/pc_linux/hash @@ -1 +1 @@ -2024-10-10 4ae29018bc6440bb50d92b3ebf0794d955d27c52 +2024-11-19 6b0c4a29deaee9f47a3cdc346c35722e6a818b55 diff --git a/repos/pc/recipes/pkg/pc_nic/hash b/repos/pc/recipes/pkg/pc_nic/hash index f9969510e5..8f8c01dc39 100644 --- a/repos/pc/recipes/pkg/pc_nic/hash +++ b/repos/pc/recipes/pkg/pc_nic/hash @@ -1 +1 @@ -2024-08-28 b2a6bcf47cecaf90bcb08adb24e5de947dbad327 +2024-12-10 d875c67823061bee5cfc61869ab105d82efc3178 diff --git a/repos/pc/recipes/pkg/pc_wifi/hash b/repos/pc/recipes/pkg/pc_wifi/hash index 864a54a200..dab2739ee5 100644 --- a/repos/pc/recipes/pkg/pc_wifi/hash +++ b/repos/pc/recipes/pkg/pc_wifi/hash @@ -1 +1 @@ -2024-08-28 663bb485f69895a0d59cfeb3907174d8a2a19d15 +2024-12-10 ce3ccc1d0cd776550678a498527b7c6ea335f9ca diff --git a/repos/pc/recipes/pkg/test_usb_host-pc/hash b/repos/pc/recipes/pkg/test_usb_host-pc/hash index bfdb2aa062..977595c4ce 100644 --- a/repos/pc/recipes/pkg/test_usb_host-pc/hash +++ b/repos/pc/recipes/pkg/test_usb_host-pc/hash @@ -1 +1 @@ -2024-08-28 268075437cc4a10b44dd0528f7eb0b7a57d9c956 +2024-12-10 7a6b2f11a3448f153b37a599779ae828d8475994 diff --git a/repos/pc/recipes/raw/pc_wifi_firmware/hash b/repos/pc/recipes/raw/pc_wifi_firmware/hash index f9b6eb1884..1bc15e2a94 100644 --- a/repos/pc/recipes/raw/pc_wifi_firmware/hash +++ b/repos/pc/recipes/raw/pc_wifi_firmware/hash @@ -1 +1 @@ -2024-08-28 aa43b665f2d6704235f72ae43490bb4d5b9a066e +2024-10-29 64855e51d95c59c2934c7ff62d3a95c27334c43b diff --git a/repos/pc/recipes/src/pc_intel_fb/hash b/repos/pc/recipes/src/pc_intel_fb/hash index 5dc15cd732..44a3aaed51 100644 --- a/repos/pc/recipes/src/pc_intel_fb/hash +++ b/repos/pc/recipes/src/pc_intel_fb/hash @@ -1 +1 @@ -2024-08-28 82da7198675b5adce9804848eec840552d002678 +2024-12-10 f05a2460a0de3349e7827038eb9f34c78094ba51 diff --git a/repos/pc/recipes/src/pc_nic/hash b/repos/pc/recipes/src/pc_nic/hash index 940b73b2cd..ca7fb8ad97 100644 --- a/repos/pc/recipes/src/pc_nic/hash +++ b/repos/pc/recipes/src/pc_nic/hash @@ -1 +1 @@ -2024-11-08 25b4febdcbd15730077ff457a20c6fa83107033b +2024-12-10 399d8a47dd66c8ee3b5fcee9a19e218ec0f8a14e diff --git a/repos/pc/recipes/src/pc_platform/hash b/repos/pc/recipes/src/pc_platform/hash index 1fd7397f8a..8bdf5ebe25 100644 --- a/repos/pc/recipes/src/pc_platform/hash +++ b/repos/pc/recipes/src/pc_platform/hash @@ -1 +1 @@ -2024-08-28 43c56f099802141a7cefa3fc5f643c6e6375e645 +2024-12-10 409516884d60906fbd4ae0cddf575e308d52786d diff --git a/repos/pc/recipes/src/pc_usb_host/hash b/repos/pc/recipes/src/pc_usb_host/hash index 105dc061de..aa31e77103 100644 --- a/repos/pc/recipes/src/pc_usb_host/hash +++ b/repos/pc/recipes/src/pc_usb_host/hash @@ -1 +1 @@ -2024-08-28 6a457bbf43cd27a863aa0e341d9e161b4d3139bf +2024-12-10 0c87191e64f5c6d42643edee7889c94a35615b88 diff --git a/repos/pc/recipes/src/pc_wifi/hash b/repos/pc/recipes/src/pc_wifi/hash index dd7e6643f1..21def5cdb2 100644 --- a/repos/pc/recipes/src/pc_wifi/hash +++ b/repos/pc/recipes/src/pc_wifi/hash @@ -1 +1 @@ -2024-08-28 debac2bfadd4661a848aa4c444f770f45b1a5038 +2024-12-10 e7cf591c82063556c76a8555efeb8b62709f288c diff --git a/repos/pc/run/intel_fb.run b/repos/pc/run/intel_fb.run index 8c4e860298..eeb4457638 100644 --- a/repos/pc/run/intel_fb.run +++ b/repos/pc/run/intel_fb.run @@ -26,10 +26,6 @@ if {$use_fb_controller} { set apply_on_hotplug "yes" } -if {$use_usb} { - import_from_depot [depot_user]/src/pc_usb_host -} - import_from_depot [depot_user]/src/fs_rom \ [depot_user]/src/vfs \ [depot_user]/src/vfs_import \ @@ -44,6 +40,7 @@ set build_components { test/framebuffer } +append_if $use_usb build_components { driver/usb_host } append_if $use_gpu build_components { driver/gpu/intel } append_if $use_top build_components { app/top } @@ -71,7 +68,12 @@ append config { </default-route> <default caps="100"/> - <start name="report_rom" caps="100"> + <start name="timer"> + <resource name="RAM" quantum="1M"/> + <provides><service name="Timer"/></provides> + </start> + + <start name="report_rom" caps="100" priority="-1"> <resource name="RAM" quantum="2M"/> <provides> <service name="ROM" /> @@ -90,7 +92,7 @@ append config { </route> </start> - <start name="acpi" caps="250"> + <start name="acpi" caps="250" priority="-1"> <resource name="RAM" quantum="6M"/> <route> <service name="IO_MEM"> <parent/> </service> @@ -103,7 +105,7 @@ append config { </route> </start> - <start name="pci_decode" caps="350"> + <start name="pci_decode" caps="350" priority="-1"> <resource name="RAM" quantum="2M"/> <route> <service name="Report"> @@ -119,7 +121,7 @@ append config { </route> </start> - <start name="platform" caps="100" managing_system="yes"> + <start name="platform" caps="100" managing_system="yes" priority="-1"> <resource name="RAM" quantum="2M"/> <provides> <service name="Platform"/> </provides> <route> @@ -146,14 +148,20 @@ append config { <pci class="USB"/> </policy> </config> - </start> + </start>} - <start name="timer"> - <resource name="RAM" quantum="1M"/> - <provides><service name="Timer"/></provides> - </start> +append_if $use_top config { + <start name="top" priority="-1"> + <resource name="RAM" quantum="2M"/> + <config period_ms="40000"/> + <route> + <service name="TRACE"> <parent label=""/> </service> + <any-service> <parent/> <any-child/> </any-service> + </route> + </start>} - <start name="init_dynamic" caps="10000"> +append config { + <start name="init_dynamic" caps="10000" priority="-2"> <binary name="init"/> <resource name="RAM" quantum="1000M"/> <route> @@ -184,16 +192,6 @@ append config { <default caps="100"/> <report init_ram="yes" child_ram="yes" delay_ms="10000"/>} -append_if $use_top config { - <start name="top"> - <resource name="RAM" quantum="2M"/> - <config period_ms="40000"/> - <route> - <service name="TRACE"> <parent label=""/> </service> - <any-service> <parent/> <any-child/> </any-service> - </route> - </start>} - append config { <start name="report_rom" priority="-1"> <resource name="RAM" quantum="2M"/> @@ -222,6 +220,13 @@ append config { <inline name="fb.config"> <config ld_verbose="yes" apply_on_hotplug="} $apply_on_hotplug {"> <report connectors="yes"/> + <merge name="mirror"> + <!-- all connectors in merge node gets mirrored --> +<!-- + <connector name="DP-1"/> + <connector name="HDMI-A-1"/> +--> + </merge> </config> </inline> </import> @@ -269,7 +274,7 @@ append_if $use_gpu config { append config { <start name="intel_fb" caps="1000"> <binary name="pc_intel_fb"/> - <resource name="RAM" quantum="90M"/> + <resource name="RAM" quantum="128M"/> <route>} append_if $use_gpu config { @@ -279,6 +284,18 @@ append config { <service name="ROM" label="config"> <child name="config_rom" label="fb.config"/> </service> <service name="Report"> <child name="report_rom"/> </service> + + <service name="Capture" label="eDP-1"> <child name="test-framebuffer-eDP-1"/> </service> + <service name="Capture" label="HDMI-A-1"> <child name="test-framebuffer-HDMI-A-1"/> </service> + <service name="Capture" label="HDMI-A-2"> <child name="test-framebuffer-HDMI-A-2"/> </service> + <service name="Capture" label="HDMI-A-3"> <child name="test-framebuffer-HDMI-A-3"/> </service> + <service name="Capture" label="DP-1"> <child name="test-framebuffer-DP-1"/> </service> + <service name="Capture" label="DP-2"> <child name="test-framebuffer-DP-2"/> </service> + <service name="Capture" label="DP-3"> <child name="test-framebuffer-DP-3"/> </service> + <service name="Capture" label="DP-4"> <child name="test-framebuffer-DP-4"/> </service> + <service name="Capture" label="VGA-1"> <child name="test-framebuffer-VGA-1"/> </service> + <service name="Capture" label="mirror"> <child name="test-framebuffer-mirror"/> </service> + <any-service> <parent/> <any-child /> </any-service> </route> </start>} @@ -312,7 +329,62 @@ append_if $use_fb_controller config { </start>} append config { - <start name="test-framebuffer" priority="-1"> + <start name="test-framebuffer-eDP-1" priority="-1"> + <binary name="test-framebuffer"/> + <resource name="RAM" quantum="10M"/> + <provides> <service name="Capture"/> </provides> + <config/> + </start> + <start name="test-framebuffer-HDMI-A-1" priority="-1"> + <binary name="test-framebuffer"/> + <resource name="RAM" quantum="10M"/> + <provides> <service name="Capture"/> </provides> + <config/> + </start> + <start name="test-framebuffer-HDMI-A-2" priority="-1"> + <binary name="test-framebuffer"/> + <resource name="RAM" quantum="10M"/> + <provides> <service name="Capture"/> </provides> + <config/> + </start> + <start name="test-framebuffer-HDMI-A-3" priority="-1"> + <binary name="test-framebuffer"/> + <resource name="RAM" quantum="10M"/> + <provides> <service name="Capture"/> </provides> + <config/> + </start> + <start name="test-framebuffer-DP-1" priority="-1"> + <binary name="test-framebuffer"/> + <resource name="RAM" quantum="10M"/> + <provides> <service name="Capture"/> </provides> + <config/> + </start> + <start name="test-framebuffer-DP-2" priority="-1"> + <binary name="test-framebuffer"/> + <resource name="RAM" quantum="10M"/> + <provides> <service name="Capture"/> </provides> + <config/> + </start> + <start name="test-framebuffer-DP-3" priority="-1"> + <binary name="test-framebuffer"/> + <resource name="RAM" quantum="10M"/> + <provides> <service name="Capture"/> </provides> + <config/> + </start> + <start name="test-framebuffer-DP-4" priority="-1"> + <binary name="test-framebuffer"/> + <resource name="RAM" quantum="10M"/> + <provides> <service name="Capture"/> </provides> + <config/> + </start> + <start name="test-framebuffer-VGA-1" priority="-1"> + <binary name="test-framebuffer"/> + <resource name="RAM" quantum="10M"/> + <provides> <service name="Capture"/> </provides> + <config/> + </start> + <start name="test-framebuffer-mirror" priority="-1"> + <binary name="test-framebuffer"/> <resource name="RAM" quantum="10M"/> <provides> <service name="Capture"/> </provides> <config/> @@ -326,7 +398,7 @@ install_config $config build_boot_image [build_artifacts] if { [get_cmd_switch --autopilot] } { - run_genode_until {\[init -\> init_dynamic -\> intel_fb\] HDMI-A-3: enable.*} 30 + run_genode_until {\[init -\> init_dynamic -\> intel_fb\].*connector connected="true" name="HDMI-A-3"} 30 run_genode_until {\</connectors\>} 20 [output_spawn_id] run_genode_until {green} 30 [output_spawn_id] } else { diff --git a/repos/pc/run/pc_wifi.run b/repos/pc/run/pc_wifi.run index 64be6b23bd..2ada3eaa53 100644 --- a/repos/pc/run/pc_wifi.run +++ b/repos/pc/run/pc_wifi.run @@ -5,68 +5,7 @@ # set debug_driver false -# -# Configure wireless lan -# - -proc wifi_ssid { } { - return $::env(GENODE_WIFI_SSID) -} - -proc wifi_psk { } { - return $::env(GENODE_WIFI_PSK) -} - -proc wifi_wpa { } { - if {![info exists ::env(GENODE_WIFI_WPA)]} { - return WPA2 - } - return $::env(GENODE_WIFI_WPA) -} - -# -# wifi-driver config generator (supporting a network list) -# -# You may script your tests with this function in the dynamic_rom config below. -# The syntax for the networks parameter is -# -# { ssid protection passphrase explicit_scan } -# -# Example dynamic_rom config: -# -# {<inline description="auto-connect both networks"> -# } [wifi_config 30 5 no [list "net1 WPA2 net1_psk no" "net2 WPA2 net2_psk no"]] { -# </inline> -# <inline description="aquto-connect both, but net2 explicitly"> -# } [wifi_config 30 5 no [list "net1 WPA2 net1_psk no" "net2 WPA2 net2_psk yes"]] { -# </inline>} - -set wifi_verbose false -set wifi_verbose_state false - -proc wifi_config { connected_scan_interval scan_interval rfkill networks } { - global wifi_verbose - global wifi_verbose_state - - set config "<wifi_config" - append config " verbose=\"$wifi_verbose\"" - append config " verbose_state=\"$wifi_verbose_state\"" - append config " connected_scan_interval=\"$connected_scan_interval\"" - append config " scan_interval=\"$scan_interval\"" - append config " rfkill=\"$rfkill\"" - append config ">\n" - foreach n $networks { - append config " <network" - append config " ssid=\"[lindex $n 0]\"" - append config " protection=\"[lindex $n 1]\"" - append config " passphrase=\"[lindex $n 2]\"" - append config " explicit_scan=\"[lindex $n 3]\"" - append config "/>\n" - } - append config "</wifi_config>\n" - - return $config -} +source ${genode_dir}/repos/dde_linux/run/wifi_config.inc # # Restrict platforms @@ -236,19 +175,19 @@ append config { <config verbose="yes"> <rom name="wifi_config"> <inline description="disconnect"> -} [wifi_config 30 5 no {}] { +} [wifi_config 5 10 no {}] { </inline> <sleep milliseconds="15000"/> <inline description="connect"> -} [wifi_config 30 5 no [list "[wifi_ssid] [wifi_wpa] [wifi_psk] yes"]] { +} [wifi_config 5 10 no [list "[wifi_ssid] [wifi_wpa] [wifi_psk] no"]] { </inline> <sleep milliseconds="60000"/> <inline description="rfkill block"> -} [wifi_config 30 5 yes [list "[wifi_ssid] [wifi_wpa] [wifi_psk] yes"]] { +} [wifi_config 5 10 yes [list "[wifi_ssid] [wifi_wpa] [wifi_psk] no"]] { </inline> <sleep milliseconds="30000"/> <inline description="rfkill unblock"> -} [wifi_config 30 5 no [list "[wifi_ssid] [wifi_wpa] [wifi_psk] yes"]] { +} [wifi_config 5 10 no [list "[wifi_ssid] [wifi_wpa] [wifi_psk] no"]] { </inline> <sleep milliseconds="30000"/> </rom> @@ -327,7 +266,7 @@ install_config $config # boot-module assembly # if {$debug_driver} { -exec rm bin/wifi.lib.so +catch {exec rm bin/wifi.lib.so} exec echo dummy > bin/wifi.lib.so } diff --git a/repos/pc/sculpt/deploy/goa_testbed b/repos/pc/sculpt/deploy/goa_testbed index 6362efb151..9d21432006 100644 --- a/repos/pc/sculpt/deploy/goa_testbed +++ b/repos/pc/sculpt/deploy/goa_testbed @@ -60,13 +60,13 @@ </route> </start> - <start name="fs_rom" priority="-2" pkg="jschlatow/pkg/fs_rom/2024-04-11"> + <start name="fs_rom" priority="-2" pkg="jschlatow/pkg/fs_rom/2024-10-07"> <route> <service name="File_system"> <parent label="report"/> </service> </route> </start> - <start name="system_info" pkg="jschlatow/pkg/system_info/2024-04-22" priority="-2"> + <start name="system_info" pkg="jschlatow/pkg/system_info/2024-10-09" priority="-2"> <route> <service name="Gui"> <parent label="backdrop"/> </service> <service name="Rtc"> <child name="system_clock"/> </service> @@ -89,15 +89,15 @@ </config> </start> - <start name="goa_testbed" pkg="jschlatow/pkg/goa_testbed/2024-07-15" priority="-2"> + <start name="goa_testbed" pkg="jschlatow/pkg/goa_testbed/2024-10-11" priority="-2"> <route> <service name="TRACE"> <parent/> </service> <service name="VM"> <parent/> </service> <service name="Gpu"> <child name="intel_gpu"/> </service> <service name="Gui"> <child name="wm"/> </service> <service name="Rtc"> <child name="system_clock"/> </service> - <service name="Audio_in"> <child name="black_hole"/> </service> - <service name="Audio_out"> <child name="black_hole"/> </service> + <service name="Play"> <child name="black_hole"/> </service> + <service name="Record"> <child name="black_hole"/> </service> <service name="Usb"> <child name="black_hole"/> </service> <service name="Event"> <child name="black_hole"/> </service> <service name="Capture"> <child name="black_hole"/> </service> @@ -105,7 +105,7 @@ <service name="Nic" label_prefix="telnet"> <child name="nic_router" label="telnet"/> </service> <service name="Nic" label_prefix="http"> <child name="nic_router" label="http"/> </service> <service name="Nic" label_prefix="gdb"> <child name="nic_router" label="gdb"/> </service> - <service name="Nic"> <!-- for test scenario --> <child name="nic_router"/> </service> + <service name="Nic"> <!-- for test scenario --> <child name="nic_router"/> </service> <service name="Report" label="clipboard"> <child name="wm"/> </service> <service name="Report" label="shape"> <child name="wm"/> </service> <service name="ROM" label="clipboard"> <child name="wm"/> </service> diff --git a/repos/pc/src/driver/framebuffer/intel/pc/README b/repos/pc/src/driver/framebuffer/intel/pc/README index e40a311dec..caeb333bf5 100644 --- a/repos/pc/src/driver/framebuffer/intel/pc/README +++ b/repos/pc/src/driver/framebuffer/intel/pc/README @@ -3,62 +3,23 @@ This driver is for Intel i915 compatible graphic cards. Default behaviour ~~~~~~~~~~~~~~~~~ -When no configuration is provided to the driver, it will switch on all devices -connected to the graphics card. It will use the highest resolution as -provided by the BIOS or EDID information from the display devices for each -connector. The virtual resolution delivered to the client is the maximum in -width and height of the active connectors. +When no configuration is provided to the driver, it will enable all connectors +with attached displays and allocate one shared framebuffer for all displays +(see non-discrete mode below). It will use the highest resolution as provided +by the BIOS or EDID information. For each discrete connector a separate +Capture connection will be requested labeled according to the connector name. +When newly connected displays are detected by the driver, the new connectors +are enabled and another Capture session labeled according to the connector +will be requested. -When newly connected devices are detected by the hardware, the new connectors -are enabled, probed, and again the highest resolution across all active -connectors will be chosen. By default, the current config of the driver will -be re-read and re-applied. This behaviour can be disabled by +By default, on hotplug of a display, the current config of the driver will be +re-parsed and re-applied. This behaviour can be disabled by ! <config apply_on_hotplug="no"/> Configuration ~~~~~~~~~~~~~ -Each of the connectors can be configured explicitly in terms of resolution and -whether it should be enabled or not. This looks like the following: - -! <config> -! <connector name="eDP-1" width="1920" height="1080" hz="60" brightness="75" enabled="true"/> -! <connector name="DP-1" mode_id="2" enabled="true"/> -! </config> - -The resolution can be configured exactly by the reported mode_id or by -the width/height/hz attributes. In the latter case the driver will take the -first matching mode out of multiple matching modes potentially. - -When the configuration changes during runtime, the driver will adapt to it. In -this case, it will also change the current virtual resolution to the maximum of -the configured resolutions in width and height, and it will inform its client -about the change in resolution. - -The brightness value is in percent and takes effect only if supported by -the hardware. - -The maximal physical resolution can be enforced by: - -! <config max_width="2560" max_height="1440"> -! </config> - -The virtual resolution can be enforced by: - -! <config force_width="1024" force_height="768"> -! </config> - -The amount of memory used by the driver for the accounting of its available -buffer space is set by: - -! <config max_framebuffer_memory="64M"> -! </config> - -The default and minimal value is '64M' and suffices for resolutions of at -least '3840x2160'. How much actual memory is used depends on the configured -resolution. - To present all available connectors and their possible resolutions to the user, the driver is able to deliver a corresponding report, which can be enabled in the configuration as follows: @@ -70,24 +31,100 @@ in the configuration as follows: The exported report has the following format: ! <connectors> -! <connector name="eDP-1" connected="true" brightness="50" width_mm="290" height_mm="170"> -! <mode width="1920" height="1080" hz="60" mode_id="1" preferred="true" used="true" width_mm="288" height_mm="165"/> -! ... -! </connector> -! <connector name="DP-1" connected="true" width_mm="280" height_mm="160"> -! <mode width="1920" height="1200" hz="60" mode_id="1" preferred="true" width_mm="280" height_mm="160"/> -! <mode width="1920" height="1080" hz="60" mode_id="2" used="true" width_mm="278" height_mm="158"/> -! <mode width="1280" height="1024" hz="60" mode_id="3"/> -! <mode width="1024" height="768" hz="60" mode_id="4"/> -! ... -! </connector> -! <connector name="HDMI-A-1" connected="false"/> +! <merge name="mirror"> +! <connector name="eDP-1" connected="true" brightness="50" width_mm="290" height_mm="170"> +! <mode width="1920" height="1080" hz="60" id="1" preferred="true" used="true" width_mm="288" height_mm="165"/> +! ... +! </connector> +! <connector name="DP-1" connected="true" width_mm="280" height_mm="160"> +! <mode width="1920" height="1200" hz="60" id="1" preferred="true" width_mm="280" height_mm="160"/> +! <mode width="1920" height="1080" hz="60" id="2" used="true" width_mm="278" height_mm="158"/> +! <mode width="1280" height="1024" hz="60" id="3"/> +! <mode width="1024" height="768" hz="60" id="4"/> +! ... +! </connector> +! <connector name="HDMI-A-1" connected="false"/> +! </merge> ! </connectors> -The physical dimension of the display is reported as width_mm and height_mm +The physical dimension of the display is reported as 'width_mm' and 'height_mm' in millimeter per connector and if available, also per mode. The values can be used as input to DPI calculations. The currently used mode of the connector is tagged in the report explicitly. -The brightness attribute is reported only if the hardware supports it. +Each of the connectors can be configured a specific mode and +whether it should be enabled or not. This looks like the following: +! <config> +! <connector name="eDP-1" enabled="true" width="1920" height="1080" hz="60" brightness="75"/> +! <connector name="DP-1" enabled="true" mode="2"/> +! </config> + +The resolution can be configured exactly by setting the 'mode' attribute +to one of the 'id' values of the reported modes or by setting the +width/height/hz attributes. In the latter case the driver will take the first +matching mode out of multiple matching modes potentially. + +The brightness value is in percent and takes effect only if supported by +the hardware. + +The maximal physical resolution across all connectors can be restricted by: + +! <config max_width="2560" max_height="1440"> +! </config> + +Note: All larger modes still will be reported, but are marked as unusable + by an additional attribute 'usable' set to false. + +The amount of memory used by the driver for the accounting of its available +buffer space is set by: + +! <config max_framebuffer_memory="64M"> +! </config> + +The default and minimal value is '64M' and suffices for resolutions of at +least '3840x2160'. How much actual memory is used depends on the configured +resolution. + + +Non-discrete usage of connectors +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Mirrored usage of connectors can be achieved by moving those connectors into +a sub node called 'merge' of the configuration. For all those connectors, +exactly one and the same framebuffer will be used internally by the driver. +The driver will allocate the framebuffer large enough to accommodate all +non-discrete connectors. If some of the modes of the connectors are smaller, +than only a subset of the content will be visible on those displays. + +! <connectors> +! +! <connector name="eDP-1" ...> <!-- discrete, not mirrored --> +! ... +! </connector> +! <connector name="DP-1" ...> <!.. discrete, not mirrored --> +! ... +! </connector> +! +! <merge name="mirror"> +! <connector name="HDMI-A-1" ...> +! ... +! </connector> +! <connector name="VGA--1" ...> +! ... +! </connector> +! </merge> +! </connectors> + +Note: If connectors are configured as non-discrete, they will also be + reported inside a separate 'merge' node. + +Additionally, the virtual resolution for non-discrete connectors may be +restricted via: + +! <merge name="mirror" width="1024" height="768"> +! ... +! </merge> + +Thereby, the driver will open a Genode capture session to the +GUI multiplexer with this limited dimension. diff --git a/repos/pc/src/driver/framebuffer/intel/pc/dummies.c b/repos/pc/src/driver/framebuffer/intel/pc/dummies.c index 5e3ead6fcc..d133c9db54 100644 --- a/repos/pc/src/driver/framebuffer/intel/pc/dummies.c +++ b/repos/pc/src/driver/framebuffer/intel/pc/dummies.c @@ -720,3 +720,51 @@ int intel_pxp_key_check(struct intel_pxp *pxp, struct drm_i915_gem_object *obj, lx_emul_trace(__func__); return -ENODEV; } + + +int intel_gt_wait_for_idle(struct intel_gt *gt, long timeout) +{ + printk("%s - timeout=%ld\n", __func__, timeout); + lx_emul_trace(__func__); + return 0; +} + + +long intel_gt_retire_requests_timeout(struct intel_gt * gt, long timeout, long * remaining_timeout) +{ + printk("%s - timeout=%ld\n", __func__, timeout); + + if (remaining_timeout) + *remaining_timeout = 0; + + return 0; +} + + +void * vmap(struct page ** pages, unsigned int count, unsigned long flags, pgprot_t prot) +{ + bool contiguous = true; + void * vmap_addr = 0; + unsigned long prev_addr = 0; + + for (unsigned i = 0; i < count; i++) { + void * virt_addr = page_address(pages[i]); + + if (!i) + vmap_addr = virt_addr; + + if (i && contiguous) + contiguous = (void *)(prev_addr + 4096) == virt_addr; + + prev_addr = (unsigned long)virt_addr; + + if (!contiguous) + break; + } + + if (!contiguous) + printk("%s -- failed, pages are non contiguous count=%u\n", + __func__, count); + + return contiguous ? vmap_addr : 0; +} diff --git a/repos/pc/src/driver/framebuffer/intel/pc/fb.c b/repos/pc/src/driver/framebuffer/intel/pc/fb.c deleted file mode 100644 index 240021045e..0000000000 --- a/repos/pc/src/driver/framebuffer/intel/pc/fb.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * \brief Linux kernel framebuffer device support - * \author Stefan Kalkowski - * \date 2021-05-03 - */ - -/* - * Copyright (C) 2021-2023 Genode Labs GmbH - * - * This file is distributed under the terms of the GNU General Public License - * version 2. - */ - -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/fb.h> -#include <lx_emul/fb.h> - - -int register_framebuffer(struct fb_info * fb_info) -{ - lx_emul_framebuffer_ready(fb_info->screen_base, fb_info->screen_size, - fb_info->var.xres_virtual, fb_info->var.yres_virtual, - fb_info->fix.line_length / - (fb_info->var.bits_per_pixel / 8), fb_info->var.yres); - return 0; -} diff --git a/repos/pc/src/driver/framebuffer/intel/pc/generated_dummies.c b/repos/pc/src/driver/framebuffer/intel/pc/generated_dummies.c index 8277515973..d715fd6de5 100644 --- a/repos/pc/src/driver/framebuffer/intel/pc/generated_dummies.c +++ b/repos/pc/src/driver/framebuffer/intel/pc/generated_dummies.c @@ -712,20 +712,6 @@ struct intel_context * i915_gem_engines_iter_next(struct i915_gem_engines_iter * } -extern int i915_gem_evict_for_node(struct i915_address_space * vm,struct i915_gem_ww_ctx * ww,struct drm_mm_node * target,unsigned int flags); -int i915_gem_evict_for_node(struct i915_address_space * vm,struct i915_gem_ww_ctx * ww,struct drm_mm_node * target,unsigned int flags) -{ - lx_emul_trace_and_stop(__func__); -} - - -extern int i915_gem_evict_something(struct i915_address_space * vm,struct i915_gem_ww_ctx * ww,u64 min_size,u64 alignment,unsigned long color,u64 start,u64 end,unsigned flags); -int i915_gem_evict_something(struct i915_address_space * vm,struct i915_gem_ww_ctx * ww,u64 min_size,u64 alignment,unsigned long color,u64 start,u64 end,unsigned flags) -{ - lx_emul_trace_and_stop(__func__); -} - - extern int i915_gem_execbuffer2_ioctl(struct drm_device * dev,void * data,struct drm_file * file); int i915_gem_execbuffer2_ioctl(struct drm_device * dev,void * data,struct drm_file * file) { @@ -1227,13 +1213,6 @@ void intel_gt_mcr_unlock(struct intel_gt * gt,unsigned long flags) } -extern long intel_gt_retire_requests_timeout(struct intel_gt * gt,long timeout,long * remaining_timeout); -long intel_gt_retire_requests_timeout(struct intel_gt * gt,long timeout,long * remaining_timeout) -{ - lx_emul_trace_and_stop(__func__); -} - - extern int intel_gt_runtime_resume(struct intel_gt * gt); int intel_gt_runtime_resume(struct intel_gt * gt) { @@ -2086,14 +2065,6 @@ void update_group_capacity(struct sched_domain * sd,int cpu) } -#include <linux/vmalloc.h> - -void * vmap(struct page ** pages,unsigned int count,unsigned long flags,pgprot_t prot) -{ - lx_emul_trace_and_stop(__func__); -} - - #include <linux/vmalloc.h> void * vmap_pfn(unsigned long * pfns,unsigned int count,pgprot_t prot) diff --git a/repos/pc/src/driver/framebuffer/intel/pc/lx_emul.c b/repos/pc/src/driver/framebuffer/intel/pc/lx_emul.c index 5262c6b112..5100e551bf 100644 --- a/repos/pc/src/driver/framebuffer/intel/pc/lx_emul.c +++ b/repos/pc/src/driver/framebuffer/intel/pc/lx_emul.c @@ -105,9 +105,6 @@ int intel_root_gt_init_early(struct drm_i915_private * i915) intel_uc_init_early(>->uc); - /* disable panel self refresh (required for FUJITSU S937/S938) */ - i915->params.enable_psr = 0; - /* * Tells driver that IOMMU, e.g. VT-d, is on, so that scratch page * workaround is applied by Intel display driver: diff --git a/repos/pc/src/driver/framebuffer/intel/pc/lx_emul/fb.h b/repos/pc/src/driver/framebuffer/intel/pc/lx_emul/fb.h deleted file mode 100644 index 438c52bc41..0000000000 --- a/repos/pc/src/driver/framebuffer/intel/pc/lx_emul/fb.h +++ /dev/null @@ -1,29 +0,0 @@ -/** - * \brief Lx_emul support to register Linux kernel framebuffer - * \author Stefan Kalkowski - * \date 2021-05-17 - */ - -/* - * Copyright (C) 2021 Genode Labs GmbH - * - * This file is distributed under the terms of the GNU General Public License - * version 2. - */ - -#ifndef _LX_EMUL__FB_H_ -#define _LX_EMUL__FB_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -void lx_emul_framebuffer_ready(void * base, unsigned long size, - unsigned xres, unsigned yres, - unsigned virtual_width, unsigned virtual_height); - -#ifdef __cplusplus -} -#endif - -#endif /* _LX_EMUL__FB_H_ */ diff --git a/repos/pc/src/driver/framebuffer/intel/pc/lx_i915.h b/repos/pc/src/driver/framebuffer/intel/pc/lx_i915.h index 2ae68b1228..e94d9fb90c 100644 --- a/repos/pc/src/driver/framebuffer/intel/pc/lx_i915.h +++ b/repos/pc/src/driver/framebuffer/intel/pc/lx_i915.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2022 Genode Labs GmbH + * Copyright (C) 2022-2024 Genode Labs GmbH * * This file is distributed under the terms of the GNU General Public License * version 2. @@ -29,18 +29,46 @@ struct genode_mode { unsigned preferred; unsigned inuse; unsigned id; + char mirror; char name[32]; }; -void lx_emul_i915_report(void * genode_xml); +enum Action { + ACTION_IDLE = 0, + ACTION_DETECT_MODES = 1, + ACTION_CONFIGURE = 2, + ACTION_REPORT = 3, + ACTION_NEW_CONFIG = 4, + ACTION_READ_CONFIG = 5, + ACTION_HOTPLUG = 6, + ACTION_EXIT = 7, + ACTION_FAILED = 9, +}; + +int lx_emul_i915_blit(unsigned const connector_id, char const may_sleep); +void lx_emul_i915_wakeup(unsigned connector_id); +void lx_emul_i915_report_discrete(void * genode_xml); +void lx_emul_i915_report_non_discrete(void * genode_xml); void lx_emul_i915_hotplug_connector(void); +int lx_emul_i915_action_to_process(int); + void lx_emul_i915_report_connector(void * lx_data, void * genode_xml, char const *name, char connected, + char valid_fb, unsigned brightness, unsigned width_mm, unsigned height_mm); void lx_emul_i915_iterate_modes(void *lx_data, void * genode_data); void lx_emul_i915_report_modes(void * genode_xml, struct genode_mode *); void lx_emul_i915_connector_config(char * name, struct genode_mode *); int lx_emul_i915_config_done_and_block(void); +void lx_emul_i915_framebuffer_ready(unsigned connector_id, + char const * const connector_name, + void * base, + unsigned long size, + unsigned xres, unsigned yres, + unsigned virtual_width, + unsigned virtual_height, + unsigned mm_width, + unsigned mm_height); #endif /* _LX_I915_H_ */ diff --git a/repos/pc/src/driver/framebuffer/intel/pc/lx_user.c b/repos/pc/src/driver/framebuffer/intel/pc/lx_user.c index 3d6b3b81bd..c4eec40ece 100644 --- a/repos/pc/src/driver/framebuffer/intel/pc/lx_user.c +++ b/repos/pc/src/driver/framebuffer/intel/pc/lx_user.c @@ -25,28 +25,41 @@ #include "lx_emul.h" -enum { MAX_BRIGHTNESS = 100, INVALID_BRIGHTNESS = MAX_BRIGHTNESS + 1 }; +enum { MAX_BRIGHTNESS = 100, INVALID_BRIGHTNESS = MAX_BRIGHTNESS + 1 }; +enum { MAX_CONNECTORS = 32, CONNECTOR_ID_MIRROR = MAX_CONNECTORS - 1 }; +enum { CAPTURE_RATE_MS = 10, ATTEMPTS_BEFORE_STOP = 7 }; + struct task_struct * lx_user_task = NULL; +static struct task_struct * lx_update_task = NULL; +static struct drm_client_dev * dev_client = NULL; - struct task_struct * lx_user_task = NULL; -static struct drm_client_dev * dev_client = NULL; +static bool const verbose = false; + +static struct state { + struct drm_mode_create_dumb fb_dumb; + struct drm_mode_fb_cmd2 fb_cmd; + struct drm_framebuffer * fbs; + struct i915_vma * vma; + unsigned long vma_flags; + uint8_t mode_id; + uint8_t unchanged; + bool mirrored; + bool enabled; +} states [MAX_CONNECTORS] = { }; static int user_register_fb(struct drm_client_dev const * const dev, struct fb_info * const info, - struct drm_mode_fb_cmd2 const * const dumb_fb); + struct drm_framebuffer * const fb, + struct i915_vma ** vma, + unsigned long * vma_flags, + unsigned width_mm, unsigned height_mm); -static int user_attach_fb_to_crtc(struct drm_client_dev * const dev, - struct drm_connector const * const connector, - struct drm_crtc const * const crtc, - struct drm_mode_modeinfo const * const mode, - unsigned const fb_id, - bool const enable); - static int check_resize_fb(struct drm_client_dev * const dev, struct drm_mode_create_dumb * const gem_dumb, struct drm_mode_fb_cmd2 * const dumb_fb, + bool * const resized, unsigned const width, unsigned const height); @@ -75,41 +88,43 @@ static inline bool conf_larger_mode(struct genode_mode const * const g, } -static inline bool fb_smaller_mode(struct fb_info const * const info, - struct drm_display_mode const * const mode) +static inline bool fb_mirror_compatible(struct drm_display_mode const * const a, + struct drm_display_mode const * const b) { - return (uint64_t)info->var.xres * (uint64_t)info->var.yres < - (uint64_t)mode->vdisplay * (uint64_t)mode->hdisplay; + return a->vdisplay <= b->vdisplay && a->hdisplay <= b->hdisplay; } +static int probe_and_apply_fbs(struct drm_client_dev *client, bool); + + /* - * Heuristic to calculate max resolution across all connectors + * Heuristic to calculate mixed resolution across all mirrored connectors */ -static void preferred_mode(struct drm_device const * const dev, - struct drm_display_mode * const prefer, - struct drm_display_mode * const min_mode) +static void mirror_heuristic(struct drm_device const * const dev, + struct drm_display_mode * const virtual, + struct drm_display_mode * const compound, + struct drm_display_mode * const min_mode) { struct drm_connector *connector = NULL; struct drm_display_mode *mode = NULL; - unsigned connector_usable = 0; - struct drm_display_mode max_enforcement = { }; struct drm_connector_list_iter conn_iter; /* read Genode's config per connector */ drm_connector_list_iter_begin(dev, &conn_iter); drm_client_for_each_connector_iter(connector, &conn_iter) { struct drm_display_mode smallest = { .hdisplay = ~0, .vdisplay = ~0 }; - struct genode_mode conf_mode = { .enabled = 1 }; + struct drm_display_mode usable = { }; + struct genode_mode conf_mode = { }; unsigned mode_id = 0; /* check for connector configuration on Genode side */ lx_emul_i915_connector_config(connector->name, &conf_mode); - if (!conf_mode.enabled) + if (!conf_mode.enabled || !conf_mode.mirror) continue; - /* look for smallest possible mode or if a specific mode is forced */ + /* look for smallest possible mode or if a specific mode is specified */ list_for_each_entry(mode, &connector->modes, head) { mode_id ++; @@ -121,21 +136,22 @@ static void preferred_mode(struct drm_device const * const dev, smallest.vdisplay = mode->vdisplay; } - if (!conf_mode.id) - continue; + /* maximal resolution enforcement */ + if (conf_mode.max_width && conf_mode.max_height) { + if (conf_smaller_max_mode(&conf_mode, mode)) + continue; + } - if (!mode || conf_mode.id != mode_id) - continue; + if (!usable.hdisplay && !usable.vdisplay) + usable = *mode; - conf_mode.width = mode->hdisplay; - conf_mode.height = mode->vdisplay; - - break; + if (conf_mode.id == mode_id) { + conf_mode.width = mode->hdisplay; + conf_mode.height = mode->vdisplay; + break; + } } - if (mode_id) - connector_usable ++; - /* * If at least on mode is available, store smallest mode if it * is larger than min_mode of other connectors @@ -144,6 +160,7 @@ static void preferred_mode(struct drm_device const * const dev, *min_mode = smallest; if (conf_mode.force_width && conf_mode.force_height) { + /* * Even so the force_* mode is selected, a configured mode for * a connector is considered, effectively the framebuffer content @@ -155,24 +172,23 @@ static void preferred_mode(struct drm_device const * const dev, } /* enforce the force mode */ - conf_mode.width = conf_mode.force_width; - conf_mode.height = conf_mode.force_height; + virtual->hdisplay = conf_mode.force_width; + virtual->vdisplay = conf_mode.force_height; } - /* maximal resolution enforcement */ - if (conf_mode.max_width && conf_mode.max_height) { - max_enforcement.hdisplay = conf_mode.max_width; - max_enforcement.vdisplay = conf_mode.max_height; - if (conf_smaller_max_mode(&conf_mode, prefer)) - continue; - } - - if (!conf_mode.width || !conf_mode.height) - continue; - - if (conf_larger_mode(&conf_mode, prefer)) { - prefer->hdisplay = conf_mode.width; - prefer->vdisplay = conf_mode.height; + /* compound calculation */ + if (conf_mode.width && conf_mode.height) { + if (conf_mode.width > compound->hdisplay) + compound->hdisplay = conf_mode.width; + if (conf_mode.height > compound->vdisplay) + compound->vdisplay = conf_mode.height; + } else { + if (usable.hdisplay && usable.vdisplay) { + if (usable.hdisplay > compound->hdisplay) + compound->hdisplay = usable.hdisplay; + if (usable.vdisplay > compound->vdisplay) + compound->vdisplay = usable.vdisplay; + } } } drm_connector_list_iter_end(&conn_iter); @@ -181,36 +197,9 @@ static void preferred_mode(struct drm_device const * const dev, if (!min_mode->hdisplay || !min_mode->vdisplay) return; - /* we got a preferred resolution */ - if (prefer->hdisplay && prefer->vdisplay) - return; - - /* if too large or nothing configured by Genode's config */ - drm_connector_list_iter_begin(dev, &conn_iter); - drm_client_for_each_connector_iter(connector, &conn_iter) { - list_for_each_entry(mode, &connector->modes, head) { - if (!mode) - continue; - - if (mode_larger(min_mode, mode)) - continue; - - if (max_enforcement.hdisplay && max_enforcement.vdisplay) { - if (mode_larger(mode, &max_enforcement)) - continue; - } - - if (mode_larger(mode, prefer)) { - prefer->hdisplay = mode->hdisplay; - prefer->vdisplay = mode->vdisplay; - } - } - } - drm_connector_list_iter_end(&conn_iter); - - /* handle the "never should happen case" gracefully */ - if (!prefer->hdisplay || !prefer->vdisplay) - *prefer = *min_mode; + /* if no mirrored connectors are enabled, compound is the minimal mode */ + if (!compound->hdisplay || !compound->vdisplay) + *compound = *min_mode; } @@ -248,225 +237,600 @@ static unsigned get_brightness(struct drm_connector * const connector, return ret * MAX_BRIGHTNESS / panel->backlight.device->props.max_brightness; } -static struct drm_mode_fb_cmd2 dumb_fb = {}; -static bool reconfigure(struct drm_client_dev * const dev) +static void destroy_fb(struct drm_client_dev * const dev, + struct drm_mode_create_dumb * const gem_dumb, + struct drm_mode_fb_cmd2 * const dumb_fb) { - static struct drm_mode_create_dumb gem_dumb = {}; + if (dumb_fb->fb_id) { + int result = drm_mode_rmfb(dev->dev, dumb_fb->fb_id, dev->file); - struct drm_display_mode mode_preferred = {}; - struct drm_display_mode mode_minimum = {}; - struct drm_display_mode framebuffer = {}; - struct drm_mode_modeinfo user_mode = {}; - struct drm_display_mode *mode = NULL; - struct drm_mode_set *mode_set = NULL; - struct fb_info report_fb_info = {}; - bool report_fb = false; - bool retry = false; - - if (!dev || !dev->dev) - return false; - - preferred_mode(dev->dev, &mode_preferred, &mode_minimum); - - if (!mode_minimum.hdisplay || !mode_minimum.vdisplay) { - /* no valid modes on any connector on early boot */ - if (!dumb_fb.fb_id) - return false; - - /* valid connectors but all are disabled by config */ - mode_minimum.hdisplay = dumb_fb.width; - mode_minimum.vdisplay = dumb_fb.height; - mode_preferred = mode_minimum; - } - - if (mode_larger(&mode_preferred, &mode_minimum)) - framebuffer = mode_preferred; - else - framebuffer = mode_minimum; - - { - int const err = check_resize_fb(dev, - &gem_dumb, - &dumb_fb, - framebuffer.hdisplay, - framebuffer.vdisplay); - - if (err) { - printk("setting up framebuffer of %ux%u failed - error=%d\n", - framebuffer.hdisplay, framebuffer.vdisplay, err); - - return true; + if (result) { + drm_err(dev->dev, "%s: failed to remove framebuffer %d\n", + __func__, result); } } - /* without fb handle created by check_resize_fb we can't proceed */ - if (!dumb_fb.fb_id) - return retry; + if (gem_dumb->handle) { + int result = drm_mode_destroy_dumb(dev->dev, gem_dumb->handle, dev->file); - /* prepare fb info for register_framebuffer() evaluated by Genode side */ - report_fb_info.var.xres = framebuffer.hdisplay; - report_fb_info.var.yres = framebuffer.vdisplay; - report_fb_info.var.xres_virtual = mode_preferred.hdisplay; - report_fb_info.var.yres_virtual = mode_preferred.vdisplay; + if (result) { + drm_err(dev->dev, "%s: failed to destroy framebuffer %d\n", + __func__, result); + } + } - drm_client_for_each_modeset(mode_set, dev) { - struct drm_display_mode *mode_match = NULL; - unsigned mode_id = 0; - struct drm_connector *connector = NULL; + memset(gem_dumb, 0, sizeof(*gem_dumb)); + memset(dumb_fb, 0, sizeof(*dumb_fb)); +} - struct genode_mode conf_mode = { }; - if (!mode_set->connectors || !*mode_set->connectors) +static int kernel_register_fb(struct fb_info const * const fb_info, + unsigned const width_mm, + unsigned const height_mm) +{ + lx_emul_i915_framebuffer_ready(fb_info->node, + fb_info->par, + fb_info->screen_base, + fb_info->screen_size, + fb_info->var.xres_virtual, + fb_info->var.yres_virtual, + fb_info->fix.line_length / + (fb_info->var.bits_per_pixel / 8), + fb_info->var.yres, + width_mm, height_mm); + + return 0; +} + + +static void destroy_fb_and_capture(struct drm_client_dev * const dev, + struct drm_connector const * const connector, + struct state * const state) +{ + struct fb_info info = {}; + + info.var.bits_per_pixel = 32; + info.node = connector->index; + info.par = connector->name; + + kernel_register_fb(&info, 0, 0); + + if (state->vma) { + intel_unpin_fb_vma(state->vma, + state->vma_flags); + + state->vma = NULL; + state->vma_flags = 0; + } + + state->enabled = false; + state->unchanged = 0; + + destroy_fb(dev, &(state->fb_dumb), &(state->fb_cmd)); +} + + +static void close_unused_captures(struct drm_client_dev * const dev) +{ + /* report disconnected connectors to close capture connections */ + struct drm_connector_list_iter conn_iter; + struct drm_connector * connector = NULL; + bool mirror_in_use = false; + + drm_connector_list_iter_begin(dev->dev, &conn_iter); + drm_client_for_each_connector_iter(connector, &conn_iter) { + + if (connector->index >= MAX_CONNECTORS) continue; - BUG_ON(!mode_set->crtc); + if (connector->index == CONNECTOR_ID_MIRROR) + continue; - /* set connector */ - connector = *mode_set->connectors; + if (!states[connector->index].fbs) + destroy_fb_and_capture(dev, connector, &states[connector->index]); + } + drm_connector_list_iter_end(&conn_iter); + + for (unsigned i = 0; i < MAX_CONNECTORS; i++) { + if (i == CONNECTOR_ID_MIRROR) + continue; + + if (!states[i].enabled || !states[i].mirrored) + continue; + + mirror_in_use = true; + break; + } + + if (!mirror_in_use) { + struct fb_info fb_info = {}; + + fb_info.var.bits_per_pixel = 32; + fb_info.node = CONNECTOR_ID_MIRROR; + fb_info.par = "mirror_capture"; + + kernel_register_fb(&fb_info, 0, 0); + } +} + + +static struct drm_display_mode * best_mode(struct genode_mode const * const conf, + struct drm_connector const * const connector, + struct drm_display_mode const * const mirror_mode, + bool * const no_match, + unsigned * const id_mode) +{ + struct drm_display_mode * mode = NULL; + struct drm_display_mode * mode_match = NULL; + unsigned mode_id = 0; + + /* heuristics to find matching mode */ + list_for_each_entry(mode, &connector->modes, head) { + mode_id ++; + + if (!mode) + continue; + + /* mode larger mirrored_mode will fail */ + if (conf->mirror && !fb_mirror_compatible(mode, mirror_mode)) + continue; + + /* use mode id if configured and matches exactly */ + if (conf->id) { + if (conf->id != mode_id) + continue; + + mode_match = mode; + break; + } + + /* if invalid, mode is configured in second loop below */ + if (conf->width == 0 || conf->height == 0) + break; + + /* no exact match by mode id -> try matching by size */ + if ((mode->hdisplay != conf->width) || (mode->vdisplay != conf->height)) + continue; + + /* take as default any mode with matching resolution */ + if (!mode_match) { + mode_match = mode; + continue; + } + + /* replace matching mode iif hz matches exactly */ + if ((conf->hz != drm_mode_vrefresh(mode_match)) && + (conf->hz == drm_mode_vrefresh(mode))) + mode_match = mode; + } + + mode_id = 0; + + /* second chance loop */ + list_for_each_entry(mode, &connector->modes, head) { + + mode_id ++; + + if (!mode) + continue; + + /* use first mode for non mirrored connector in case of no match */ + if (!mode_match && !conf->mirror) { + + struct drm_display_mode max = { .hdisplay = conf->max_width, + .vdisplay = conf->max_height }; + + if (conf->max_width && conf->max_height) { + if (conf_larger_mode(conf, &max)) + continue; + } + + mode_match = mode; + } + + /* no matching mode ? */ + if (!mode_match) { + + /* mode larger mirrored_mode will fail */ + if (conf->mirror && !fb_mirror_compatible(mode, mirror_mode)) + continue; + + /* use first smaller mode */ + mode_match = mode; + + if (conf->id) + *no_match = true; + } + + if (mode_match != mode) + continue; + + *id_mode = mode_id; + + break; + } + + return mode_match; +} + + +static void reconfigure(struct drm_client_dev * const dev) +{ + static struct drm_mode_create_dumb * gem_mirror = NULL; + static struct drm_mode_fb_cmd2 * mirror_fb_cmd = NULL; + + struct drm_connector_list_iter conn_iter; + struct drm_connector * connector = NULL; + + struct drm_display_mode mirror_force = {}; + struct drm_display_mode mirror_compound = {}; + struct drm_display_mode mirror_minimum = {}; + struct drm_display_mode mirror_fb = {}; + + struct { + struct fb_info info; + unsigned width_mm; + unsigned height_mm; + bool report; + } mirror = { { }, 0, 0, false }; + + gem_mirror = &states[CONNECTOR_ID_MIRROR].fb_dumb; + mirror_fb_cmd = &states[CONNECTOR_ID_MIRROR].fb_cmd; + + if (!dev || !dev->dev || !gem_mirror || !mirror_fb_cmd) + return; + + mirror_heuristic(dev->dev, &mirror_force, &mirror_compound, + &mirror_minimum); + + if (!mirror_minimum.hdisplay || !mirror_minimum.vdisplay) { + /* no valid modes on any connector on early boot */ + if (!mirror_fb_cmd->fb_id) + return; + + /* valid connectors but all are disabled by config */ + mirror_minimum.hdisplay = mirror_fb_cmd->width; + mirror_minimum.vdisplay = mirror_fb_cmd->height; + mirror_compound = mirror_minimum; + } + + if (mode_larger(&mirror_compound, &mirror_minimum)) + mirror_fb = mirror_compound; + else + mirror_fb = mirror_minimum; + + { + struct state * state_mirror = &states[CONNECTOR_ID_MIRROR]; + bool resized = false; + + int const err = check_resize_fb( dev, + gem_mirror, + mirror_fb_cmd, + &resized, + mirror_fb.hdisplay, + mirror_fb.vdisplay); + + if (err) { + printk("setting up mirrored framebuffer of %ux%u failed - error=%d\n", + mirror_fb.hdisplay, mirror_fb.vdisplay, err); + + return; + } + + if (verbose) { + printk("mirror: compound %ux%u force=%ux%u fb=%ux%u\n", + mirror_compound.hdisplay, mirror_compound.vdisplay, + mirror_force.hdisplay, mirror_force.vdisplay, + mirror_fb.hdisplay, mirror_fb.vdisplay); + } + + /* if mirrored fb changed, drop reference and get new framebuffer */ + if (resized) { + if (state_mirror->fbs) + drm_framebuffer_put(state_mirror->fbs); + + state_mirror->fbs = drm_framebuffer_lookup(dev->dev, dev->file, + mirror_fb_cmd->fb_id); + } + + mirror.info.var.xres = mirror_fb.hdisplay; + mirror.info.var.yres = mirror_fb.vdisplay; + mirror.info.var.xres_virtual = mirror_force.hdisplay ? : mirror_compound.hdisplay; + mirror.info.var.yres_virtual = mirror_force.vdisplay ? : mirror_compound.vdisplay; + mirror.info.node = CONNECTOR_ID_MIRROR; + mirror.info.par = "mirror_capture"; + } + + /* without fb handle created by check_resize_fb we can't proceed */ + if (!mirror_fb_cmd->fb_id) { + printk("%s:%u no mirror fb id\n", __func__, __LINE__); + return; + } + + drm_connector_list_iter_begin(dev_client->dev, &conn_iter); + drm_client_for_each_connector_iter(connector, &conn_iter) { + + struct drm_display_mode * mode = NULL; + unsigned mode_id = 0; + bool no_match = false; + bool same_state = false; + bool resized = false; + int err = -EINVAL; + struct genode_mode conf_mode = {}; + struct fb_info fb_info = {}; + struct state * state = &states[connector->index]; + + if (connector->index >= MAX_CONNECTORS) { + printk("connector id too large %s %u\n", + connector->name, connector->index); + continue; + } /* read configuration of connector */ lx_emul_i915_connector_config(connector->name, &conf_mode); - /* heuristics to find matching mode */ - list_for_each_entry(mode, &connector->modes, head) { - mode_id ++; - - if (!mode) - continue; - - /* allocated framebuffer smaller than mode can't be used */ - if (fb_smaller_mode(&report_fb_info, mode)) - continue; - - /* use mode id if configured and matches exactly */ - if (conf_mode.id) { - if (conf_mode.id != mode_id) - continue; - - mode_match = mode; - break; - } - - /* if invalid, mode is configured in second loop below */ - if (conf_mode.width == 0 || conf_mode.height == 0) { - break; - } - - /* no exact match by mode id -> try matching by size */ - if ((mode->hdisplay != conf_mode.width) || - (mode->vdisplay != conf_mode.height)) - continue; - - /* take as default any mode with matching resolution */ - if (!mode_match) { - mode_match = mode; - continue; - } - - /* replace matching mode iif hz matches exactly */ - if ((conf_mode.hz != drm_mode_vrefresh(mode_match)) && - (conf_mode.hz == drm_mode_vrefresh(mode))) - mode_match = mode; + /* drop old fb reference, taken again later */ + if (state->fbs) { + drm_framebuffer_put(state->fbs); + state->fbs = NULL; } - /* apply new mode */ - mode_id = 0; - list_for_each_entry(mode, &connector->modes, head) { - int err = -1; - bool no_match = false; + /* lookup next mode */ + mode = best_mode(&conf_mode, connector, &mirror_fb, &no_match, &mode_id); - mode_id ++; + /* reduce flickering if in same state */ + same_state = conf_mode.mirror == state->mirrored && + conf_mode.enabled == state->enabled && + mode_id == state->mode_id; - if (!mode) - continue; + /* close capture on change of discrete -> mirror */ + if (!state->mirrored && conf_mode.mirror) + destroy_fb_and_capture(dev, connector, state); - /* no matching mode ? */ - if (!mode_match) { + state->mirrored = conf_mode.mirror; + state->enabled = conf_mode.enabled; + state->mode_id = mode_id; - /* fb smaller than mode is denied by drm_mode_setcrtc */ - if (fb_smaller_mode(&report_fb_info, mode)) - continue; + if (!mode) + continue; - /* use first smaller mode */ - mode_match = mode; + /* prepare fb info for kernel_register_fb() evaluated by Genode side */ + if (conf_mode.mirror) { + if (conf_mode.enabled) + mirror.report = true; + fb_info = mirror.info; + } else { + fb_info.var.xres = mode->hdisplay; + fb_info.var.yres = mode->vdisplay; + fb_info.var.xres_virtual = mode->hdisplay; + fb_info.var.yres_virtual = mode->vdisplay; + fb_info.node = connector->index; + fb_info.par = connector->name; + } - if (conf_mode.enabled && conf_mode.id) - no_match = true; - } - - if (mode_match != mode) - continue; - - /* convert kernel internal mode to user mode expectecd via ioctl */ - drm_mode_convert_to_umode(&user_mode, mode); - - /* assign fb & connector to crtc with specified mode */ - err = user_attach_fb_to_crtc(dev, connector, mode_set->crtc, - &user_mode, dumb_fb.fb_id, - conf_mode.enabled); - - if (err) - retry = true; - else - report_fb = true; - - /* set brightness */ - if (!err && conf_mode.enabled && conf_mode.brightness <= MAX_BRIGHTNESS) { - drm_modeset_lock(&dev->dev->mode_config.connection_mutex, NULL); - set_brightness(conf_mode.enabled ? conf_mode.brightness : 0, - connector); - drm_modeset_unlock(&dev->dev->mode_config.connection_mutex); - } - - /* diagnostics */ - printk("%10s: %s name='%9s' id=%u%s mode=%4ux%4u@%u%s fb=%4ux%4u%s", + /* diagnostics */ + if (verbose) + printk("%10s: %s name='%9s' id=%u%s%s mode=%4ux%4u@%u%s fb=%4ux%4u%s", connector->name ? connector->name : "unnamed", conf_mode.enabled ? " enable" : "disable", mode->name ? mode->name : "noname", - mode_id, mode_id < 10 ? " " : "", mode->hdisplay, - mode->vdisplay, drm_mode_vrefresh(mode), + mode_id, mode_id < 10 ? " " : "", + conf_mode.mirror ? " mirror " : " discrete", + mode->hdisplay, mode->vdisplay, drm_mode_vrefresh(mode), drm_mode_vrefresh(mode) < 100 ? " ": "", - framebuffer.hdisplay, framebuffer.vdisplay, - (err || no_match) ? "" : "\n"); + fb_info.var.xres, fb_info.var.yres, + (no_match) ? "" : "\n"); - if (no_match) - printk(" - no mode match: %ux%u\n", - conf_mode.width, - conf_mode.height); - if (err) - printk(" - failed, error=%d\n", err); + if (verbose && no_match) + printk(" - no mode match: %ux%u\n", + conf_mode.width, + conf_mode.height); + if (!conf_mode.enabled) + continue; + + /* set brightness */ + if (conf_mode.brightness <= MAX_BRIGHTNESS) { + drm_modeset_lock(&dev->dev->mode_config.connection_mutex, NULL); + set_brightness(conf_mode.enabled ? conf_mode.brightness : 0, + connector); + drm_modeset_unlock(&dev->dev->mode_config.connection_mutex); + } + + if (conf_mode.mirror) { + /* get new fb reference for mirrored fb */ + state->fbs = drm_framebuffer_lookup(dev->dev, dev->file, + mirror_fb_cmd->fb_id); + continue; + } + + /* discrete case handling */ + + err = check_resize_fb(dev, &state->fb_dumb, &state->fb_cmd, + &resized, mode->hdisplay, mode->vdisplay); + if (err) { + printk("setting up framebuffer of %ux%u failed - error=%d\n", + mode->hdisplay, mode->vdisplay, err); + } + + /* get new fb reference after check_resize_fb */ + state->fbs = drm_framebuffer_lookup(dev->dev, dev->file, + state->fb_cmd.fb_id); + + if (verbose) + printk("%s:%u %s %s %s\n", __func__, __LINE__, connector->name, + same_state ? " same state " : " different state", + resized ? " resized " : "not resized"); + + if (state->fbs && (!same_state || resized)) { + unsigned width_mm = mode->width_mm ? : connector->display_info.width_mm; + unsigned height_mm = mode->height_mm ? : connector->display_info.height_mm; + + int err = user_register_fb(dev, &fb_info, state->fbs, + &state->vma, &state->vma_flags, + width_mm, height_mm); + + if (err == -ENOSPC) { + if (state->fbs) { + drm_framebuffer_put(state->fbs); + state->fbs = NULL; + } + destroy_fb_and_capture(dev, connector, state); + } + } + } + drm_connector_list_iter_end(&conn_iter); + + if (mirror.report) { + user_register_fb(dev, &mirror.info, + states[CONNECTOR_ID_MIRROR].fbs, + &states[CONNECTOR_ID_MIRROR].vma, + &states[CONNECTOR_ID_MIRROR].vma_flags, + mirror.width_mm, mirror.height_mm); + } + + close_unused_captures(dev); + + return; +} + + +static int do_action_loop(void * data) +{ + int status_last_action = !ACTION_FAILED; + + while (true) { + + int const action = lx_emul_i915_action_to_process(status_last_action); + + switch (action) { + case ACTION_DETECT_MODES: + /* probe new modes of connectors and apply very same previous fbs */ + status_last_action = probe_and_apply_fbs(dev_client, true) + ? ACTION_FAILED : !ACTION_FAILED; + break; + case ACTION_CONFIGURE: + /* re-read Genode configuration and resize fbs depending on config */ + reconfigure(dev_client); + + /* + * Apply current fbs to connectors. It may fail when + * the reconfigure decision is outdated. By invoking the Linux + * probe code we may "see" already new hardware state. + */ + status_last_action = probe_and_apply_fbs(dev_client, false) + ? ACTION_FAILED : !ACTION_FAILED; + + break; + default: + lx_emul_task_schedule(true /* block task */); break; } } - if (report_fb) - user_register_fb(dev, &report_fb_info, &dumb_fb); - - return retry; + return 0; } -static int configure_connectors(void * data) +static void mark_framebuffer_dirty(struct drm_framebuffer * const fb) { - unsigned retry_count = 0; + struct drm_clip_rect *clips = NULL; + struct drm_mode_fb_dirty_cmd r = { }; + unsigned flags = 0; + int num_clips = 0; + int ret = 0; + + if (!dev_client) + return; + + if (!fb || !fb->funcs || !fb->funcs->dirty) + return; + + ret = fb->funcs->dirty(fb, dev_client->file, flags, r.color, clips, + num_clips); + + if (ret) + printk("%s failed %d\n", __func__, ret); +} + + +void lx_emul_i915_wakeup(unsigned const connector_id) +{ + bool const valid_id = connector_id < MAX_CONNECTORS; + + if (!valid_id) { + printk("%s: connector id invalid %d\n", __func__, connector_id); + return; + } + + states[connector_id].unchanged = 0; + + /* wake potential sleeping update task */ + lx_emul_task_unblock(lx_update_task); +} + + +static int update_content(void *) +{ while (true) { - bool retry = reconfigure(dev_client); + struct drm_connector_list_iter conn_iter; + struct drm_connector * connector = NULL; + struct drm_device const * dev = dev_client->dev; + bool block_task = true; + bool mirror_run = false; - if (retry && retry_count < 3) { - retry_count ++; + drm_connector_list_iter_begin(dev, &conn_iter); + drm_client_for_each_connector_iter(connector, &conn_iter) { - printk("retry applying configuration in 1s\n"); - msleep(1000); - continue; + bool may_sleep = false; + unsigned index = connector->index; + + if (connector->status != connector_status_connected) + continue; + + if (connector->index >= MAX_CONNECTORS) { + printk("%s: connector id invalid %d\n", __func__, index); + index = CONNECTOR_ID_MIRROR; /* should never happen case */ + } + + if (!states[index].enabled) + continue; + + if (states[index].mirrored) { + if (mirror_run) + continue; + + mirror_run = true; + index = CONNECTOR_ID_MIRROR; + } + + states[index].unchanged ++; + + may_sleep = states[index].unchanged >= ATTEMPTS_BEFORE_STOP; + + if (!lx_emul_i915_blit(index, may_sleep)) { + if (!may_sleep) + block_task = false; + + continue; + } + + block_task = false; + + states[index].unchanged = 0; + + if (states[index].fbs) + mark_framebuffer_dirty(states[index].fbs); } + drm_connector_list_iter_end(&conn_iter); - retry_count = 0; - - if (lx_emul_i915_config_done_and_block()) + if (block_task) lx_emul_task_schedule(true /* block task */); + else + /* schedule_timeout(jiffes) or hrtimer or msleep */ + msleep(CAPTURE_RATE_MS); } return 0; @@ -475,24 +839,39 @@ static int configure_connectors(void * data) void lx_user_init(void) { - int pid = kernel_thread(configure_connectors, NULL, "lx_user", - CLONE_FS | CLONE_FILES); - lx_user_task = find_task_by_pid_ns(pid, NULL);; + int pid = kernel_thread(do_action_loop, NULL, "lx_user", + CLONE_FS | CLONE_FILES); + int pid2 = kernel_thread(update_content, NULL, "lx_update", + CLONE_FS | CLONE_FILES); + + lx_user_task = find_task_by_pid_ns(pid , NULL); + lx_update_task = find_task_by_pid_ns(pid2, NULL); } -void lx_emul_i915_report(void * genode_data) +static void _report_connectors(void * genode_data, bool const discrete) { - struct drm_connector_list_iter conn_iter; + struct drm_connector_list_iter conn_iter; + struct drm_connector * connector = NULL; - struct drm_device const *dev = dev_client->dev; - struct drm_connector *connector = NULL; - - drm_connector_list_iter_begin(dev, &conn_iter); + drm_connector_list_iter_begin(dev_client->dev, &conn_iter); drm_client_for_each_connector_iter(connector, &conn_iter) { + + bool const valid_fb = connector->index < MAX_CONNECTORS + ? states[connector->index].fbs : false; + + struct genode_mode conf_mode = {}; + + /* read configuration for connector */ + lx_emul_i915_connector_config(connector->name, &conf_mode); + + if ((discrete && conf_mode.mirror) || (!discrete && !conf_mode.mirror)) + continue; + lx_emul_i915_report_connector(connector, genode_data, connector->name, connector->status != connector_status_disconnected, + valid_fb, get_brightness(connector, INVALID_BRIGHTNESS), connector->display_info.width_mm, connector->display_info.height_mm); @@ -501,17 +880,35 @@ void lx_emul_i915_report(void * genode_data) } +void lx_emul_i915_report_discrete(void * genode_data) +{ + _report_connectors(genode_data, true /* discrete */); +} + + +void lx_emul_i915_report_non_discrete(void * genode_data) +{ + _report_connectors(genode_data, false /* non discrete */); +} + + void lx_emul_i915_iterate_modes(void * lx_data, void * genode_data) { - struct drm_connector *connector = lx_data; - struct drm_display_mode *mode = NULL; - struct drm_display_mode *prev_mode = NULL; - unsigned mode_id = 0; + struct drm_connector * connector = lx_data; + struct drm_display_mode * mode = NULL; + struct drm_display_mode * prev_mode = NULL; + unsigned mode_id = 0; + bool quirk_inuse = false; + struct state * state = &states[connector->index]; + struct genode_mode conf_mode = { }; - /* mark modes as unavailable due to max_resolution enforcement */ - struct genode_mode conf_max_mode = { }; - lx_emul_i915_connector_config("dummy", &conf_max_mode); + if (connector->index >= MAX_CONNECTORS) + return; + lx_emul_i915_connector_config(connector->name, &conf_mode); + + /* no fb and conf_mode.enabled is a temporary inconsistent state */ + quirk_inuse = conf_mode.enabled && !state->fbs; list_for_each_entry(mode, &connector->modes, head) { bool skip = false; @@ -521,42 +918,57 @@ void lx_emul_i915_iterate_modes(void * lx_data, void * genode_data) if (!mode) continue; - /* skip duplicates - actually not really, some parameters varies ?! */ + /* skip consecutive similar modes */ if (prev_mode) { + static_assert(sizeof(mode->name) == DRM_DISPLAY_MODE_LEN); skip = (mode->hdisplay == prev_mode->hdisplay) && (mode->vdisplay == prev_mode->vdisplay) && (drm_mode_vrefresh(mode) == drm_mode_vrefresh(prev_mode)) && !strncmp(mode->name, prev_mode->name, DRM_DISPLAY_MODE_LEN); } - if (!skip) { - bool const max_mode = conf_max_mode.max_width && - conf_max_mode.max_height; - bool const inuse = connector->state && connector->state->crtc && - connector->state->crtc->state && - drm_mode_equal(&connector->state->crtc->state->mode, mode); + prev_mode = mode; - struct genode_mode conf_mode = { + { + bool const max_mode = conf_mode.max_width && conf_mode.max_height; + + struct genode_mode config_report = { .width = mode->hdisplay, .height = mode->vdisplay, .width_mm = mode->width_mm, .height_mm = mode->height_mm, .preferred = mode->type & (DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DEFAULT), - .inuse = inuse, + .inuse = !quirk_inuse && state->mode_id == mode_id && state->enabled, + .mirror = state->mirrored, .hz = drm_mode_vrefresh(mode), .id = mode_id, .enabled = !max_mode || - !conf_smaller_max_mode(&conf_max_mode, mode) + !conf_smaller_max_mode(&conf_mode, mode) }; - static_assert(sizeof(conf_mode.name) == DRM_DISPLAY_MODE_LEN); - memcpy(conf_mode.name, mode->name, sizeof(conf_mode.name)); + /* + * Report first usable mode as used mode in the quirk state to + * avoid sending a mode list with no used mode at all, which + * external configuration components may trigger to disable the + * connector. + */ + if (quirk_inuse && config_report.enabled) { + config_report.inuse = true; + quirk_inuse = false; + } - lx_emul_i915_report_modes(genode_data, &conf_mode); + /* skip similar mode and if it is not the used one */ + if (skip && !config_report.inuse) + continue; + + { + static_assert(sizeof(config_report.name) == DRM_DISPLAY_MODE_LEN); + memcpy(config_report.name, mode->name, sizeof(config_report.name)); + } + + lx_emul_i915_report_modes(genode_data, &config_report); } - - prev_mode = mode; } } @@ -573,14 +985,20 @@ void i915_switcheroo_unregister(struct drm_i915_private *i915) } -static int fb_client_hotplug(struct drm_client_dev *client) +static int fb_client_hotplug(struct drm_client_dev *) { - struct drm_mode_set *modeset = NULL; - struct drm_framebuffer *fb = NULL; - int result = -EINVAL; + /* notify Genode side */ + lx_emul_i915_hotplug_connector(); - if (dumb_fb.fb_id) - fb = drm_framebuffer_lookup(client->dev, client->file, dumb_fb.fb_id); + return 0; +} + + +static int probe_and_apply_fbs(struct drm_client_dev *client, bool const detect) +{ + struct drm_modeset_acquire_ctx ctx; + struct drm_mode_set *modeset = NULL; + int result = -EINVAL; /* * Triggers set up of display pipelines for connectors and @@ -590,39 +1008,100 @@ static int fb_client_hotplug(struct drm_client_dev *client) 0 /* auto height */); if (result) { printk("%s: error on modeset probe %d\n", __func__, result); - return 0; + return result; } + /* (re-)assign framebuffers to enabled connectors */ + DRM_MODESET_LOCK_ALL_BEGIN(client->dev, ctx, + DRM_MODESET_ACQUIRE_INTERRUPTIBLE, + result); + /* - * (Re-)assign framebuffer to modeset (lost due to modeset_probe) and - * commit the change. + * (Re-)assign framebuffers to modeset (lost due to modeset_probe) + * and commit the change. */ - if (fb) { - mutex_lock(&client->modeset_mutex); - drm_client_for_each_modeset(modeset, client) { - if (!modeset || !modeset->num_connectors) - continue; + mutex_lock(&client->modeset_mutex); + drm_client_for_each_modeset(modeset, client) { + struct drm_connector * connector = NULL; - modeset->fb = fb; - } - mutex_unlock(&client->modeset_mutex); + if (!modeset) + continue; - /* triggers disablement of encoders attached to disconnected ports */ - result = drm_client_modeset_commit(client); + if (!modeset->num_connectors || !modeset->connectors || !*modeset->connectors) + continue; - if (result) { - printk("%s: error on modeset commit %d%s\n", __func__, result, - (result == -ENOSPC) ? " - ENOSPC" : " - unknown error"); + /* set connector */ + connector = *modeset->connectors; + + if (verbose) + printk("%s:%u %s fb=%px i=%u fbs[i]=%px %s\n", + __func__, __LINE__, + connector->name, modeset->fb, + connector->index, + connector->index < MAX_CONNECTORS ? + states[connector->index].fbs : NULL, + detect ? " - detect run" : " - configure run"); + + modeset->fb = connector->index < MAX_CONNECTORS + ? states[connector->index].fbs + : NULL; + + if (!modeset->fb) { + /* + * If no fb is available for the (new) connector, we have to + * explicitly revert structures prepared by + * drm_client_modeset_probe so that drm_client_modeset_commit + * will accept the modeset. + */ + for (unsigned i = 0; i < modeset->num_connectors; i++) { + drm_connector_put(modeset->connectors[i]); + modeset->connectors[i] = NULL; + } + + modeset->num_connectors = 0; + + if (modeset->mode) { + kfree(modeset->mode); + modeset->mode = NULL; + } + } else { + struct drm_display_mode * mode = NULL; + unsigned mode_id = 0; + + /* check and select right mode in modeset as configured by state[] */ + list_for_each_entry(mode, &connector->modes, head) { + mode_id ++; + + if (!mode) + continue; + + if (states[connector->index].mode_id != mode_id) + continue; + + if (drm_mode_equal(mode, modeset->mode)) + break; + + if (modeset->mode) + kfree(modeset->mode); + + modeset->mode = drm_mode_duplicate(client->dev, mode); + + break; + } } } + mutex_unlock(&client->modeset_mutex); + DRM_MODESET_LOCK_ALL_END(client->dev, ctx, result); - /* notify Genode side */ - lx_emul_i915_hotplug_connector(); + /* triggers also disablement of encoders attached to disconnected ports */ + result = drm_client_modeset_commit(client); - if (fb) - drm_framebuffer_put(fb); + if (result) { + printk("%s: error on modeset commit %d%s\n", __func__, result, + (result == -ENOSPC) ? " - ENOSPC" : " - unknown error"); + } - return 0; + return result; } @@ -670,102 +1149,93 @@ static int register_drm_client(struct drm_device * const dev) } -int user_attach_fb_to_crtc(struct drm_client_dev * const dev, - struct drm_connector const * const connector, - struct drm_crtc const * const crtc, - struct drm_mode_modeinfo const * const mode, - unsigned const fb_id, - bool const enable) -{ - int result = -EINVAL; - uint32_t connectors [1] = { connector->base.id }; - struct drm_mode_crtc crtc_req = { - .set_connectors_ptr = (uintptr_t)(&connectors), - .count_connectors = enable ? 1 : 0, - .crtc_id = crtc->base.id, - .fb_id = fb_id, - .x = 0, - .y = 0, /* position on the framebuffer */ - .gamma_size = 0, - .mode_valid = enable, - .mode = *mode, - }; - - result = drm_mode_setcrtc(dev->dev, &crtc_req, dev->file); - if (result) - drm_err(dev->dev, "%s: failed to set crtc %d\n", __func__, result); - - return result; -} - - -static int user_register_fb(struct drm_client_dev const * const dev, - struct fb_info * const info, - struct drm_mode_fb_cmd2 const * const dumb_fb) +static int user_register_fb(struct drm_client_dev const * const dev, + struct fb_info * const info, + struct drm_framebuffer * const fb, + struct i915_vma ** const vma, + unsigned long * const vma_flags, + unsigned const width_mm, + unsigned const height_mm) { intel_wakeref_t wakeref; int result = -EINVAL; struct i915_gtt_view const view = { .type = I915_GTT_VIEW_NORMAL }; - static struct i915_vma *vma = NULL; - static unsigned long flags = 0; void __iomem *vaddr = NULL; struct drm_i915_private *dev_priv = to_i915(dev->dev); - struct drm_framebuffer *fb = drm_framebuffer_lookup(dev->dev, - dev->file, - dumb_fb->fb_id); - if (!info || !fb) { + if (!info || !fb || !dev_priv || !vma || !vma_flags) { printk("%s:%u error setting up info and fb\n", __func__, __LINE__); return -ENODEV; } - wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm); + if (*vma) { + intel_unpin_fb_vma(*vma, *vma_flags); - if (vma) { - intel_unpin_fb_vma(vma, flags); - - vma = NULL; - flags = 0; + *vma = NULL; + *vma_flags = 0; } + wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm); + /* Pin the GGTT vma for our access via info->screen_base. * This also validates that any existing fb inherited from the * BIOS is suitable for own access. */ - vma = intel_pin_and_fence_fb_obj(fb, false /* phys_cursor */, - &view, false /* use fences */, - &flags); + *vma = intel_pin_and_fence_fb_obj( fb, false /* phys_cursor */, + &view, false /* use fences */, + vma_flags); - if (IS_ERR(vma)) { + if (IS_ERR(*vma)) { intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref); - result = PTR_ERR(vma); - printk("%s:%u error setting vma %d\n", __func__, __LINE__, result); + result = PTR_ERR(*vma); + + printk("%s:%u error setting vma %d\n", __func__, __LINE__, result); + + *vma = NULL; + *vma_flags = 0; + return result; } - vaddr = i915_vma_pin_iomap(vma); + if (!i915_vma_is_map_and_fenceable(*vma)) { + printk("%s: framebuffer not mappable in aperture -> destroying framebuffer\n", + (info && info->par) ? (char *)info->par : "unknown"); + + intel_unpin_fb_vma(*vma, *vma_flags); + + *vma = NULL; + *vma_flags = 0; + + return -ENOSPC; + } + + vaddr = i915_vma_pin_iomap(*vma); + if (IS_ERR(vaddr)) { intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref); result = PTR_ERR(vaddr); printk("%s:%u error pin iomap %d\n", __func__, __LINE__, result); + + intel_unpin_fb_vma(*vma, *vma_flags); + + *vma = NULL; + *vma_flags = 0; + return result; } - /* fill framebuffer info for register_framebuffer */ + /* fill framebuffer info for kernel_register_fb */ info->screen_base = vaddr; - info->screen_size = vma->size; + info->screen_size = (*vma)->size; info->fix.line_length = fb->pitches[0]; info->var.bits_per_pixel = drm_format_info_bpp(fb->format, 0); intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref); - register_framebuffer(info); - - if (fb) - drm_framebuffer_put(fb); + kernel_register_fb(info, width_mm, height_mm); return 0; } @@ -774,33 +1244,25 @@ static int user_register_fb(struct drm_client_dev const * const dev, static int check_resize_fb(struct drm_client_dev * const dev, struct drm_mode_create_dumb * const gem_dumb, struct drm_mode_fb_cmd2 * const dumb_fb, + bool * const resized, unsigned const width, unsigned const height) { int result = -EINVAL; /* paranoia */ - if (!dev || !dev->dev || !dev->file || !gem_dumb || !dumb_fb) + if (!dev || !dev->dev || !dev->file || !gem_dumb || !dumb_fb || !resized) return -ENODEV; + *resized = false; + /* if requested size is smaller, free up current dumb buffer */ if (gem_dumb->width && gem_dumb->height && (gem_dumb->width < width || gem_dumb->height < height)) { - result = drm_mode_rmfb(dev->dev, dumb_fb->fb_id, dev->file); - if (result) { - drm_err(dev->dev, "%s: failed to remove framebufer %d\n", - __func__, result); - } + destroy_fb(dev, gem_dumb, dumb_fb); - result = drm_mode_destroy_dumb(dev->dev, gem_dumb->handle, dev->file); - if (result) { - drm_err(dev->dev, "%s: failed to destroy framebuffer %d\n", - __func__, result); - } - - memset(gem_dumb, 0, sizeof(*gem_dumb)); - memset(dumb_fb, 0, sizeof(*dumb_fb)); + *resized = true; } /* allocate dumb framebuffer, on success a GEM object handle is returned */ @@ -818,6 +1280,8 @@ static int check_resize_fb(struct drm_client_dev * const dev, memset(gem_dumb, 0, sizeof(*gem_dumb)); return -ENODEV; } + + *resized = true; } /* bind framebuffer(GEM object) to drm client */ @@ -840,6 +1304,8 @@ static int check_resize_fb(struct drm_client_dev * const dev, memset(dumb_fb, 0, sizeof(*dumb_fb)); return -ENODEV; } + + *resized = true; } return 0; diff --git a/repos/pc/src/driver/framebuffer/intel/pc/main.cc b/repos/pc/src/driver/framebuffer/intel/pc/main.cc index d480048568..f017107475 100644 --- a/repos/pc/src/driver/framebuffer/intel/pc/main.cc +++ b/repos/pc/src/driver/framebuffer/intel/pc/main.cc @@ -13,7 +13,6 @@ #include <base/attached_rom_dataspace.h> #include <base/component.h> -#include <timer_session/connection.h> #include <capture_session/connection.h> #include <os/pixel_rgb888.h> #include <os/reporter.h> @@ -21,7 +20,6 @@ /* emulation includes */ #include <lx_emul/init.h> -#include <lx_emul/fb.h> #include <lx_emul/task.h> #include <lx_kit/env.h> #include <lx_kit/init.h> @@ -46,79 +44,204 @@ struct Framebuffer::Driver using Attached_rom_system = Constructible<Attached_rom_dataspace>; Env &env; - Timer::Connection timer { env }; + Heap heap { env.ram(), env.rm() }; Attached_rom_dataspace config { env, "config" }; Attached_rom_system system { }; Expanding_reporter reporter { env, "connectors", "connectors" }; + Signal_handler<Driver> process_handler { env.ep(), *this, + &Driver::process_action }; Signal_handler<Driver> config_handler { env.ep(), *this, &Driver::config_update }; - Signal_handler<Driver> timer_handler { env.ep(), *this, - &Driver::handle_timer }; Signal_handler<Driver> scheduler_handler { env.ep(), *this, &Driver::handle_scheduler }; Signal_handler<Driver> system_handler { env.ep(), *this, &Driver::system_update }; - bool update_in_progress { false }; - bool new_config_rom { false }; bool disable_all { false }; - bool disable_report_once { false }; + bool merge_label_changed { false }; + bool verbose { false }; - class Fb + Capture::Connection::Label merge_label { "mirror" }; + + char const * action_name(enum Action const action) { - private: + switch (action) { + case ACTION_IDLE : return "IDLE"; + case ACTION_DETECT_MODES : return "DETECT_MODES"; + case ACTION_CONFIGURE : return "CONFIGURE"; + case ACTION_REPORT : return "REPORT"; + case ACTION_NEW_CONFIG : return "NEW_CONFIG"; + case ACTION_READ_CONFIG : return "READ_CONFIG"; + case ACTION_HOTPLUG : return "HOTPLUG"; + case ACTION_EXIT : return "EXIT"; + case ACTION_FAILED : return "FAILED"; + } + return "UNKNOWN"; + } - Capture::Connection _capture; - Capture::Area const _size; - Capture::Area const _size_phys; - Capture::Connection::Screen _captured_screen; - void * _base; + enum Action active { }; + enum Action pending[31] { }; - /* - * Non_copyable - */ - Fb(const Fb&); - Fb & operator=(const Fb&); + void add_action(enum Action const add, bool may_squash = false) + { + Action * prev { }; - public: - - void paint() - { - using Pixel = Capture::Pixel; - Surface<Pixel> surface((Pixel*)_base, _size_phys); - _captured_screen.apply_to_surface(surface); + for (auto &entry : pending) { + if (entry != ACTION_IDLE) { + prev = &entry; + continue; } - Fb(Env & env, void * base, Capture::Area size, - Capture::Area size_phys) - : - _capture(env), - _size(size), - _size_phys(size_phys), - _captured_screen(_capture, env.rm(), _size), - _base(base) {} - - bool same_setup(void * base, Capture::Area &size, - Capture::Area &size_phys) - { - return ((base == _base) && (size == _size) && - (size_phys == _size_phys)); + /* skip in case the last entry contains the very same to be added */ + if (may_squash && prev && add == *prev) { + if (verbose) + error("action already queued - '", action_name(add), "'"); + return; } + + entry = add; + + if (verbose) + error("action added to queue - '", action_name(add), "'"); + + return; + } + + error("action ", action_name(add), " NOT QUEUED - trouble ahead"); + } + + auto next_action() + { + Action next { ACTION_IDLE }; + Action * prev { }; + + for (auto &entry : pending) { + if (next == ACTION_IDLE) + next = entry; + + if (prev) + *prev = entry; + + prev = &entry; + } + + if (prev) + *prev = ACTION_IDLE; + + if (verbose) + error("action now executing - '", action_name(next), "'"); + + active = next; + + return active; + } + + bool action_in_execution() const { return active != ACTION_IDLE; } + + struct Connector { + using Space = Id_space<Connector>; + using Id = Space::Id; + + Space::Element id_element; + Signal_handler<Connector> capture_wakeup; + + addr_t base { }; + Capture::Area size { }; + Capture::Area size_phys { }; + Capture::Area size_mm { }; + + Constructible<Capture::Connection> capture { }; + Constructible<Capture::Connection::Screen> screen { }; + + Connector(Env &env, Space &space, Id id) + : + id_element(*this, space, id), + capture_wakeup(env.ep(), *this, &Connector::wakeup_handler) + { } + + void wakeup_handler() + { + lx_emul_i915_wakeup(unsigned(id_element.id().value)); + Lx_kit::env().scheduler.execute(); + } }; - Constructible<Fb> fb {}; + Connector::Space ids { }; + bool capture(Connector::Space &ids, Connector::Id const &id, bool const may_stop) + { + using Pixel = Capture::Pixel; + + bool dirty = false; + + ids.apply<Connector>(id, [&](Connector &connector) { + + if (!connector.capture.constructed() || + !connector.screen.constructed()) + return; + + Surface<Pixel> surface((Pixel*)connector.base, connector.size_phys); + + auto box = connector.screen->apply_to_surface(surface); + + if (box.valid()) + dirty = true; + + if (!dirty && may_stop) + connector.capture->capture_stopped(); + + }, [&] () { /* unknown connector id -> no dirty content */ }); + + return dirty; + } + + bool update(Connector &conn, + addr_t const base, + Capture::Area const &size, + Capture::Area const &size_phys, + Capture::Area const &mm, + auto const &label, + bool const force_change) + { + bool same = (base == conn.base) && + (size == conn.size) && + (size_phys == conn.size_phys) && + (mm == conn.size_mm) && + !force_change; + + if (same) + return same; + + conn.base = base; + conn.size = size; + conn.size_phys = size_phys; + conn.size_mm = mm; + + conn.screen .destruct(); + conn.capture.destruct(); + + if (!conn.size.valid()) + return same; + + Capture::Connection::Screen::Attr attr = { .px = conn.size, + .mm = conn.size_mm }; + + conn.capture.construct(env, label); + conn.screen .construct(*conn.capture, env.rm(), attr); + + conn.capture->wakeup_sigh(conn.capture_wakeup); + + return same; + } + + void process_action(); void config_update(); + void config_read(); void system_update(); void generate_report(); void lookup_config(char const *, struct genode_mode &mode); - void handle_timer() - { - if (fb.constructed()) { fb->paint(); } - } - void handle_scheduler() { Lx_kit::env().scheduler.execute(); @@ -150,6 +273,8 @@ struct Framebuffer::Driver }); config.sigh(config_handler); + + config_read(); } void start() @@ -157,9 +282,6 @@ struct Framebuffer::Driver log("--- Intel framebuffer driver started ---"); lx_emul_start_kernel(nullptr); - - timer.sigh(timer_handler); - timer.trigger_periodic(20*1000); } bool apply_config_on_hotplug() const @@ -172,8 +294,7 @@ struct Framebuffer::Driver return apply_config; } - template <typename T> - void with_max_enforcement(T const &fn) const + void with_max_enforcement(auto const &fn) const { unsigned max_width = config.xml().attribute_value("max_width", 0u); unsigned max_height = config.xml().attribute_value("max_height",0u); @@ -182,11 +303,10 @@ struct Framebuffer::Driver fn(max_width, max_height); } - template <typename T> - void with_force(T const &fn) const + void with_force(auto const &node, auto const &fn) const { - unsigned force_width = config.xml().attribute_value("force_width", 0u); - unsigned force_height = config.xml().attribute_value("force_height", 0u); + unsigned force_width = node.attribute_value("width", 0u); + unsigned force_height = node.attribute_value("height", 0u); if (force_width && force_height) fn(force_width, force_height); @@ -234,26 +354,52 @@ struct Framebuffer::Driver enum { MAX_BRIGHTNESS = 100u }; +void Framebuffer::Driver::process_action() +{ + if (action_in_execution()) + return; + + if (!lx_user_task) { + error("no lx user task"); + return; + } + + lx_emul_task_unblock(lx_user_task); + Lx_kit::env().scheduler.execute(); +} + + void Framebuffer::Driver::config_update() +{ + add_action(Action::ACTION_NEW_CONFIG, true); + + if (action_in_execution()) + return; + + Genode::Signal_transmitter(process_handler).submit(); +} + + +void Framebuffer::Driver::config_read() { config.update(); - if (!config.valid() || !lx_user_task) + if (!config.valid()) return; + config.xml().with_optional_sub_node("merge", [&](auto const &node) { + auto const merge_label_before = merge_label; + + merge_label = node.attribute_value("name", String<160>("mirror")); + + merge_label_changed = merge_label_before != merge_label; + }); + if (config.xml().attribute_value("system", false)) { system.construct(Lx_kit::env().env, "system"); system->sigh(system_handler); } else system.destruct(); - - if (update_in_progress) - new_config_rom = true; - else - update_in_progress = true; - - lx_emul_task_unblock(lx_user_task); - Lx_kit::env().scheduler.execute(); } @@ -282,12 +428,8 @@ static Framebuffer::Driver & driver(Genode::Env & env) void Framebuffer::Driver::generate_report() { - if (!config.valid()) - return; - - if (apply_config_on_hotplug() && !disable_report_once) { - disable_report_once = true; - Genode::Signal_transmitter(config_handler).submit(); + if (!config.valid()) { + error("no valid config - report is dropped"); return; } @@ -304,57 +446,87 @@ void Framebuffer::Driver::generate_report() xml.attribute("max_height", height); }); - with_force([&](unsigned width, unsigned height) { - xml.attribute("force_width", width); - xml.attribute("force_height", height); - }); + lx_emul_i915_report_discrete(&xml); - lx_emul_i915_report(&xml); + xml.node("merge", [&] () { + xml.attribute("name", merge_label); + node.with_optional_sub_node("merge", [&](auto const &merge) { + with_force(merge, [&](unsigned width, unsigned height) { + xml.attribute("width", width); + xml.attribute("height", height); + }); + }); + + lx_emul_i915_report_non_discrete(&xml); + }); }); }); - - disable_report_once = false; } void Framebuffer::Driver::lookup_config(char const * const name, struct genode_mode &mode) { + bool mirror_node = false; + /* default settings, possibly overridden by explicit configuration below */ mode.enabled = !disable_all; - mode.brightness = 70 /* percent */; + mode.brightness = 70; /* percent */ + mode.mirror = true; - if (!config.valid() || disable_all) + if (!config.valid()) return; - /* iterate independently of force* ever to get brightness and hz */ - config.xml().for_each_sub_node("connector", [&] (Xml_node &node) { + with_max_enforcement([&](unsigned const width, unsigned const height) { + mode.max_width = width; + mode.max_height = height; + }); + + if (disable_all) + return; + + auto for_each_node = [&](auto const &node, bool const mirror){ using Name = String<32>; Name const con_policy = node.attribute_value("name", Name()); if (con_policy != name) return; + mode.mirror = mirror; mode.enabled = node.attribute_value("enabled", true); + if (!mode.enabled) return; + mode.width = node.attribute_value("width" , 0U); + mode.height = node.attribute_value("height" , 0U); + mode.hz = node.attribute_value("hz" , 0U); + mode.id = node.attribute_value("mode" , 0U); mode.brightness = node.attribute_value("brightness", unsigned(MAX_BRIGHTNESS + 1)); + }; - mode.width = node.attribute_value("width", 0U); - mode.height = node.attribute_value("height", 0U); - mode.hz = node.attribute_value("hz", 0U); - mode.id = node.attribute_value("mode_id", 0U); + /* lookup config of discrete connectors */ + config.xml().for_each_sub_node("connector", [&] (Xml_node const &conn) { + for_each_node(conn, false); }); - with_force([&](unsigned const width, unsigned const height) { - mode.force_width = width; - mode.force_height = height; - }); + /* lookup config of mirrored connectors */ + config.xml().for_each_sub_node("merge", [&] (Xml_node const &merge) { + if (mirror_node) { + error("only one mirror node supported"); + return; + } - with_max_enforcement([&](unsigned const width, unsigned const height) { - mode.max_width = width; - mode.max_height = height; + merge.for_each_sub_node("connector", [&] (Xml_node const &conn) { + for_each_node(conn, true); + }); + + with_force(merge, [&](unsigned const width, unsigned const height) { + mode.force_width = width; + mode.force_height = height; + }); + + mirror_node = true; }); } @@ -366,49 +538,149 @@ unsigned long long driver_max_framebuffer_memory(void) } -/** - * Can be called already as side-effect of `lx_emul_start_kernel`, - * that's why the Driver object needs to be constructed already here. - */ -extern "C" void lx_emul_framebuffer_ready(void * base, unsigned long, - unsigned xres, unsigned yres, - unsigned phys_width, - unsigned phys_height) +void lx_emul_i915_framebuffer_ready(unsigned const connector_id, + char const * const conn_name, + void * const base, + unsigned long, + unsigned const xres, + unsigned const yres, + unsigned const phys_width, + unsigned const phys_height, + unsigned const mm_width, + unsigned const mm_height) { auto &env = Lx_kit::env().env; auto &drv = driver(env); - auto &fb = drv.fb; - Capture::Area area(xres, yres); - Capture::Area area_phys(phys_width, phys_height); + using namespace Genode; - if (fb.constructed()) { - if (fb->same_setup(base, area, area_phys)) + typedef Framebuffer::Driver::Connector Connector; + + auto const id = Connector::Id { connector_id }; + + /* allocate new id for new connector */ + drv.ids.apply<Connector>(id, [&](Connector &) { /* known id */ }, [&](){ + /* ignore unused connector - don't need a object for it */ + if (!base) return; - fb.destruct(); - } + new (drv.heap) Connector (env, drv.ids, id); + }); - /* clear artefacts */ - if (area != area_phys) - Genode::memset(base, 0, area_phys.count() * 4); + drv.ids.apply<Connector>(id, [&](Connector &conn) { - fb.construct(env, base, area, area_phys); + Capture::Area const area (xres, yres); + Capture::Area const area_phys(phys_width, phys_height); - Genode::log("framebuffer reconstructed - virtual=", xres, "x", yres, - " physical=", phys_width, "x", phys_height); + bool const merge = Capture::Connection::Label(conn_name) == "mirror_capture"; + + auto const label = !conn_name + ? Capture::Connection::Label(conn.id_element) + : merge ? drv.merge_label + : Capture::Connection::Label(conn_name); + + bool const same = drv.update(conn, Genode::addr_t(base), area, + area_phys, { mm_width, mm_height}, label, + merge && drv.merge_label_changed); + + if (merge) + drv.merge_label_changed = false; + + if (same) { + lx_emul_i915_wakeup(unsigned(id.value)); + return; + } + + /* clear artefacts */ + if (base && (area != area_phys)) + Genode::memset(base, 0, area_phys.count() * 4); + + String<12> space { }; + for (auto i = label.length(); i < space.capacity() - 1; i++) { + space = String<12>(" ", space); + } + + if (conn.size.valid()) { + if (drv.verbose) + log(space, label, ": capture ", xres, "x", yres, " with " + " framebuffer ", phys_width, "x", phys_height); + + lx_emul_i915_wakeup(unsigned(id.value)); + } else + if (drv.verbose) + log(space, label, ": capture closed ", + merge ? "(was mirror capture)" : ""); + + }, [](){ /* unknown id */ }); } -extern "C" void lx_emul_i915_hotplug_connector() +void lx_emul_i915_hotplug_connector() { - Genode::Env &env = Lx_kit::env().env; - driver(env).generate_report(); + auto & drv = driver(Lx_kit::env().env); + + drv.add_action(Action::ACTION_HOTPLUG, true); + + Genode::Signal_transmitter(drv.process_handler).submit(); +} + + +int lx_emul_i915_action_to_process(int const action_failed) +{ + auto & env = Lx_kit::env().env; + + while (true) { + + auto const action = driver(env).next_action(); + + switch (action) { + case Action::ACTION_HOTPLUG: + if (driver(env).apply_config_on_hotplug()) { + driver(env).add_action(Action::ACTION_DETECT_MODES); + driver(env).add_action(Action::ACTION_CONFIGURE); + driver(env).add_action(Action::ACTION_REPORT); + } else { + driver(env).add_action(Action::ACTION_DETECT_MODES); + driver(env).add_action(Action::ACTION_REPORT); + } + break; + case Action::ACTION_NEW_CONFIG: + driver(env).add_action(Action::ACTION_READ_CONFIG); + driver(env).add_action(Action::ACTION_CONFIGURE); + driver(env).add_action(Action::ACTION_REPORT); + if (driver(env).disable_all) + driver(env).add_action(Action::ACTION_EXIT); + + break; + case Action::ACTION_READ_CONFIG: + driver(env).config_read(); + break; + case Action::ACTION_REPORT: + if (action_failed) { + if (driver(env).verbose) + Genode::warning("previous action failed"); + + /* retry */ + driver(env).add_action(Action::ACTION_HOTPLUG, true); + } else + driver(env).generate_report(); + break; + case Action::ACTION_EXIT: + /* good bye world */ + driver(env).disable_all = false; + Lx_kit::env().env.parent().exit(0); + break; + default: + /* other actions are handled by Linux code */ + return action; + } + } } void lx_emul_i915_report_connector(void * lx_data, void * genode_xml, char const *name, char const connected, + char const /* fb_available */, unsigned brightness, unsigned width_mm, unsigned height_mm) { @@ -416,8 +688,8 @@ void lx_emul_i915_report_connector(void * lx_data, void * genode_xml, xml.node("connector", [&] () { - xml.attribute("name", name); xml.attribute("connected", !!connected); + xml.attribute("name", name); if (width_mm) xml.attribute("width_mm" , width_mm); if (height_mm) @@ -441,17 +713,17 @@ void lx_emul_i915_report_modes(void * genode_xml, struct genode_mode *mode) xml.node("mode", [&] () { - xml.attribute("width", mode->width); - xml.attribute("height", mode->height); - xml.attribute("hz", mode->hz); - xml.attribute("mode_id", mode->id); - xml.attribute("mode_name", mode->name); + xml.attribute("width", mode->width); + xml.attribute("height", mode->height); + xml.attribute("hz", mode->hz); + xml.attribute("id", mode->id); + xml.attribute("name", mode->name); if (mode->width_mm) xml.attribute("width_mm", mode->width_mm); if (mode->height_mm) xml.attribute("height_mm", mode->height_mm); if (!mode->enabled) - xml.attribute("unavailable", true); + xml.attribute("usable", false); if (mode->preferred) xml.attribute("preferred", true); if (mode->inuse) @@ -460,6 +732,16 @@ void lx_emul_i915_report_modes(void * genode_xml, struct genode_mode *mode) } +int lx_emul_i915_blit(unsigned const connector_id, char const may_stop) +{ + auto &drv = driver(Lx_kit::env().env); + + auto const id = Framebuffer::Driver::Connector::Id { connector_id }; + + return drv.capture(drv.ids, id, may_stop); +} + + void lx_emul_i915_connector_config(char * name, struct genode_mode * mode) { if (!mode || !name) @@ -470,28 +752,6 @@ void lx_emul_i915_connector_config(char * name, struct genode_mode * mode) } -int lx_emul_i915_config_done_and_block(void) -{ - auto &state = driver(Lx_kit::env().env); - - bool const new_config = state.new_config_rom; - - state.update_in_progress = false; - state.new_config_rom = false; - - if (state.disable_all) { - state.disable_all = false; - Lx_kit::env().env.parent().exit(0); - } - - if (!new_config) - driver(Lx_kit::env().env).generate_report(); - - /* true if linux task should block, otherwise continue due to new config */ - return !new_config; -} - - void Component::construct(Genode::Env &env) { driver(env).start(); diff --git a/repos/pc/src/driver/framebuffer/intel/pc/spec/x86_32/source.list b/repos/pc/src/driver/framebuffer/intel/pc/spec/x86_32/source.list index 2adf8fbe6d..61dd65c19a 100644 --- a/repos/pc/src/driver/framebuffer/intel/pc/spec/x86_32/source.list +++ b/repos/pc/src/driver/framebuffer/intel/pc/spec/x86_32/source.list @@ -191,6 +191,7 @@ drivers/gpu/drm/i915/i915_active.c drivers/gpu/drm/i915/i915_config.c drivers/gpu/drm/i915/i915_driver.c drivers/gpu/drm/i915/i915_drm_client.c +drivers/gpu/drm/i915/i915_gem_evict.c drivers/gpu/drm/i915/i915_gem_gtt.c drivers/gpu/drm/i915/i915_gem_ww.c drivers/gpu/drm/i915/i915_getparam.c diff --git a/repos/pc/src/driver/framebuffer/intel/pc/spec/x86_64/source.list b/repos/pc/src/driver/framebuffer/intel/pc/spec/x86_64/source.list index e80978deed..99c373c7d0 100644 --- a/repos/pc/src/driver/framebuffer/intel/pc/spec/x86_64/source.list +++ b/repos/pc/src/driver/framebuffer/intel/pc/spec/x86_64/source.list @@ -194,6 +194,7 @@ drivers/gpu/drm/i915/i915_active.c drivers/gpu/drm/i915/i915_config.c drivers/gpu/drm/i915/i915_driver.c drivers/gpu/drm/i915/i915_drm_client.c +drivers/gpu/drm/i915/i915_gem_evict.c drivers/gpu/drm/i915/i915_gem_gtt.c drivers/gpu/drm/i915/i915_gem_ww.c drivers/gpu/drm/i915/i915_getparam.c diff --git a/repos/pc/src/driver/framebuffer/intel/pc/target.inc b/repos/pc/src/driver/framebuffer/intel/pc/target.inc index 93004a960f..d69ff94f46 100644 --- a/repos/pc/src/driver/framebuffer/intel/pc/target.inc +++ b/repos/pc/src/driver/framebuffer/intel/pc/target.inc @@ -15,7 +15,6 @@ SRC_C += dummies.c SRC_C += pci.c SRC_C += lx_emul.c SRC_C += $(notdir $(wildcard $(REL_PRG_DIR)/generated_dummies.c)) -SRC_C += fb.c SRC_C += lx_user.c SRC_C += gem.c SRC_C += lx_emul/common_dummies.c diff --git a/repos/pc/src/driver/nic/pc/lx_user.c b/repos/pc/src/driver/nic/pc/lx_user.c index 5ecfaa43a6..3dbbe4f846 100644 --- a/repos/pc/src/driver/nic/pc/lx_user.c +++ b/repos/pc/src/driver/nic/pc/lx_user.c @@ -11,214 +11,17 @@ * version 2. */ -#include <linux/kthread.h> -#include <linux/netdevice.h> #include <lx_user/init.h> -#include <genode_c_api/uplink.h> -#include <genode_c_api/mac_address_reporter.h> - - -static struct genode_uplink *dev_genode_uplink(struct net_device *dev) -{ - return (struct genode_uplink *)dev->ifalias; -} - - -struct genode_uplink_rx_context -{ - struct net_device *dev; -}; - - -struct genode_uplink_tx_packet_context -{ - struct sk_buff *skb; -}; - - -static unsigned long uplink_tx_packet_content(struct genode_uplink_tx_packet_context *ctx, - char *dst, unsigned long dst_len) -{ - struct sk_buff * const skb = ctx->skb; - - skb_push(skb, ETH_HLEN); - - if (dst_len < skb->len) { - printk("uplink_tx_packet_content: packet exceeds uplink packet size\n"); - memset(dst, 0, dst_len); - return 0; - } - - skb_copy_from_linear_data(skb, dst, skb->len); - - /* clear unused part of the destination buffer */ - memset(dst + skb->len, 0, dst_len - skb->len); - - return skb->len; -} - - -static rx_handler_result_t handle_rx(struct sk_buff **pskb) -{ - struct sk_buff *skb = *pskb; - struct net_device *dev = skb->dev; - struct genode_uplink_tx_packet_context ctx = { .skb = skb }; - struct genode_uplink *uplink = dev_genode_uplink(dev); - - if (!uplink) - return RX_HANDLER_PASS; - - { - bool progress = genode_uplink_tx_packet(uplink, - uplink_tx_packet_content, - &ctx); - if (!progress) - printk("handle_rx: uplink saturated, dropping packet\n"); - } - - kfree_skb(skb); - return RX_HANDLER_CONSUMED; -} - - -/** - * Create Genode uplink for given net device - * - * The uplink is registered at the dev->ifalias pointer. - */ -static void handle_create_uplink(struct net_device *dev) -{ - struct genode_uplink_args args; - - if (dev_genode_uplink(dev)) - return; - - if (!netif_carrier_ok(dev)) - return; - - printk("create uplink for net device %s\n", &dev->name[0]); - - memset(&args, 0, sizeof(args)); - - if (dev->addr_len != sizeof(args.mac_address)) { - printk("error: net device has unexpected addr_len %u\n", dev->addr_len); - return; - } - - { - unsigned i; - for (i = 0; i < dev->addr_len; i++) - args.mac_address[i] = dev->dev_addr[i]; - } - - args.label = &dev->name[0]; - - dev->ifalias = (struct dev_ifalias *)genode_uplink_create(&args); -} - - -static void handle_destroy_uplink(struct net_device *dev) -{ - struct genode_uplink *uplink = dev_genode_uplink(dev); - - if (!uplink) - return; - - if (netif_carrier_ok(dev)) - return; - - genode_uplink_destroy(uplink); - - dev->ifalias = NULL; -} - - -static genode_uplink_rx_result_t uplink_rx_one_packet(struct genode_uplink_rx_context *ctx, - char const *ptr, unsigned long len) -{ - struct sk_buff *skb = alloc_skb(len, GFP_KERNEL); - - if (!skb) { - printk("alloc_skb failed\n"); - return GENODE_UPLINK_RX_RETRY; - } - - skb_copy_to_linear_data(skb, ptr, len); - skb_put(skb, len); - skb->dev = ctx->dev; - - if (dev_queue_xmit(skb) < 0) { - printk("lx_user: failed to xmit packet\n"); - return GENODE_UPLINK_RX_REJECTED; - } - - return GENODE_UPLINK_RX_ACCEPTED; -} - - -static int user_task_function(void *arg) -{ - for (;;) { - - struct net_device *dev; - - for_each_netdev(&init_net, dev) { - struct genode_mac_address dev_addr; - - /* enable link sensing, repeated calls are handled by testing IFF_UP */ - dev_open(dev, 0); - - memcpy(dev_addr.addr, dev->dev_addr, sizeof(dev_addr)); - genode_mac_address_register(dev->name, dev_addr); - - /* install rx handler once */ - if (!netdev_is_rx_handler_busy(dev)) - netdev_rx_handler_register(dev, handle_rx, NULL); - - /* respond to cable plug/unplug */ - handle_create_uplink(dev); - handle_destroy_uplink(dev); - - /* transmit packets received from the uplink session */ - if (netif_carrier_ok(dev)) { - - struct genode_uplink_rx_context ctx = { .dev = dev }; - - while (genode_uplink_rx(dev_genode_uplink(dev), - uplink_rx_one_packet, - &ctx)); - } - }; - - /* block until lx_emul_task_unblock */ - lx_emul_task_schedule(true); - } - return 0; -} - - -struct task_struct *user_task_struct_ptr; /* used by 'Main' for lx_emul_task_unblock */ +#include <lx_emul/nic.h> void lx_user_init(void) { - pid_t pid; - - pid = kernel_thread(user_task_function, NULL, "user_task", CLONE_FS | CLONE_FILES); - - user_task_struct_ptr = find_task_by_pid_ns(pid, NULL); + lx_emul_nic_init(); } -#include <linux/rtnetlink.h> - -/* - * Called whenever the link state changes - */ -void rtmsg_ifinfo(int type, struct net_device * dev, unsigned int change, gfp_t flags, - u32 portid, const struct nlmsghdr *nlh) +void lx_user_handle_io(void) { - /* trigger handle_create_uplink / handle_destroy_uplink */ - if (user_task_struct_ptr) - lx_emul_task_unblock(user_task_struct_ptr); + lx_emul_nic_handle_io(); } diff --git a/repos/pc/src/driver/nic/pc/main.cc b/repos/pc/src/driver/nic/pc/main.cc index f81f6e0dda..22d57541e5 100644 --- a/repos/pc/src/driver/nic/pc/main.cc +++ b/repos/pc/src/driver/nic/pc/main.cc @@ -16,7 +16,7 @@ #include <lx_kit/init.h> #include <lx_kit/env.h> #include <lx_emul/init.h> -#include <lx_emul/task.h> +#include <lx_user/io.h> #include <genode_c_api/uplink.h> #include <genode_c_api/mac_address_reporter.h> @@ -26,8 +26,6 @@ namespace Pc { } -extern task_struct *user_task_struct_ptr; - struct Pc::Main { Env &_env; @@ -52,11 +50,8 @@ struct Pc::Main void _handle_signal() { - if (user_task_struct_ptr) - lx_emul_task_unblock(user_task_struct_ptr); - + lx_user_handle_io(); Lx_kit::env().scheduler.execute(); - genode_uplink_notify_peers(); } diff --git a/repos/pc/src/driver/nic/pc/rtnetlink.c b/repos/pc/src/driver/nic/pc/rtnetlink.c index 78c956d90d..9dac867eae 100644 --- a/repos/pc/src/driver/nic/pc/rtnetlink.c +++ b/repos/pc/src/driver/nic/pc/rtnetlink.c @@ -12,6 +12,7 @@ */ #include <lx_emul.h> +#include <lx_emul/nic.h> #include <net/rtnetlink.h> #include <linux/mutex.h> @@ -56,3 +57,13 @@ void rtnl_unlock(void) { netdev_run_todo(); } + + +/* + * Called whenever the link state changes + */ +void rtmsg_ifinfo(int type, struct net_device * dev, unsigned int change, gfp_t flags, + u32 portid, const struct nlmsghdr *nlh) +{ + lx_emul_nic_handle_io(); +} diff --git a/repos/pc/src/driver/nic/pc/target.inc b/repos/pc/src/driver/nic/pc/target.inc index 3fd76b75d6..94761b45c6 100644 --- a/repos/pc/src/driver/nic/pc/target.inc +++ b/repos/pc/src/driver/nic/pc/target.inc @@ -7,6 +7,7 @@ SRC_CC += main.cc SRC_C += dummies.c SRC_C += lx_emul.c SRC_C += lx_emul/common_dummies.c +SRC_C += lx_emul/nic.c SRC_C += lx_user.c SRC_C += rtnetlink.c diff --git a/repos/pc/src/driver/platform/pc/intel/context_table.cc b/repos/pc/src/driver/platform/pc/intel/context_table.cc index d4cd22b35c..87dd09a35e 100644 --- a/repos/pc/src/driver/platform/pc/intel/context_table.cc +++ b/repos/pc/src/driver/platform/pc/intel/context_table.cc @@ -24,7 +24,6 @@ static void attribute_hex(Genode::Xml_generator & xml, char const * name, void Intel::Context_table::generate(Xml_generator & xml, - Env & env, Report_helper & report_helper) { for_each(0, [&] (Pci::rid_t id) { @@ -51,7 +50,7 @@ void Intel::Context_table::generate(Xml_generator & xml, /* dump stage2 table */ report_helper.with_table<Table3>(stage2_addr, [&] (Table3 & stage2_table) { - stage2_table.generate(xml, env, report_helper); }); + stage2_table.generate(xml, report_helper); }); break; case Hi::Address_width::AGAW_4_LEVEL: using Table4 = Intel::Level_4_translation_table; @@ -59,7 +58,7 @@ void Intel::Context_table::generate(Xml_generator & xml, /* dump stage2 table */ report_helper.with_table<Table4>(stage2_addr, [&] (Table4 & stage2_table) { - stage2_table.generate(xml, env, report_helper); }); + stage2_table.generate(xml, report_helper); }); break; default: xml.node("unsupported-agaw-error", [&] () {}); diff --git a/repos/pc/src/driver/platform/pc/intel/context_table.h b/repos/pc/src/driver/platform/pc/intel/context_table.h index 1aeccd616d..eeff25f413 100644 --- a/repos/pc/src/driver/platform/pc/intel/context_table.h +++ b/repos/pc/src/driver/platform/pc/intel/context_table.h @@ -149,7 +149,7 @@ class Intel::Context_table clflush(&_entries[_lo_index(rid)]); } - void generate(Xml_generator &, Env &, Intel::Report_helper &); + void generate(Xml_generator &, Intel::Report_helper &); void flush_all() { diff --git a/repos/pc/src/driver/platform/pc/intel/invalidator.cc b/repos/pc/src/driver/platform/pc/intel/invalidator.cc new file mode 100644 index 0000000000..ed1b4eaf39 --- /dev/null +++ b/repos/pc/src/driver/platform/pc/intel/invalidator.cc @@ -0,0 +1,218 @@ +/* + * \brief Intel IOMMU invalidation interfaces + * \author Johannes Schlatow + * \date 2024-03-21 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* local includes */ +#include <intel/invalidator.h> +#include <intel/io_mmu.h> + +/** + * Clear IOTLB. + * + * By default, we perform a global invalidation. When provided with a valid + * Domain_id, a domain-specific invalidation is conducted. + * + * See Table 25 for required invalidation scopes. + */ +void Intel::Register_invalidator::invalidate_iotlb(Domain_id domain_id) +{ + using Context_command = Context_mmio::Context_command; + using Iotlb = Iotlb_mmio::Iotlb; + + unsigned requested_scope = Context_command::Cirg::GLOBAL; + if (domain_id.valid()) + requested_scope = Context_command::Cirg::DOMAIN; + + /* wait for ongoing invalidation request to be completed */ + while (_iotlb_mmio.read<Iotlb::Invalidate>()); + + /* invalidate IOTLB */ + _iotlb_mmio.write<Iotlb>(Iotlb::Invalidate::bits(1) | + Iotlb::Iirg::bits(requested_scope) | + Iotlb::Dr::bits(1) | Iotlb::Dw::bits(1) | + Iotlb::Did::bits(domain_id.value)); + + /* wait for completion */ + while (_iotlb_mmio.read<Iotlb::Invalidate>()); + + /* check for errors */ + unsigned actual_scope = _iotlb_mmio.read<Iotlb::Iaig>(); + if (!actual_scope) + error("IOTLB invalidation failed (scope=", requested_scope, ")"); + else if (_verbose && actual_scope < requested_scope) + warning("Performed IOTLB invalidation with different granularity ", + "(requested=", requested_scope, ", actual=", actual_scope, ")"); + + /* + * Note: At the moment we have no practical benefit from implementing + * page-selective invalidation, because + * a) When adding a DMA buffer range, invalidation is only required if + * caching mode is set. This is not supposed to occur on real hardware but + * only in emulators. + * b) Removal of DMA buffer ranges typically occurs only when a domain is + * destructed. In this case, invalidation is not issued for individual + * buffers but for the entire domain once all buffer ranges have been + * removed. + * c) We do not use the register-based invalidation interface if queued + * invalidation is available. + */ +} + + +/** + * Clear context cache + * + * By default, we perform a global invalidation. When provided with a valid + * Domain_id, a domain-specific invalidation is conducted. When a rid is + * provided, a device-specific invalidation is done. + * + * See Table 25 for required invalidation scopes. + */ +void Intel::Register_invalidator::invalidate_context(Domain_id domain_id, Pci::rid_t rid) +{ + using Context_command = Context_mmio::Context_command; + + /* make sure that there is no context invalidation ongoing */ + while (_context_mmio.read<Context_command::Invalidate>()); + + unsigned requested_scope = Context_command::Cirg::GLOBAL; + if (domain_id.valid()) + requested_scope = Context_command::Cirg::DOMAIN; + + if (rid != 0) + requested_scope = Context_command::Cirg::DEVICE; + + /* clear context cache */ + _context_mmio.write<Context_command>(Context_command::Invalidate::bits(1) | + Context_command::Cirg::bits(requested_scope) | + Context_command::Sid::bits(rid) | + Context_command::Did::bits(domain_id.value)); + + /* wait for completion */ + while (_context_mmio.read<Context_command::Invalidate>()); + + /* check for errors */ + unsigned actual_scope = _context_mmio.read<Context_command::Caig>(); + if (!actual_scope) + error("Context-cache invalidation failed (scope=", requested_scope, ")"); + else if (_verbose && actual_scope < requested_scope) + warning("Performed context-cache invalidation with different granularity ", + "(requested=", requested_scope, ", actual=", actual_scope, ")"); +} + + +void Intel::Register_invalidator::invalidate_all(Domain_id domain_id, Pci::rid_t rid) +{ + invalidate_context(domain_id, rid); + + /* XXX clear PASID cache if we ever switch from legacy mode translation */ + + invalidate_iotlb(domain_id); +} + + +/* Clear interrupt entry cache */ +void Intel::Queued_invalidator::invalidate_irq(unsigned idx, bool global) +{ + Descriptor::access_t *entry = _tail(); + Iec::Type::set(*entry, Iec::Type::IEC); + Iec::Global::set(*entry, global ? Iec::Global::GLOBAL : Iec::Global::INDEX); + Iec::Index::set(*entry, idx); + + _next(); + + /* wait for completion */ + while (!_empty()); +} + + +/** + * Clear IOTLB. + * + * By default, we perform a global invalidation. When provided with a valid + * Domain_id, a domain-specific invalidation is conducted. + * + * See Table 25 for required invalidation scopes. + */ +void Intel::Queued_invalidator::invalidate_iotlb(Domain_id domain_id) +{ + unsigned requested_scope = Descriptor::Granularity::GLOBAL; + if (domain_id.valid()) + requested_scope = Descriptor::Granularity::DOMAIN; + + /* clear context cache */ + Descriptor::access_t *entry = _tail(); + Iotlb::Type::set(*entry, Iotlb::Type::IOTLB); + Iotlb::Granularity::set(*entry, requested_scope); + Iotlb::Dr::set(*entry, 1); + Iotlb::Dw::set(*entry, 1); + Iotlb::Domain_id::set(*entry, domain_id.value); + + _next(); + + /* wait for completion */ + while (!_empty()); + + /* + * Note: At the moment we have no practical benefit from implementing + * page-selective invalidation, because + * a) When adding a DMA buffer range, invalidation is only required if + * caching mode is set. This is not supposed to occur on real hardware but + * only in emulators. + * b) Removal of DMA buffer ranges typically occurs only when a domain is + * destructed. In this case, invalidation is not issued for individual + * buffers but for the entire domain once all buffer ranges have been + * removed. + */ +} + + +/** + * Clear context cache + * + * By default, we perform a global invalidation. When provided with a valid + * Domain_id, a domain-specific invalidation is conducted. When a rid is + * provided, a device-specific invalidation is done. + * + * See Table 25 for required invalidation scopes. + */ +void Intel::Queued_invalidator::invalidate_context(Domain_id domain_id, Pci::rid_t rid) +{ + unsigned requested_scope = Descriptor::Granularity::GLOBAL; + if (domain_id.valid()) + requested_scope = Descriptor::Granularity::DOMAIN; + + if (rid != 0) + requested_scope = Descriptor::Granularity::DEVICE_OR_PAGE; + + /* clear context cache */ + Descriptor::access_t *entry = _tail(); + Context::Type::set(*entry, Context::Type::CONTEXT); + Context::Granularity::set(*entry, requested_scope); + Context::Source_id::set(*entry, rid); + Context::Domain_id::set(*entry, domain_id.value); + + _next(); + + /* wait for completion */ + while (!_empty()); +} + + +void Intel::Queued_invalidator::invalidate_all(Domain_id domain_id, Pci::rid_t rid) +{ + invalidate_context(domain_id, rid); + + /* XXX clear PASID cache if we ever switch from legacy mode translation */ + + invalidate_iotlb(domain_id); +} diff --git a/repos/pc/src/driver/platform/pc/intel/invalidator.h b/repos/pc/src/driver/platform/pc/intel/invalidator.h new file mode 100644 index 0000000000..6a3f968253 --- /dev/null +++ b/repos/pc/src/driver/platform/pc/intel/invalidator.h @@ -0,0 +1,255 @@ +/* + * \brief Intel IOMMU invalidation interfaces + * \author Johannes Schlatow + * \date 2024-03-21 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _SRC__DRIVERS__PLATFORM__INTEL__INVALIDATOR_H_ +#define _SRC__DRIVERS__PLATFORM__INTEL__INVALIDATOR_H_ + +/* Genode includes */ +#include <util/mmio.h> +#include <base/attached_ram_dataspace.h> +#include <pci/types.h> + +/* local includes */ +#include <intel/domain_allocator.h> + +namespace Intel { + using namespace Genode; + + class Io_mmu; /* forward declaration */ + class Invalidator; + class Register_invalidator; + class Queued_invalidator; +} + + +class Intel::Invalidator +{ + public: + + virtual ~Invalidator() { } + + virtual void invalidate_irq(unsigned, bool) { }; + virtual void invalidate_iotlb(Domain_id) = 0; + virtual void invalidate_context(Domain_id domain, Pci::rid_t) = 0; + virtual void invalidate_all(Domain_id domain = Domain_id { Domain_id::INVALID }, + Pci::rid_t = 0) = 0; +}; + + +class Intel::Register_invalidator : public Invalidator +{ + private: + + struct Context_mmio : Mmio<8> + { + struct Context_command : Register<0x0, 64> + { + struct Invalidate : Bitfield<63,1> { }; + + /* invalidation request granularity */ + struct Cirg : Bitfield<61,2> + { + enum { + GLOBAL = 0x1, + DOMAIN = 0x2, + DEVICE = 0x3 + }; + }; + + /* actual invalidation granularity */ + struct Caig : Bitfield<59,2> { }; + + /* source id */ + struct Sid : Bitfield<16,16> { }; + + /* domain id */ + struct Did : Bitfield<0,16> { }; + }; + + Context_mmio(Byte_range_ptr const &range) + : Mmio<8>(range) + { } + } _context_mmio; + + struct Iotlb_mmio : Mmio<16> + { + struct Iotlb : Register<0x8, 64> + { + struct Invalidate : Bitfield<63,1> { }; + + /* IOTLB invalidation request granularity */ + struct Iirg : Bitfield<60,2> + { + enum { + GLOBAL = 0x1, + DOMAIN = 0x2, + DEVICE = 0x3 + }; + }; + + /* IOTLB actual invalidation granularity */ + struct Iaig : Bitfield<57,2> { }; + + /* drain reads/writes */ + struct Dr : Bitfield<49,1> { }; + struct Dw : Bitfield<48,1> { }; + + /* domain id */ + struct Did : Bitfield<32,16> { }; + }; + + Iotlb_mmio(Byte_range_ptr const &range) + : Mmio<16>(range) + { } + } _iotlb_mmio; + + bool _verbose; + + public: + + void invalidate_iotlb(Domain_id) override; + void invalidate_context(Domain_id domain, Pci::rid_t) override; + void invalidate_all(Domain_id domain = Domain_id { Domain_id::INVALID }, + Pci::rid_t = 0) override; + + Register_invalidator(addr_t context_reg_base, addr_t iotlb_reg_base, bool verbose) + : _context_mmio({(char*)context_reg_base, 8}), + _iotlb_mmio ({(char*)iotlb_reg_base, 16}), + _verbose(verbose) + { } +}; + + +class Intel::Queued_invalidator : public Invalidator +{ + private: + + struct Queue_mmio : Mmio<56> + { + struct Head : Register<0x0, 64> + { + }; + + struct Tail : Register<0x8, 64> + { + }; + + struct Address : Register<0x10, 64> + { + struct Size : Bitfield< 0,3> { enum { SIZE_4K = 0}; }; + struct Width : Bitfield<11,1> { enum { WIDTH_128 = 0}; }; + struct Base : Bitfield<12,52> { }; + }; + + Queue_mmio(Byte_range_ptr const &range) + : Mmio<56>(range) + { } + + } _queue_mmio; + + Attached_ram_dataspace _queue; + + /* + * descriptor definitions + */ + + struct Descriptor : Genode::Register<64> + { + struct Type_0_3 : Bitfield<0,4> { }; + struct Type_4_6 : Bitfield<9,3> { }; + struct Type : Bitset_2<Type_0_3, Type_4_6> + { + enum { + CONTEXT = 1, + IOTLB = 2, + IEC = 4 + }; + }; + + struct Granularity : Bitfield<4,2> { + enum { + GLOBAL = 0x1, + DOMAIN = 0x2, + DEVICE_OR_PAGE = 0x3 + }; + }; + + struct Domain_id : Bitfield<16,16> { }; + }; + + struct Context : Descriptor + { + struct Source_id : Bitfield<32,16> { }; + }; + + struct Iotlb : Descriptor + { + /* drain reads/writes */ + struct Dw : Bitfield<6,1> { }; + struct Dr : Bitfield<7,1> { }; + }; + + struct Iec : Descriptor + { + struct Global : Bitfield<4,1> { + enum { + GLOBAL = 0, + INDEX = 1 + }; + }; + struct Index : Bitfield<32,16> { }; + }; + + bool _empty() { + return _queue_mmio.read<Queue_mmio::Head>() == _queue_mmio.read<Queue_mmio::Tail>(); } + + Descriptor::access_t *_tail() { + return (Descriptor::access_t*)(_queue_mmio.read<Queue_mmio::Tail>() + (addr_t)_queue.local_addr<void>()); } + + void _next() + { + addr_t tail_offset = _queue_mmio.read<Queue_mmio::Tail>(); + + tail_offset += 16; + if (tail_offset >= 0x1000) + tail_offset = 0; + + _queue_mmio.write<Queue_mmio::Tail>(tail_offset); + } + + public: + + void invalidate_irq(unsigned, bool) override; + void invalidate_iotlb(Domain_id) override; + void invalidate_context(Domain_id domain, Pci::rid_t) override; + void invalidate_all(Domain_id domain = Domain_id { Domain_id::INVALID }, + Pci::rid_t = 0) override; + + Queued_invalidator(Genode::Env & env, addr_t queue_reg_base) + : _queue_mmio({(char*)queue_reg_base, 56}), + _queue(env.ram(), env.rm(), 4096, Cache::CACHED) + { + /* set tail register to zero*/ + _queue_mmio.write<Queue_mmio::Tail>(0); + + /* write physical address of invalidation queue into address register */ + using Address = Queue_mmio::Address; + addr_t queue_paddr = env.pd().dma_addr(_queue.cap()); + _queue_mmio.write<Address>(Address::Base::masked(queue_paddr) | + Address::Size::bits(Address::Size::SIZE_4K) | + Address::Width::bits(Address::Width::WIDTH_128)); + } +}; + + +#endif /* _SRC__DRIVERS__PLATFORM__INTEL__INVALIDATOR_H_ */ diff --git a/repos/pc/src/driver/platform/pc/intel/io_mmu.cc b/repos/pc/src/driver/platform/pc/intel/io_mmu.cc index 1c50d5ae4d..0335cbf98d 100644 --- a/repos/pc/src/driver/platform/pc/intel/io_mmu.cc +++ b/repos/pc/src/driver/platform/pc/intel/io_mmu.cc @@ -43,9 +43,9 @@ void Intel::Io_mmu::Domain<TABLE>::enable_pci_device(Io_mem_dataspace_capability * unless invalidation takes place. */ if (cur_domain.valid()) - _intel_iommu.invalidate_all(cur_domain, Pci::Bdf::rid(bdf)); + _intel_iommu.invalidator().invalidate_all(cur_domain, Pci::Bdf::rid(bdf)); else if (_intel_iommu.caching_mode()) - _intel_iommu.invalidate_context(Domain_id(), Pci::Bdf::rid(bdf)); + _intel_iommu.invalidator().invalidate_context(Domain_id(), Pci::Bdf::rid(bdf)); else _intel_iommu.flush_write_buffer(); } @@ -59,7 +59,7 @@ void Intel::Io_mmu::Domain<TABLE>::disable_pci_device(Pci::Bdf const & bdf) /* lookup default mappings and insert instead */ _intel_iommu.apply_default_mappings(bdf); - _intel_iommu.invalidate_all(_domain_id); + _intel_iommu.invalidator().invalidate_all(_domain_id); } @@ -97,7 +97,7 @@ void Intel::Io_mmu::Domain<TABLE>::add_range(Range const & range, /* only invalidate iotlb if failed requests are cached */ if (_intel_iommu.caching_mode()) - _intel_iommu.invalidate_iotlb(_domain_id, vaddr, size); + _intel_iommu.invalidator().invalidate_iotlb(_domain_id); else _intel_iommu.flush_write_buffer(); } @@ -111,7 +111,7 @@ void Intel::Io_mmu::Domain<TABLE>::remove_range(Range const & range) !_intel_iommu.coherent_page_walk()); if (!_skip_invalidation) - _intel_iommu.invalidate_iotlb(_domain_id, range.start, range.size); + _intel_iommu.invalidator().invalidate_iotlb(_domain_id); } @@ -136,104 +136,12 @@ void Intel::Io_mmu::flush_write_buffer() } -/** - * Clear IOTLB. - * - * By default, we perform a global invalidation. When provided with a valid - * Domain_id, a domain-specific invalidation is conducted. If provided with - * a DMA address and size, a page-selective invalidation is performed. - * - * See Table 25 for required invalidation scopes. - */ -void Intel::Io_mmu::invalidate_iotlb(Domain_id domain_id, addr_t, size_t) +Intel::Invalidator & Intel::Io_mmu::invalidator() { - unsigned requested_scope = Context_command::Cirg::GLOBAL; - if (domain_id.valid()) - requested_scope = Context_command::Cirg::DOMAIN; - - /* wait for ongoing invalidation request to be completed */ - while (Iotlb::Invalidate::get(read_iotlb_reg())); - - /* invalidate IOTLB */ - write_iotlb_reg(Iotlb::Invalidate::bits(1) | - Iotlb::Iirg::bits(requested_scope) | - Iotlb::Dr::bits(1) | Iotlb::Dw::bits(1) | - Iotlb::Did::bits(domain_id.value)); - - /* wait for completion */ - while (Iotlb::Invalidate::get(read_iotlb_reg())); - - /* check for errors */ - unsigned actual_scope = Iotlb::Iaig::get(read_iotlb_reg()); - if (!actual_scope) - error("IOTLB invalidation failed (scope=", requested_scope, ")"); - else if (_verbose && actual_scope < requested_scope) - warning("Performed IOTLB invalidation with different granularity ", - "(requested=", requested_scope, ", actual=", actual_scope, ")"); - - /* XXX implement page-selective-within-domain IOTLB invalidation */ -} - -/** - * Clear context cache - * - * By default, we perform a global invalidation. When provided with a valid - * Domain_id, a domain-specific invalidation is conducted. When a rid is - * provided, a device-specific invalidation is done. - * - * See Table 25 for required invalidation scopes. - */ -void Intel::Io_mmu::invalidate_context(Domain_id domain_id, Pci::rid_t rid) -{ - /** - * We are using the register-based invalidation interface for the - * moment. This is only supported in legacy mode and for major - * architecture version 5 and lower (cf. 6.5). - */ - - if (read<Version::Major>() > 5) { - error("Unable to invalidate caches: Register-based invalidation only ", - "supported in architecture versions 5 and lower"); - return; - } - - /* make sure that there is no context invalidation ongoing */ - while (read<Context_command::Invalidate>()); - - unsigned requested_scope = Context_command::Cirg::GLOBAL; - if (domain_id.valid()) - requested_scope = Context_command::Cirg::DOMAIN; - - if (rid != 0) - requested_scope = Context_command::Cirg::DEVICE; - - /* clear context cache */ - write<Context_command>(Context_command::Invalidate::bits(1) | - Context_command::Cirg::bits(requested_scope) | - Context_command::Sid::bits(rid) | - Context_command::Did::bits(domain_id.value)); - - - /* wait for completion */ - while (read<Context_command::Invalidate>()); - - /* check for errors */ - unsigned actual_scope = read<Context_command::Caig>(); - if (!actual_scope) - error("Context-cache invalidation failed (scope=", requested_scope, ")"); - else if (_verbose && actual_scope < requested_scope) - warning("Performed context-cache invalidation with different granularity ", - "(requested=", requested_scope, ", actual=", actual_scope, ")"); -} - - -void Intel::Io_mmu::invalidate_all(Domain_id domain_id, Pci::rid_t rid) -{ - invalidate_context(domain_id, rid); - - /* XXX clear PASID cache if we ever switch from legacy mode translation */ - - invalidate_iotlb(domain_id, 0, 0); + if (!read<Global_status::Qies>()) + return *_register_invalidator; + else + return *_queued_invalidator; } @@ -249,6 +157,12 @@ void Intel::Io_mmu::_handle_faults() if (read<Fault_status::Iqe>()) error("Invalidation queue error"); + if (read<Fault_status::Ice>()) + error("Invalidation completion error"); + + if (read<Fault_status::Ite>()) + error("Invalidation time-out error"); + /* acknowledge all faults */ write<Fault_status>(0x7d); @@ -347,6 +261,9 @@ void Intel::Io_mmu::generate(Xml_generator & xml) xml.attribute("mask", (bool)read<Fault_event_control::Mask>()); }); + if (read<Global_status::Irtps>()) + _irq_table.generate(xml); + if (!read<Global_status::Rtps>()) return; @@ -365,7 +282,7 @@ void Intel::Io_mmu::generate(Xml_generator & xml) /* dump root table, context table, and page tables */ _report_helper.with_table<Root_table>(rt_addr, [&] (Root_table & root_table) { - root_table.generate(xml, _env, _report_helper); + root_table.generate(xml, _report_helper); }); }); } @@ -398,6 +315,62 @@ void Intel::Io_mmu::default_mappings_complete() /* insert contexts into managed root table */ _default_mappings.copy_stage2(_managed_root_table); + _enable_translation(); + + log("enabled IOMMU ", name(), " with default mappings"); +} + + +void Intel::Io_mmu::resume() +{ + _init(); + _enable_translation(); + _enable_irq_remapping(); +} + + +void Intel::Io_mmu::_enable_irq_remapping() +{ + /* + * If IRQ remapping has already been enabled during boot, the kernel is + * in charge of the remapping. Since there is no way to get the required + * unremapped vector for requested MSI, we cannot take over control. + */ + + if (read<Global_status::Ires>()) { + warning("IRQ remapping is controlled by kernel for ", name()); + return; + } + + /* caches must be cleared if Esirtps is not set */ + if (read<Capability::Esirtps>()) + invalidator().invalidate_irq(0, true); + + /* set interrupt remapping table address */ + write<Irq_table_address>( + Irq_table_address::Size::bits(Irq_table::ENTRIES_LOG2-1) | + Irq_table_address::Address::masked(_irq_table_phys)); + + /* issue set interrupt remapping table pointer command */ + _global_command<Global_command::Sirtp>(1); + + /* disable compatibility format interrupts */ + _global_command<Global_command::Cfi>(0); + + /* enable interrupt remapping */ + _global_command<Global_command::Ire>(1); + + log("enabled interrupt remapping for ", name()); + + _remap_irqs = true; +} + + +void Intel::Io_mmu::_enable_translation() +{ + Root_table_address::access_t rtp = + Root_table_address::Address::masked(_managed_root_table.phys_addr()); + /* set root table address */ write<Root_table_address>(rtp); @@ -406,48 +379,55 @@ void Intel::Io_mmu::default_mappings_complete() /* caches must be cleared if Esrtps is not set (see 6.6) */ if (!read<Capability::Esrtps>()) - invalidate_all(); + invalidator().invalidate_all(); /* enable IOMMU */ if (!read<Global_status::Enabled>()) _global_command<Global_command::Enable>(1); - - log("enabled IOMMU ", name(), " with default mappings"); } -void Intel::Io_mmu::suspend() +void Intel::Io_mmu::_init() { - _s3_fec = read<Fault_event_control>(); - _s3_fedata = read<Fault_event_data>(); - _s3_feaddr = read<Fault_event_address>(); - _s3_rta = read<Root_table_address>(); -} + if (read<Global_status::Enabled>()) { + log("IOMMU has been enabled during boot"); - -void Intel::Io_mmu::resume() -{ - /* disable queued invalidation interface if it was re-enabled by kernel */ - if (read<Global_status::Enabled>() && read<Global_status::Qies>()) - _global_command<Global_command::Qie>(false); - - /* restore fault events only if kernel did not enable IRQ remapping */ - if (!read<Global_status::Ires>()) { - write<Fault_event_control>(_s3_fec); - write<Fault_event_data>(_s3_fedata); - write<Fault_event_address>(_s3_feaddr); + /* disable queued invalidation interface */ + if (read<Global_status::Qies>()) + _global_command<Global_command::Qie>(false); } - /* issue set root table pointer command */ - write<Root_table_address>(_s3_rta); - _global_command<Global_command::Srtp>(1); + if (read<Extended_capability::Qi>()) { + /* enable queued invalidation if supported */ + _queued_invalidator.construct(_env, base() + 0x80); + _global_command<Global_command::Qie>(true); + } else { + /* use register-based invalidation interface as fallback */ + addr_t context_reg_base = base() + 0x28; + addr_t iotlb_reg_base = base() + 8*_offset<Extended_capability::Iro>(); + _register_invalidator.construct(context_reg_base, iotlb_reg_base, _verbose); + } - if (!read<Capability::Esrtps>()) - invalidate_all(); + /* enable fault event interrupts if desired */ + if (_fault_irq.constructed()) { + Irq_session::Info info = _fault_irq->info(); - /* enable IOMMU */ - if (!read<Global_status::Enabled>()) - _global_command<Global_command::Enable>(1); + if (info.type == Irq_session::Info::INVALID) + error("Unable to enable fault event interrupts for ", _name); + else { + write<Fault_event_address>((Fault_event_address::access_t)info.address); + write<Fault_event_data>((Fault_event_data::access_t)info.value); + write<Fault_event_control::Mask>(0); + } + } + + /* + * We always enable IRQ remapping if its supported by the IOMMU. Note, there + * might be the possibility that the ACPI DMAR table says otherwise but + * we've never seen such a case yet. + */ + if (read<Extended_capability::Ir>()) + _enable_irq_remapping(); } @@ -460,10 +440,11 @@ Intel::Io_mmu::Io_mmu(Env & env, : Attached_mmio(env, {(char *)range.start, range.size}), Driver::Io_mmu(io_mmu_devices, name), _env(env), - _managed_root_table(_env, table_allocator, *this, !coherent_page_walk()), - _default_mappings(_env, table_allocator, *this, !coherent_page_walk(), - _sagaw_to_levels()), - _domain_allocator(_max_domains()-1) + _table_allocator(table_allocator), + _domain_allocator(_max_domains()-1), + _managed_root_table(_env, _table_allocator, *this, !coherent_page_walk()), + _default_mappings(_env, _table_allocator, *this, !coherent_page_walk(), + _sagaw_to_levels()) { if (_broken_device()) { error(name, " reports invalid capability registers. Please disable VT-d/IOMMU."); @@ -475,28 +456,13 @@ Intel::Io_mmu::Io_mmu(Env & env, return; } - if (read<Global_status::Enabled>()) { - log("IOMMU has been enabled during boot"); - - /* disable queued invalidation interface */ - if (read<Global_status::Qies>()) - _global_command<Global_command::Qie>(false); - } - /* enable fault event interrupts (if not already enabled by kernel) */ if (irq_number && !read<Global_status::Ires>()) { _fault_irq.construct(_env, irq_number, 0, Irq_session::TYPE_MSI); _fault_irq->sigh(_fault_handler); _fault_irq->ack_irq(); - - Irq_session::Info info = _fault_irq->info(); - if (info.type == Irq_session::Info::INVALID) - error("Unable to enable fault event interrupts for ", name); - else { - write<Fault_event_address>((Fault_event_address::access_t)info.address); - write<Fault_event_data>((Fault_event_data::access_t)info.value); - write<Fault_event_control::Mask>(0); - } } + + _init(); } diff --git a/repos/pc/src/driver/platform/pc/intel/io_mmu.h b/repos/pc/src/driver/platform/pc/intel/io_mmu.h index 2760073d81..4ebabe7d9a 100644 --- a/repos/pc/src/driver/platform/pc/intel/io_mmu.h +++ b/repos/pc/src/driver/platform/pc/intel/io_mmu.h @@ -31,6 +31,8 @@ #include <intel/page_table.h> #include <intel/domain_allocator.h> #include <intel/default_mappings.h> +#include <intel/invalidator.h> +#include <intel/irq_remap_table.h> #include <expanding_page_table_allocator.h> namespace Intel { @@ -39,6 +41,14 @@ namespace Intel { using Context_table_allocator = Managed_root_table::Allocator; + /** + * We use a 4KB interrupt remap table since kernels (nova, hw) do not + * support more than 256 interrupts anyway. We can thus reuse the + * context-table allocator. + */ + using Irq_table = Irq_remap_table<12>; + using Irq_allocator = Irq_table::Irq_allocator; + class Io_mmu; class Io_mmu_factory; } @@ -50,6 +60,8 @@ class Intel::Io_mmu : private Attached_mmio<0x800>, { public: + friend class Register_invalidator; + /* Use derived domain class to store reference to buffer registry */ template <typename TABLE> class Domain : public Driver::Io_mmu::Domain, @@ -68,6 +80,7 @@ class Intel::Io_mmu : private Attached_mmio<0x800>, Domain_allocator & _domain_allocator; Domain_id _domain_id { _domain_allocator.alloc() }; bool _skip_invalidation { false }; + Irq_allocator & _irq_allocator; addr_t _translation_table_phys { _table_allocator.construct<TABLE>() }; @@ -92,7 +105,7 @@ class Intel::Io_mmu : private Attached_mmio<0x800>, _domain._skip_invalidation = false; if (_requires_invalidation) - _domain._intel_iommu.invalidate_all(_domain._domain_id); + _domain._intel_iommu.invalidator().invalidate_all(_domain._domain_id); else _domain._intel_iommu.flush_write_buffer(); } @@ -128,7 +141,8 @@ class Intel::Io_mmu : private Attached_mmio<0x800>, Registry<Dma_buffer> const & buffer_registry, Env & env, Ram_allocator & ram_alloc, - Domain_allocator & domain_allocator) + Domain_allocator & domain_allocator, + Irq_allocator & irq_allocator) : Driver::Io_mmu::Domain(intel_iommu, md_alloc), Registered_translation_table(intel_iommu), _intel_iommu(intel_iommu), @@ -136,7 +150,8 @@ class Intel::Io_mmu : private Attached_mmio<0x800>, _ram_alloc(ram_alloc), _buffer_registry(buffer_registry), _table_allocator(_env, md_alloc, ram_alloc, 2), - _domain_allocator(domain_allocator) + _domain_allocator(domain_allocator), + _irq_allocator(irq_allocator) { Invalidation_guard guard { *this, _intel_iommu.caching_mode() }; @@ -165,7 +180,39 @@ class Intel::Io_mmu : private Attached_mmio<0x800>, private: - Env & _env; + static + Irq_table & _irq_table_virt(Context_table_allocator & alloc, addr_t phys) + { + addr_t va { 0 }; + + alloc.with_table<Irq_table>(phys, + [&] (Irq_table & t) { va = (addr_t)&t; }, + [&] () { /* never reached */ }); + + /** + * Dereferencing is save because _irq_table_phys is never 0 + * (allocator throws exception) and with_table() thus always sets + * a valid virtual address. + */ + return *(Irq_table*)va; + } + + + Env & _env; + bool _verbose { false }; + Context_table_allocator & _table_allocator; + + const addr_t _irq_table_phys { + _table_allocator.construct<Irq_table>() }; + + Irq_table & _irq_table { + _irq_table_virt(_table_allocator, _irq_table_phys) }; + + Irq_allocator _irq_allocator { }; + + Report_helper _report_helper { *this }; + Domain_allocator _domain_allocator; + Domain_id _default_domain { _domain_allocator.alloc() }; /** * For a start, we keep a distinct root table for every hardware unit. @@ -181,16 +228,18 @@ class Intel::Io_mmu : private Attached_mmio<0x800>, * The default root table holds default mappings (e.g. reserved memory) * that needs to be accessible even if devices have not been acquired yet. */ - bool _verbose { false }; Managed_root_table _managed_root_table; Default_mappings _default_mappings; - Report_helper _report_helper { *this }; - Domain_allocator _domain_allocator; - Domain_id _default_domain { _domain_allocator.alloc() }; + + bool _remap_irqs { false }; + Constructible<Irq_connection> _fault_irq { }; Signal_handler<Io_mmu> _fault_handler { _env.ep(), *this, &Io_mmu::_handle_faults }; + Constructible<Register_invalidator> _register_invalidator { }; + Constructible<Queued_invalidator> _queued_invalidator { }; + /** * Registers */ @@ -238,6 +287,9 @@ class Intel::Io_mmu : private Attached_mmio<0x800>, /* interrupt remapping support */ struct Ir : Bitfield<3,1> { }; + /* queued-invalidation support */ + struct Qi : Bitfield<1,1> { }; + struct Page_walk_coherency : Bitfield<0,1> { }; }; @@ -254,8 +306,14 @@ class Intel::Io_mmu : private Attached_mmio<0x800>, /* queued invalidation enable */ struct Qie : Bitfield<26,1> { }; + /* interrupt remapping enable */ + struct Ire : Bitfield<25,1> { }; + /* set interrupt remap table pointer */ struct Sirtp : Bitfield<24,1> { }; + + /* compatibility format interrupts */ + struct Cfi : Bitfield<23,1> { }; }; struct Global_status : Register<0x1c, 32> @@ -287,28 +345,12 @@ class Intel::Io_mmu : private Attached_mmio<0x800>, struct Address : Bitfield<12,52> { }; }; - struct Context_command : Register<0x28, 64> + struct Irq_table_address : Register<0xB8, 64> { - struct Invalidate : Bitfield<63,1> { }; + struct Size : Bitfield< 0, 4> { }; + struct Address : Bitfield<12,52> { }; - /* invalidation request granularity */ - struct Cirg : Bitfield<61,2> - { - enum { - GLOBAL = 0x1, - DOMAIN = 0x2, - DEVICE = 0x3 - }; - }; - - /* actual invalidation granularity */ - struct Caig : Bitfield<59,2> { }; - - /* source id */ - struct Sid : Bitfield<16,16> { }; - - /* domain id */ - struct Did : Bitfield<0,16> { }; + /* not using extended interrupt mode (x2APIC) */ }; struct Fault_status : Register<0x34, 32> @@ -316,6 +358,12 @@ class Intel::Io_mmu : private Attached_mmio<0x800>, /* fault record index */ struct Fri : Bitfield<8,8> { }; + /* invalidation time-out error */ + struct Ite : Bitfield<6,1> { }; + + /* invalidation completion error */ + struct Ice : Bitfield<5,1> { }; + /* invalidation queue error */ struct Iqe : Bitfield<4,1> { }; @@ -383,38 +431,6 @@ class Intel::Io_mmu : private Attached_mmio<0x800>, struct Info : Bitfield<12,52> { }; }; - struct Iotlb : Genode::Register<64> - { - struct Invalidate : Bitfield<63,1> { }; - - /* IOTLB invalidation request granularity */ - struct Iirg : Bitfield<60,2> - { - enum { - GLOBAL = 0x1, - DOMAIN = 0x2, - DEVICE = 0x3 - }; - }; - - /* IOTLB actual invalidation granularity */ - struct Iaig : Bitfield<57,2> { }; - - /* drain reads/writes */ - struct Dr : Bitfield<49,1> { }; - struct Dw : Bitfield<48,1> { }; - - /* domain id */ - struct Did : Bitfield<32,16> { }; - - }; - - /* saved registers during suspend */ - Fault_event_control::access_t _s3_fec { }; - Fault_event_data ::access_t _s3_fedata { }; - Fault_event_address ::access_t _s3_feaddr { }; - Root_table_address::access_t _s3_rta { }; - uint32_t _max_domains() { return 1 << (4 + read<Capability::Domains>()*2); } @@ -461,12 +477,6 @@ class Intel::Io_mmu : private Attached_mmio<0x800>, All_registers::access_t read_offset_register(unsigned index) { return read<All_registers>(_offset<OFFSET_BITFIELD>() + index); } - void write_iotlb_reg(Iotlb::access_t v) { - write_offset_register<Extended_capability::Iro>(1, v); } - - Iotlb::access_t read_iotlb_reg() { - return read_offset_register<Extended_capability::Iro>(1); } - template <typename REG> REG::access_t read_fault_record(unsigned index) { return read_offset_register<Capability::Fro>(index*2 + REG::offset()); } @@ -478,6 +488,12 @@ class Intel::Io_mmu : private Attached_mmio<0x800>, void _handle_faults(); + void _enable_irq_remapping(); + + /* utility methods used on boot and resume */ + void _init(); + void _enable_translation(); + /** * Io_mmu interface */ @@ -539,9 +555,7 @@ class Intel::Io_mmu : private Attached_mmio<0x800>, void generate(Xml_generator &) override; - void invalidate_iotlb(Domain_id, addr_t, size_t); - void invalidate_context(Domain_id domain, Pci::rid_t); - void invalidate_all(Domain_id domain = Domain_id { Domain_id::INVALID }, Pci::rid_t = 0); + Invalidator & invalidator(); bool coherent_page_walk() const { return read<Extended_capability::Page_walk_coherency>(); } bool caching_mode() const { return read<Capability::Caching_mode>(); } @@ -552,7 +566,6 @@ class Intel::Io_mmu : private Attached_mmio<0x800>, /** * Io_mmu suspend/resume interface */ - void suspend() override; void resume() override; /** @@ -566,6 +579,33 @@ class Intel::Io_mmu : private Attached_mmio<0x800>, void apply_default_mappings(Pci::Bdf const & bdf) { _default_mappings.copy_stage2(_managed_root_table, bdf); } + /** + * Io_mmu interface for IRQ remapping + */ + void unmap_irq(Pci::Bdf const & bdf, unsigned idx) override + { + if (!_remap_irqs) + return; + + if (_irq_table.unmap(_irq_allocator, bdf, idx)) + invalidator().invalidate_irq(idx, false); + } + + Irq_info map_irq(Pci::Bdf const & bdf, + Irq_info const & info, + Irq_config const & config) override + { + if (!_remap_irqs) + return info; + + return _irq_table.map(_irq_allocator, bdf, info, config, [&] (unsigned idx) { + if (caching_mode()) + invalidator().invalidate_irq(idx, false); + else + flush_write_buffer(); + }); + } + /** * Io_mmu interface */ @@ -583,7 +623,8 @@ class Intel::Io_mmu : private Attached_mmio<0x800>, buffer_registry, _env, ram_alloc, - _domain_allocator); + _domain_allocator, + _irq_allocator); if (!read<Capability::Sagaw_3_level>() && read<Capability::Sagaw_5_level>()) error("IOMMU requires 5-level translation tables (not implemented)"); @@ -594,7 +635,8 @@ class Intel::Io_mmu : private Attached_mmio<0x800>, buffer_registry, _env, ram_alloc, - _domain_allocator); + _domain_allocator, + _irq_allocator); } /** @@ -611,6 +653,7 @@ class Intel::Io_mmu : private Attached_mmio<0x800>, ~Io_mmu() { _domain_allocator.free(_default_domain); + _table_allocator.destruct<Irq_table>(_irq_table_phys); _destroy_domains(); } }; @@ -661,9 +704,13 @@ class Intel::Io_mmu_factory : public Driver::Io_mmu_factory device.for_each_io_mem([&] (unsigned idx, Range range, Device::Pci_bar, bool) { - if (idx == 0) - new (alloc) Intel::Io_mmu(_env, io_mmu_devices, device.name(), - range, _table_allocator, irq_number); + try { + if (idx == 0) + new (alloc) Intel::Io_mmu(_env, io_mmu_devices, device.name(), + range, _table_allocator, irq_number); + } catch (...) { + error("Intel::Io_mmu failed to initialize - ", device.name()); + } }); } }; diff --git a/repos/pc/src/driver/platform/pc/intel/irq_remap_table.cc b/repos/pc/src/driver/platform/pc/intel/irq_remap_table.cc new file mode 100644 index 0000000000..f73c1ed405 --- /dev/null +++ b/repos/pc/src/driver/platform/pc/intel/irq_remap_table.cc @@ -0,0 +1,60 @@ +/* + * \brief Intel IOMMU Interrupt Remapping Table implementation + * \author Johannes Schlatow + * \date 2023-11-09 + * + * The interrupt remapping table is a page-aligned table structure of up to 64K + * 128bit entries (see section 9.9 [1]). Each entries maps a virtual interrupt + * index to a destination ID and vector. + * + * [1] "Intel® Virtualization Technology for Directed I/O" + * Revision 4.1, March 2023 + */ + +/* + * Copyright (C) 2023-2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* local includes */ +#include <intel/irq_remap_table.h> + +Intel::Irq_remap::Hi::access_t Intel::Irq_remap::hi_val(Pci::Bdf const & bdf) +{ + return Hi::Svt::bits(Hi::Svt::SOURCE_ID) | + Hi::Sq::bits(Hi::Sq::ALL_BITS) | + Hi::Source_id::bits(Pci::Bdf::rid(bdf)); +} + + +Intel::Irq_remap::Lo::access_t Intel::Irq_remap::lo_val(Irq_session::Info const & info, + Driver::Irq_controller::Irq_config const & config) +{ + using Irq_config = Driver::Irq_controller::Irq_config; + + Irq_address::access_t address = info.address; + Irq_data::access_t data = info.value; + + if (info.type == Irq_session::Info::MSI) + return + Lo::Present::bits(1) | + Lo::Destination_id::bits(Irq_address::Destination_id::get(address)) | + Lo::Destination_mode::bits(Irq_address::Destination_mode::get(address)) | + Lo::Redirection_hint::bits(Irq_address::Redirection_hint::get(address)) | + Lo::Trigger_mode::bits(Irq_data::Trigger_mode::get(data)) | + Lo::Delivery_mode::bits(Irq_data::Delivery_mode::get(data)) | + Lo::Vector::bits(Irq_data::Vector::get(data)); + else if (config.mode != Irq_config::INVALID) + return + Lo::Present::bits(1) | + Lo::Destination_id::bits(config.destination) | + Lo::Destination_mode::bits(config.mode == Irq_config::LOGICAL ? 1 : 0) | + Lo::Trigger_mode::bits(config.trigger == Irq_session::TRIGGER_LEVEL ? 1 : 0) | + Lo::Vector::bits(config.vector); + else + error("Unable to set IRQ remap table entry: missing information"); + + return 0; +} diff --git a/repos/pc/src/driver/platform/pc/intel/irq_remap_table.h b/repos/pc/src/driver/platform/pc/intel/irq_remap_table.h new file mode 100644 index 0000000000..4a1fce1c36 --- /dev/null +++ b/repos/pc/src/driver/platform/pc/intel/irq_remap_table.h @@ -0,0 +1,242 @@ +/* + * \brief Intel IOMMU Interrupt Remapping Table implementation + * \author Johannes Schlatow + * \date 2023-11-09 + * + * The interrupt remapping table is a page-aligned table structure of up to 64K + * 128bit entries (see section 9.9 [1]). Each entries maps a virtual interrupt + * index to a destination ID and vector. + * + * [1] "Intel® Virtualization Technology for Directed I/O" + * Revision 4.1, March 2023 + */ + +/* + * Copyright (C) 2023-2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _SRC__DRIVERS__PLATFORM__INTEL__IRQ_REMAP_TABLE_H_ +#define _SRC__DRIVERS__PLATFORM__INTEL__IRQ_REMAP_TABLE_H_ + +/* Genode includes */ +#include <util/register.h> +#include <util/bit_allocator.h> +#include <irq_session/irq_session.h> +#include <util/xml_generator.h> +#include <pci/types.h> + +/* platform-driver includes */ +#include <io_mmu.h> + +/* local includes */ +#include <cpu/clflush.h> + +namespace Intel { + using namespace Genode; + + class Irq_remap; + + template <unsigned SIZE_LOG2> + class Irq_remap_table; +} + +struct Intel::Irq_remap +{ + struct Hi : Genode::Register<64> + { + struct Source_id : Bitfield<0, 16> { }; + + /* Source-id qualifier */ + struct Sq : Bitfield<16, 2> { + enum { + ALL_BITS = 0, + IGNORE_BITS_2 = 1, + IGNORE_BITS_2_1 = 2, + IGNORE_BITS_2_1_0 = 3 + }; + }; + + /* Source validation type */ + struct Svt : Bitfield<18, 2> { + enum { + DISABLE = 0, + SOURCE_ID = 1, + BUS_ID_ONLY = 2 + }; + }; + }; + + struct Lo : Genode::Register<64> + { + struct Present : Bitfield< 0, 1> { }; + struct Ignore_faults : Bitfield< 1, 1> { }; + struct Destination_mode : Bitfield< 2, 1> { }; + struct Redirection_hint : Bitfield< 3, 1> { }; + struct Trigger_mode : Bitfield< 4, 1> { }; + struct Delivery_mode : Bitfield< 5, 3> { }; + struct Vector : Bitfield<16, 8> { }; + struct Destination_id : Bitfield<40, 8> { }; + }; + + struct Irq_address : Register<64> + { + struct Destination_mode : Bitfield<2,1> { }; + struct Redirection_hint : Bitfield<3,1> { }; + + struct Format : Bitfield<4,1> { + enum { + COMPATIBILITY = 0, + REMAPPABLE = 1 + }; + }; + + struct Destination_id : Bitfield<12,8> { }; + struct Handle : Bitfield<5,15> { }; + }; + + struct Irq_data : Register<64> + { + struct Vector : Bitfield< 0,8> { }; + struct Delivery_mode : Bitfield< 8,3> { }; + struct Trigger_mode : Bitfield<15,1> { }; + }; + + static Hi::access_t hi_val(Pci::Bdf const &); + static Lo::access_t lo_val(Irq_session::Info const &, + Driver::Irq_controller::Irq_config const &); +}; + + +template <unsigned SIZE_LOG2> +class Intel::Irq_remap_table +{ + public: + + static constexpr size_t ENTRIES_LOG2 = SIZE_LOG2 - 4; + static constexpr size_t ENTRIES = 1 << ENTRIES_LOG2; + + private: + + Irq_remap::Lo::access_t _entries[ENTRIES*2]; + + static size_t _lo_index(unsigned idx) { return 2*idx; } + static size_t _hi_index(unsigned idx) { return 2*idx + 1; } + + public: + + using Irq_allocator = Bit_allocator<ENTRIES>; + using Irq_info = Driver::Io_mmu::Irq_info; + using Irq_config = Driver::Irq_controller::Irq_config; + + bool present(unsigned idx) { + return Irq_remap::Lo::Present::get(_entries[_lo_index(idx)]); } + + unsigned destination_id(unsigned idx) { + return Irq_remap::Lo::Destination_id::get(_entries[_lo_index(idx)]); } + + Pci::rid_t source_id(unsigned idx) { + return Irq_remap::Hi::Source_id::get(_entries[_hi_index(idx)]); } + + template <typename FN> + Irq_info map(Irq_allocator & irq_alloc, + Pci::Bdf const & bdf, + Irq_info const & info, + Irq_config const & config, + FN && fn) + { + using Format = Irq_remap::Irq_address::Format; + + Irq_session::Info session_info = info.session_info; + + /* check whether info is already in remapped format */ + if (Format::get(session_info.address) == Format::REMAPPABLE) + return info; + + try { + unsigned idx = (unsigned)irq_alloc.alloc(); + + _entries[_hi_index(idx)] = Irq_remap::hi_val(bdf); + _entries[_lo_index(idx)] = Irq_remap::lo_val(session_info, config); + + clflush(&_entries[_lo_index(idx)]); + clflush(&_entries[_hi_index(idx)]); + + fn(idx); + + if (session_info.type == Irq_session::Info::Type::MSI) { + session_info.address = 0xfee00000U + | Irq_remap::Irq_address::Handle::bits(idx) + | Format::bits(Format::REMAPPABLE); + session_info.value = 0; + } + + /* XXX support multi-vectors MSI (see 5.1.5.2) */ + + /* return remapped Irq_info */ + return { Irq_info::REMAPPED, session_info, idx }; + + } catch (typename Irq_allocator::Out_of_indices) { + error("IRQ remapping table is full"); } + + return info; + } + + bool unmap(Irq_allocator & irq_alloc, Pci::Bdf const & bdf, unsigned idx) + { + Pci::rid_t rid = Pci::Bdf::rid(bdf); + + if (present(idx) && source_id(idx) == rid) { + _entries[_lo_index(idx)] = 0; + clflush(&_entries[_lo_index(idx)]); + irq_alloc.free(idx); + + return true; + } + + return false; + } + + void generate(Xml_generator & xml) + { + auto attribute_hex = [&] (Xml_generator & xml, + char const * name, + unsigned long long value) + { + xml.attribute(name, Genode::String<32>(Genode::Hex(value))); + }; + + for (unsigned idx = 0; idx < ENTRIES; idx++) { + if (!present(idx)) + continue; + + xml.node("irt_entry", [&] () { + attribute_hex(xml, "index", idx); + attribute_hex(xml, "source_id", source_id(idx)); + attribute_hex(xml, "hi", _entries[_hi_index(idx)]); + attribute_hex(xml, "lo", _entries[_lo_index(idx)]); + }); + } + } + + void flush_all() { + for (unsigned i=0; i < ENTRIES*2; i+=8) + clflush(&_entries[i]); + } + + Irq_remap_table() + { + for (unsigned i=0; i < ENTRIES; i++) { + _entries[_lo_index(i)] = 0; + _entries[_hi_index(i)] = 0; + } + + flush_all(); + } + +} __attribute__((aligned(4096))); + + +#endif /* _SRC__DRIVERS__PLATFORM__INTEL__IRQ_REMAP_TABLE_H_ */ diff --git a/repos/pc/src/driver/platform/pc/intel/page_table.cc b/repos/pc/src/driver/platform/pc/intel/page_table.cc index 8b40f4a966..e31eb7f627 100644 --- a/repos/pc/src/driver/platform/pc/intel/page_table.cc +++ b/repos/pc/src/driver/platform/pc/intel/page_table.cc @@ -15,7 +15,6 @@ void Intel::Level_1_translation_table::generate( Genode::Xml_generator & xml, - Genode::Env &, Report_helper &) { for_each_entry([&] (unsigned long i, Descriptor::access_t e) { @@ -25,38 +24,35 @@ void Intel::Level_1_translation_table::generate( void Intel::Level_2_translation_table::generate( Genode::Xml_generator & xml, - Genode::Env & env, Report_helper & report_helper) { for_each_entry([&] (unsigned long i, Descriptor::access_t e) { if (Descriptor::maps_page(e)) Descriptor::Page::generate_page(i, e, xml); else - Descriptor::Table::generate<Entry>(i, e, xml, env, report_helper); + Descriptor::Table::generate<Entry>(i, e, xml, report_helper); }); } void Intel::Level_3_translation_table::generate( Genode::Xml_generator & xml, - Genode::Env & env, Report_helper & report_helper) { for_each_entry([&] (unsigned long i, Descriptor::access_t e) { if (Descriptor::maps_page(e)) Descriptor::Page::generate_page(i, e, xml); else - Descriptor::Table::generate<Entry>(i, e, xml, env, report_helper); + Descriptor::Table::generate<Entry>(i, e, xml, report_helper); }); } void Intel::Level_4_translation_table::generate( Genode::Xml_generator & xml, - Genode::Env & env, Report_helper & report_helper) { for_each_entry([&] (unsigned long i, Descriptor::access_t e) { - Descriptor::generate<Entry>(i, e, xml, env, report_helper); + Descriptor::generate<Entry>(i, e, xml, report_helper); }); } diff --git a/repos/pc/src/driver/platform/pc/intel/page_table.h b/repos/pc/src/driver/platform/pc/intel/page_table.h index 332c76e0a9..7a582edf4c 100644 --- a/repos/pc/src/driver/platform/pc/intel/page_table.h +++ b/repos/pc/src/driver/platform/pc/intel/page_table.h @@ -155,7 +155,6 @@ struct Intel::Page_directory_descriptor<_PAGE_SIZE_LOG2>::Table static void generate(unsigned long index, access_t entry, Genode::Xml_generator & xml, - Genode::Env & env, Report_helper & report_helper) { using Genode::Hex; @@ -168,7 +167,7 @@ struct Intel::Page_directory_descriptor<_PAGE_SIZE_LOG2>::Table xml.attribute("address", Hex_str(Hex(pd_addr))); report_helper.with_table<ENTRY>(pd_addr, [&] (ENTRY & pd) { - pd.generate(xml, env, report_helper); }); + pd.generate(xml, report_helper); }); }); } }; @@ -237,7 +236,6 @@ struct Intel::Level_4_descriptor : Common_descriptor static void generate(unsigned long index, access_t entry, Genode::Xml_generator & xml, - Genode::Env & env, Report_helper & report_helper) { using Genode::Hex; @@ -250,7 +248,7 @@ struct Intel::Level_4_descriptor : Common_descriptor xml.attribute("address", Hex_str(Hex(level3_addr))); report_helper.with_table<ENTRY>(level3_addr, [&] (ENTRY & level3_table) { - level3_table.generate(xml, env, report_helper); }); + level3_table.generate(xml, report_helper); }); }); } }; @@ -264,7 +262,7 @@ namespace Intel { { static constexpr unsigned address_width() { return SIZE_LOG2_2MB; } - void generate(Genode::Xml_generator &, Genode::Env & env, Report_helper &); + void generate(Genode::Xml_generator &, Report_helper &); } __attribute__((aligned(1 << ALIGNM_LOG2))); struct Level_2_translation_table @@ -274,7 +272,7 @@ namespace Intel { { static constexpr unsigned address_width() { return SIZE_LOG2_1GB; } - void generate(Genode::Xml_generator &, Genode::Env & env, Report_helper &); + void generate(Genode::Xml_generator &, Report_helper &); } __attribute__((aligned(1 << ALIGNM_LOG2))); struct Level_3_translation_table @@ -284,7 +282,7 @@ namespace Intel { { static constexpr unsigned address_width() { return SIZE_LOG2_512GB; } - void generate(Genode::Xml_generator &, Genode::Env & env, Report_helper &); + void generate(Genode::Xml_generator &, Report_helper &); } __attribute__((aligned(1 << ALIGNM_LOG2))); struct Level_4_translation_table @@ -294,7 +292,7 @@ namespace Intel { { static constexpr unsigned address_width() { return SIZE_LOG2_256TB; } - void generate(Genode::Xml_generator &, Genode::Env & env, Report_helper &); + void generate(Genode::Xml_generator &, Report_helper &); } __attribute__((aligned(1 << ALIGNM_LOG2))); } diff --git a/repos/pc/src/driver/platform/pc/intel/root_table.cc b/repos/pc/src/driver/platform/pc/intel/root_table.cc index 1e1ce7f34c..e40a59d8c5 100644 --- a/repos/pc/src/driver/platform/pc/intel/root_table.cc +++ b/repos/pc/src/driver/platform/pc/intel/root_table.cc @@ -24,7 +24,6 @@ static void attribute_hex(Genode::Xml_generator & xml, char const * name, void Intel::Root_table::generate(Xml_generator & xml, - Env & env, Report_helper & report_helper) { for_each([&] (uint8_t bus) { @@ -38,7 +37,7 @@ void Intel::Root_table::generate(Xml_generator & xml, attribute_hex(xml, "context_table", ctx_addr); auto fn = [&] (Context_table & context) { - context.generate(xml, env, report_helper); + context.generate(xml, report_helper); }; /* dump context table */ diff --git a/repos/pc/src/driver/platform/pc/intel/root_table.h b/repos/pc/src/driver/platform/pc/intel/root_table.h index f67b1ff541..ab6203fbf3 100644 --- a/repos/pc/src/driver/platform/pc/intel/root_table.h +++ b/repos/pc/src/driver/platform/pc/intel/root_table.h @@ -72,7 +72,7 @@ class Intel::Root_table clflush(&_entries[bus*2]); } - void generate(Xml_generator &, Env &, Report_helper &); + void generate(Xml_generator &, Report_helper &); Root_table() { diff --git a/repos/pc/src/driver/platform/pc/ioapic.cc b/repos/pc/src/driver/platform/pc/ioapic.cc new file mode 100644 index 0000000000..2fa3395ed2 --- /dev/null +++ b/repos/pc/src/driver/platform/pc/ioapic.cc @@ -0,0 +1,108 @@ +/* + * \brief IOAPIC implementation + * \author Johannes Schlatow + * \date 2024-03-20 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* local includes */ +#include <ioapic.h> + +unsigned Driver::Ioapic::_read_max_entries() +{ + write<Ioregsel>(Ioregsel::IOAPICVER); + return read<Iowin::Maximum_entries>() + 1; +} + + +bool Driver::Ioapic::handles_irq(unsigned irq) +{ + if (irq < _irq_start || irq >= _irq_start + _max_entries) + return false; + + return true; +} + + +/** + * Sets remapping bit and destination index in IOAPIC redirection table. + * + * Note: Expected to be called only if handles_irq() returned true. + */ +void Driver::Ioapic::remap_irq(unsigned from, unsigned to) +{ + const unsigned idx = from - _irq_start; + + /* read upper 32 bit */ + write<Ioregsel>(Ioregsel::IOREDTBL + 2 * idx + 1); + Irte::access_t irte { read<Iowin>() }; + irte <<= 32; + + /* read lower 32 bit */ + write<Ioregsel>(Ioregsel::IOREDTBL + 2 * idx); + irte |= read<Iowin>(); + + /* remap entry */ + Irte::Remap::set(irte, 1); + Irte::Index::set(irte, to & 0xFF); + + /* write upper 32 bit */ + write<Ioregsel>(Ioregsel::IOREDTBL + 2 * idx + 1); + write<Iowin>((Iowin::access_t)(irte >> 32)); + + /* write lower 32 bit */ + write<Ioregsel>(Ioregsel::IOREDTBL + 2 * idx); + write<Iowin>((Iowin::access_t)(irte & 0xFFFFFFFF)); +} + + +/** + * Reads and returns IRQ configuration from IOAPIC redirection table. + * + * Note: Expected to be called only if handles_irq() returned true. + */ +Driver::Ioapic::Irq_config Driver::Ioapic::irq_config(unsigned irq) +{ + const unsigned idx = irq - _irq_start; + + /* read upper 32 bit */ + write<Ioregsel>(Ioregsel::IOREDTBL + 2 * idx + 1); + Irte::access_t irte { read<Iowin>() }; + irte <<= 32; + + /* read lower 32 bit */ + write<Ioregsel>(Ioregsel::IOREDTBL + 2 * idx); + irte |= read<Iowin>(); + + /* extract trigger mode */ + Irq_session::Trigger trigger { Irq_session::TRIGGER_UNCHANGED }; + switch (Irte::Trigger_mode::get(irte)) { + case Irte::Trigger_mode::EDGE: + trigger = Irq_session::TRIGGER_EDGE; + break; + case Irte::Trigger_mode::LEVEL: + trigger = Irq_session::TRIGGER_LEVEL; + break; + } + + /* extract destination mode */ + Irq_config::Mode mode { Irq_config::Mode::INVALID }; + switch (Irte::Destination_mode::get(irte)) { + case Irte::Destination_mode::PHYSICAL: + mode = Irq_config::Mode::PHYSICAL; + break; + case Irte::Destination_mode::LOGICAL: + mode = Irq_config::Mode::LOGICAL; + break; + } + + return { mode, trigger, + Irte::Vector::get(irte), + Irte::Destination::get(irte) }; +} diff --git a/repos/pc/src/driver/platform/pc/ioapic.h b/repos/pc/src/driver/platform/pc/ioapic.h new file mode 100644 index 0000000000..ef3ad44381 --- /dev/null +++ b/repos/pc/src/driver/platform/pc/ioapic.h @@ -0,0 +1,152 @@ +/* + * \brief IOAPIC implementation + * \author Johannes Schlatow + * \date 2024-03-20 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _SRC__DRIVERS__PLATFORM__PC__IOAPIC_H_ +#define _SRC__DRIVERS__PLATFORM__PC__IOAPIC_H_ + +/* Genode includes */ +#include <os/attached_mmio.h> +#include <util/register_set.h> +#include <base/allocator.h> + +/* Platform-driver includes */ +#include <device.h> +#include <irq_controller.h> + +namespace Driver { + using namespace Genode; + + class Ioapic; + class Ioapic_factory; +} + + +class Driver::Ioapic : private Attached_mmio<0x1000>, + public Driver::Irq_controller +{ + private: + + Env & _env; + unsigned _irq_start; + unsigned _max_entries; + + /** + * Registers + */ + + struct Ioregsel : Register<0x00, 32> { + enum { + IOAPICVER = 0x01, + IOREDTBL = 0x10 + }; + }; + + struct Iowin : Register<0x10, 32> { + struct Maximum_entries : Bitfield<16, 8> { }; + }; + + struct Irte : Genode::Register<64> { + struct Index_15 : Bitfield<11, 1> { }; + struct Remap : Bitfield<48, 1> { }; + struct Index_0_14 : Bitfield<49, 15> { }; + struct Index : Bitset_2<Index_0_14, Index_15> { }; + + struct Vector : Bitfield<0,8> { }; + struct Trigger_mode : Bitfield<15,1> { + enum { EDGE = 0, LEVEL = 1 }; }; + + struct Destination_mode : Bitfield<11,1> { + enum { PHYSICAL = 0, LOGICAL = 1 }; }; + + struct Destination : Bitfield<56,8> { }; + }; + + unsigned _read_max_entries(); + + public: + + /** + * Irq_controller interface + */ + void remap_irq(unsigned, unsigned) override; + bool handles_irq(unsigned) override; + Irq_config irq_config(unsigned) override; + + /** + * Constructor/Destructor + */ + + Ioapic(Env & env, + Registry<Irq_controller> & irq_controller_registry, + Device::Name const & name, + Device::Name const & iommu_name, + Pci::Bdf const & bdf, + Device::Io_mem::Range range, + unsigned irq_start) + : Attached_mmio(env, {(char *)range.start, range.size}), + Driver::Irq_controller(irq_controller_registry, name, iommu_name, bdf), + _env(env), _irq_start(irq_start), _max_entries(_read_max_entries()) + { } +}; + + +class Driver::Ioapic_factory : public Driver::Irq_controller_factory +{ + private: + + Genode::Env & _env; + + public: + + Ioapic_factory(Genode::Env & env, Registry<Irq_controller_factory> & registry) + : Driver::Irq_controller_factory(registry, Device::Type { "ioapic" }), + _env(env) + { } + + void create(Allocator & alloc, Registry<Irq_controller> & irq_controller_registry, Device const & device) override + { + using Range = Device::Io_mem::Range; + using Property = Device::Property; + + /* evaluate properties (remapping support, base IRQ, routing id) */ + bool remap { false }; + unsigned irq_start { 0 }; + Pci::rid_t rid { 0 }; + device.for_each_property([&] (Property::Name const & name, Property::Value const & value) { + if (name == "remapping") + ascii_to(value.string(), remap); + else if (name == "irq_start") + ascii_to(value.string(), irq_start); + else if (name == "routing_id") + ascii_to(value.string(), rid); + }); + + /* ignore IOAPIC devices without remapping support */ + if (!remap) + return; + + unsigned iommu_idx = 0; + device.for_each_io_mmu([&] (Device::Io_mmu const & iommu) { + if (iommu_idx++) return; + + device.for_each_io_mem([&] (unsigned idx, Range range, Device::Pci_bar, bool) + { + if (idx == 0) + new (alloc) Ioapic(_env, irq_controller_registry, device.name(), + iommu.name, Pci::Bdf::bdf(rid), range, irq_start); + }); + }, [] () { /* empty fn */ }); + } +}; + +#endif /* _SRC__DRIVERS__PLATFORM__PC__IOAPIC_H_ */ diff --git a/repos/pc/src/driver/platform/pc/spec/x86_64/main.cc b/repos/pc/src/driver/platform/pc/spec/x86_64/main.cc index 7ca7e1afe1..16d9f96ed7 100644 --- a/repos/pc/src/driver/platform/pc/spec/x86_64/main.cc +++ b/repos/pc/src/driver/platform/pc/spec/x86_64/main.cc @@ -16,6 +16,7 @@ #include <common.h> #include <pci.h> #include <intel/io_mmu.h> +#include <ioapic.h> namespace Driver { struct Main; }; @@ -33,6 +34,7 @@ struct Driver::Main &Main::_system_update }; Intel::Io_mmu_factory _intel_iommu { _env, _common.io_mmu_factories() }; + Ioapic_factory _ioapic_factory { _env, _common.irq_controller_factories() }; void _handle_config(); void _suspend(String<8>); @@ -51,6 +53,7 @@ struct Driver::Main _system_update(); _common.acquire_io_mmu_devices(); + _common.acquire_irq_controller(); _common.announce_service(); } }; diff --git a/repos/pc/src/driver/platform/pc/spec/x86_64/target.mk b/repos/pc/src/driver/platform/pc/spec/x86_64/target.mk index b4c1927e22..4ecdd68c4e 100644 --- a/repos/pc/src/driver/platform/pc/spec/x86_64/target.mk +++ b/repos/pc/src/driver/platform/pc/spec/x86_64/target.mk @@ -9,7 +9,11 @@ SRC_CC += intel/managed_root_table.cc SRC_CC += intel/io_mmu.cc SRC_CC += intel/page_table.cc SRC_CC += intel/default_mappings.cc +SRC_CC += intel/invalidator.cc +SRC_CC += ioapic.cc +SRC_CC += intel/irq_remap_table.cc INC_DIR += $(PRG_DIR)/../../ vpath intel/%.cc $(PRG_DIR)/../../ +vpath ioapic.cc $(PRG_DIR)/../../ diff --git a/repos/pc/src/lib/pc_wifi/dummies.c b/repos/pc/src/lib/pc_wifi/dummies.c index bcc7e7fbc7..2631ab74de 100644 --- a/repos/pc/src/lib/pc_wifi/dummies.c +++ b/repos/pc/src/lib/pc_wifi/dummies.c @@ -774,3 +774,12 @@ struct thermal_zone_device * thermal_zone_device_register_with_trips(const char lx_emul_trace(__func__); return ERR_PTR(-EINVAL); } + + +#include <linux/ratelimit_types.h> + +int ___ratelimit(struct ratelimit_state * rs,const char * func) +{ + lx_emul_trace(__func__); + return 0; +} diff --git a/repos/pc/src/lib/pc_wifi/generated_dummies.c b/repos/pc/src/lib/pc_wifi/generated_dummies.c index 801d9b7e18..3dcc9709ba 100644 --- a/repos/pc/src/lib/pc_wifi/generated_dummies.c +++ b/repos/pc/src/lib/pc_wifi/generated_dummies.c @@ -7,14 +7,6 @@ #include <lx_emul.h> -#include <linux/ratelimit_types.h> - -int ___ratelimit(struct ratelimit_state * rs,const char * func) -{ - lx_emul_trace_and_stop(__func__); -} - - #include <linux/cpumask.h> struct cpumask __cpu_active_mask; diff --git a/repos/ports/ports/netperf.hash b/repos/ports/ports/netperf.hash index b3f3bf65a0..7326120286 100644 --- a/repos/ports/ports/netperf.hash +++ b/repos/ports/ports/netperf.hash @@ -1 +1 @@ -6db34a7949b8942c256b881977e91fbf53638dd6 +56f2157a43b51cb0a534f251187dbc00038b276a diff --git a/repos/ports/ports/virtualbox6.hash b/repos/ports/ports/virtualbox6.hash index a1455e97db..cf83bd1ff0 100644 --- a/repos/ports/ports/virtualbox6.hash +++ b/repos/ports/ports/virtualbox6.hash @@ -1 +1 @@ -4f4c05a80b5767a0132c333a352fada6ba8965a8 +4fe7913734f0dbabae9fae0684e34fe1fe60e8b2 diff --git a/repos/ports/recipes/pkg/gdb_x86/hash b/repos/ports/recipes/pkg/gdb_x86/hash index 5df5ed0942..dedf334828 100644 --- a/repos/ports/recipes/pkg/gdb_x86/hash +++ b/repos/ports/recipes/pkg/gdb_x86/hash @@ -1 +1 @@ -2024-08-28 4394f51ecbb9a10c70c9410f149170fcab11f953 +2024-12-10 5c32adefe62a440f6560e297a180f82709ec28e6 diff --git a/repos/ports/recipes/pkg/lighttpd/hash b/repos/ports/recipes/pkg/lighttpd/hash index d49b27a694..f8a0d7a8fd 100644 --- a/repos/ports/recipes/pkg/lighttpd/hash +++ b/repos/ports/recipes/pkg/lighttpd/hash @@ -1 +1 @@ -2024-08-28 ad5882ef30cdd8b4877035ac4f84683984507c1d +2024-12-10 7dedcb18248877f91f2917b9a27eda8dd7da432e diff --git a/repos/ports/recipes/pkg/report_dump/hash b/repos/ports/recipes/pkg/report_dump/hash index 67d14f97b8..5124f27fa6 100644 --- a/repos/ports/recipes/pkg/report_dump/hash +++ b/repos/ports/recipes/pkg/report_dump/hash @@ -1 +1 @@ -2024-08-28 51a904ffdd7bebdbea6faf1c57bf782ad0c63bd2 +2024-12-10 388aed6c056767122c09e69288cf5391368b4ed6 diff --git a/repos/ports/recipes/pkg/socat_tcp/hash b/repos/ports/recipes/pkg/socat_tcp/hash index 05a7a968a1..5ce4c52ed0 100644 --- a/repos/ports/recipes/pkg/socat_tcp/hash +++ b/repos/ports/recipes/pkg/socat_tcp/hash @@ -1 +1 @@ -2024-08-28 216e167a569e6622a741075f98bf893b4ec63444 +2024-12-10 b17bb662b8b95f81c5af1305265b3e6c721581d6 diff --git a/repos/ports/recipes/pkg/system_shell/hash b/repos/ports/recipes/pkg/system_shell/hash index 4f118d2398..80702819d1 100644 --- a/repos/ports/recipes/pkg/system_shell/hash +++ b/repos/ports/recipes/pkg/system_shell/hash @@ -1 +1 @@ -2024-08-28 cad8de09ea5c0489f231ff7ee49139fd610ff5c2 +2024-12-10 3c29f0d46ab22c4b54aafec1ae88459dfb286045 diff --git a/repos/ports/recipes/pkg/system_shell/runtime b/repos/ports/recipes/pkg/system_shell/runtime index 8f5e8f0be7..632646cf3b 100644 --- a/repos/ports/recipes/pkg/system_shell/runtime +++ b/repos/ports/recipes/pkg/system_shell/runtime @@ -1,4 +1,4 @@ -<runtime ram="76M" caps="1000" binary="init" config="system_shell.config"> +<runtime ram="108M" caps="1000" binary="init" config="system_shell.config"> <requires> <gui/> diff --git a/repos/ports/recipes/pkg/vbox5-nova-capture/hash b/repos/ports/recipes/pkg/vbox5-nova-capture/hash index 8d67d00048..f9569d3d8a 100644 --- a/repos/ports/recipes/pkg/vbox5-nova-capture/hash +++ b/repos/ports/recipes/pkg/vbox5-nova-capture/hash @@ -1 +1 @@ -2024-08-28 6dbfb1d9b58fa987f70385c0b3752979a6fd3ed9 +2024-12-10 49ae1012c3547febdb4fc5db8769a50e285f9224 diff --git a/repos/ports/recipes/pkg/vbox5-nova-sculpt/hash b/repos/ports/recipes/pkg/vbox5-nova-sculpt/hash index 1bc0df732e..ead18dd18b 100644 --- a/repos/ports/recipes/pkg/vbox5-nova-sculpt/hash +++ b/repos/ports/recipes/pkg/vbox5-nova-sculpt/hash @@ -1 +1 @@ -2024-08-28 84aa7821079008a2a71eb1566e4b47442877d927 +2024-12-10 2b7147b20fcc8a1d63b2fcccb8a6d31a9b7ddb58 diff --git a/repos/ports/recipes/pkg/vbox6-capture/archives b/repos/ports/recipes/pkg/vbox6-capture/archives index fd5314ece3..2325c2c170 100644 --- a/repos/ports/recipes/pkg/vbox6-capture/archives +++ b/repos/ports/recipes/pkg/vbox6-capture/archives @@ -1,6 +1,5 @@ _/raw/vbox6 _/src/expat -_/src/init _/src/jpeg _/src/libc _/src/libdrm diff --git a/repos/ports/recipes/pkg/vbox6-capture/hash b/repos/ports/recipes/pkg/vbox6-capture/hash index fe252f5dec..3c1e93e395 100644 --- a/repos/ports/recipes/pkg/vbox6-capture/hash +++ b/repos/ports/recipes/pkg/vbox6-capture/hash @@ -1 +1 @@ -2024-08-28 4e69297a012cbda8eca0133fa70b9615df9e7dfd +2024-12-10 b9082423031ff10ec99a3c8d5764c66c4de93ff8 diff --git a/repos/ports/recipes/pkg/vbox6-capture/runtime b/repos/ports/recipes/pkg/vbox6-capture/runtime index 2947d60693..f87652527e 100644 --- a/repos/ports/recipes/pkg/vbox6-capture/runtime +++ b/repos/ports/recipes/pkg/vbox6-capture/runtime @@ -1,4 +1,4 @@ -<runtime ram="4300M" caps="8000" binary="init"> +<runtime ram="4300M" caps="2500" binary="virtualbox6"> <requires> <file_system label="vm"/> @@ -22,80 +22,30 @@ <record/> </requires> - <config verbose="yes"> - - <parent-provides> - <service name="ROM"/> - <service name="PD"/> - <service name="RM"/> - <service name="CPU"/> - <service name="LOG"/> - <service name="VM"/> - <service name="Gui"/> - <service name="Gpu"/> - <service name="Timer"/> - <service name="Rtc"/> - <service name="Report"/> - <service name="File_system"/> - <service name="Usb"/> - <service name="Nic"/> - <service name="Play"/> - <service name="Record"/> - <service name="Capture"/> - </parent-provides> - - <default-route> <any-service> <parent/> <any-child/> </any-service> </default-route> - - <default caps="100"/> - - <start name="vbox" caps="7000"> - <binary name="virtualbox6" /> - <resource name="RAM" quantum="8G"/> - <exit propagate="yes"/> - <config vbox_file="machine.vbox6" xhci="yes" vm_name="linux" capslock="rom" ld_verbose="yes"> - <vfs> - <dir name="dev"> - <log/> <rtc/> <null/> <gpu/> <zero/> - <oss name="dsp" min_ofrag_size="8192" min_ifrag_size="8192"/> - </dir> - <dir name="pipe"> <pipe/> </dir> - <dir name="shared"> <fs label="shared" writeable="yes"/> </dir> - <rom name="VBoxSharedClipboard.so"/> - <rom name="VBoxSharedFolders.so"/> - <fs writeable="yes"/> - </vfs> - <libc stdout="/dev/log" stderr="/dev/log" rtc="/dev/rtc" pipe="/pipe"> - <pthread placement="single-cpu"/> - </libc> - <webcam vertical_flip="true" fps="30" screen_size="false" width="640" height="480"/> - <arg value="virtualbox"/> - <env key="VBOX_USER_HOME" value="/"/> - <env key="VBOX_LOG_DEST" value="file=/dev/log"/> - <env key="VBOX_LOG" value="+dbgf+gim"/> - <env key="VBOX_LOG_FLAGS" value="thread"/> - <env key="VBOX_RELEASE_LOG_DEST" value="file=/dev/log"/> - <env key="VBOX_RELEASE_LOG" value=""/> - <env key="VBOX_RELEASE_LOG_FLAGS" value="thread"/> - </config> - <route> - <service name="File_system" label="shared"> <parent label="shared"/> </service> - <service name="File_system"> <parent label="vm"/> </service> - <service name="ROM" label="capslock"> <parent label="capslock"/> </service> - <service name="ROM" label="platform_info"> <parent label="platform_info"/> </service> - <service name="ROM" label="VBoxSharedClipboard.so"> - <parent label="virtualbox6-sharedclipboard.lib.so"/> </service> - <service name="ROM" label="VBoxSharedFolders.so"> - <parent label="virtualbox6-sharedfolders.lib.so"/> </service> - <service name="ROM" label="mesa_gpu.lib.so"> - <parent label="mesa_gpu.lib.so"/> </service> - <service name="Nic"> <parent/> </service> - <service name="Report" label="shape"> <parent label="shape"/> </service> - <service name="ROM" label="clipboard"> <parent label="clipboard"/> </service> - <service name="Report" label="clipboard"> <parent label="clipboard"/> </service> - <service name="Gui"> <parent label=""/> </service> - <any-service> <parent/> </any-service> - </route> - </start> + <config vbox_file="machine.vbox6" xhci="yes" vm_name="linux" capslock="rom" ld_verbose="yes"> + <vfs> + <dir name="dev"> + <log/> <rtc/> <null/> <gpu/> <zero/> + <oss name="dsp" min_ofrag_size="8192" min_ifrag_size="8192"/> + </dir> + <dir name="pipe"> <pipe/> </dir> + <dir name="shared"> <fs label="shared" writeable="yes"/> </dir> + <rom name="VBoxSharedClipboard.so"/> + <rom name="VBoxSharedFolders.so"/> + <fs label="vm" writeable="yes"/> + </vfs> + <libc stdout="/dev/log" stderr="/dev/log" rtc="/dev/rtc" pipe="/pipe"> + <pthread placement="single-cpu"/> + </libc> + <webcam vertical_flip="true" fps="30" screen_size="false" width="640" height="480"/> + <arg value="virtualbox"/> + <env key="VBOX_USER_HOME" value="/"/> + <env key="VBOX_LOG_DEST" value="file=/dev/log"/> + <env key="VBOX_LOG" value="+dbgf+gim"/> + <env key="VBOX_LOG_FLAGS" value="thread"/> + <env key="VBOX_RELEASE_LOG_DEST" value="file=/dev/log"/> + <env key="VBOX_RELEASE_LOG" value=""/> + <env key="VBOX_RELEASE_LOG_FLAGS" value="thread"/> </config> <content> @@ -103,7 +53,6 @@ <rom label="expat.lib.so"/> <rom label="glapi.lib.so"/> <rom label="ld.lib.so"/> - <rom label="init"/> <rom label="virtualbox6"/> <rom label="jpeg.lib.so"/> <rom label="libc.lib.so"/> @@ -119,8 +68,8 @@ <rom label="vfs_oss.lib.so"/> <rom label="vfs_pipe.lib.so"/> <rom label="virtualbox6-shaderlib.lib.so"/> - <rom label="virtualbox6-sharedclipboard.lib.so"/> - <rom label="virtualbox6-sharedfolders.lib.so"/> + <rom label="virtualbox6-sharedclipboard.lib.so" as="VBoxSharedClipboard.so"/> + <rom label="virtualbox6-sharedfolders.lib.so" as="VBoxSharedFolders.so"/> <rom label="zlib.lib.so"/> </content> diff --git a/repos/ports/recipes/pkg/vbox6/archives b/repos/ports/recipes/pkg/vbox6/archives index fd5314ece3..2325c2c170 100644 --- a/repos/ports/recipes/pkg/vbox6/archives +++ b/repos/ports/recipes/pkg/vbox6/archives @@ -1,6 +1,5 @@ _/raw/vbox6 _/src/expat -_/src/init _/src/jpeg _/src/libc _/src/libdrm diff --git a/repos/ports/recipes/pkg/vbox6/hash b/repos/ports/recipes/pkg/vbox6/hash index eeb74143a2..ac790169c2 100644 --- a/repos/ports/recipes/pkg/vbox6/hash +++ b/repos/ports/recipes/pkg/vbox6/hash @@ -1 +1 @@ -2024-08-28 0a58077655c5675a68170f84e8b30182efd155a0 +2024-12-10 b52e5eaf9d3f6db4a1d916ea51b721a2a4a6576b diff --git a/repos/ports/recipes/pkg/vbox6/runtime b/repos/ports/recipes/pkg/vbox6/runtime index ad971486af..5045d34c57 100644 --- a/repos/ports/recipes/pkg/vbox6/runtime +++ b/repos/ports/recipes/pkg/vbox6/runtime @@ -1,4 +1,4 @@ -<runtime ram="4300M" caps="8000" binary="init"> +<runtime ram="4300M" caps="2500" binary="virtualbox6"> <requires> <file_system label="vm"/> @@ -21,78 +21,29 @@ <record/> </requires> - <config verbose="yes"> - - <parent-provides> - <service name="ROM"/> - <service name="PD"/> - <service name="RM"/> - <service name="CPU"/> - <service name="LOG"/> - <service name="VM"/> - <service name="Gui"/> - <service name="Gpu"/> - <service name="Timer"/> - <service name="Rtc"/> - <service name="Report"/> - <service name="File_system"/> - <service name="Usb"/> - <service name="Nic"/> - <service name="Play"/> - <service name="Record"/> - </parent-provides> - - <default-route> <any-service> <parent/> <any-child/> </any-service> </default-route> - - <default caps="100"/> - - <start name="vbox" caps="7000"> - <binary name="virtualbox6" /> - <resource name="RAM" quantum="8G"/> - <exit propagate="yes"/> - <config vbox_file="machine.vbox6" xhci="yes" vm_name="linux" capslock="rom" ld_verbose="yes"> - <vfs> - <dir name="dev"> - <log/> <rtc/> <null/> <gpu/> <zero/> - <oss name="dsp" min_ofrag_size="8192" min_ifrag_size="8192"/> - </dir> - <dir name="pipe"> <pipe/> </dir> - <dir name="shared"> <fs label="shared" writeable="yes"/> </dir> - <rom name="VBoxSharedClipboard.so"/> - <rom name="VBoxSharedFolders.so"/> - <fs writeable="yes"/> - </vfs> - <libc stdout="/dev/log" stderr="/dev/log" rtc="/dev/rtc" pipe="/pipe"> - <pthread placement="single-cpu"/> - </libc> - <arg value="virtualbox"/> - <env key="VBOX_USER_HOME" value="/"/> - <env key="VBOX_LOG_DEST" value="file=/dev/log"/> - <env key="VBOX_LOG" value="+dbgf+gim"/> - <env key="VBOX_LOG_FLAGS" value="thread"/> - <env key="VBOX_RELEASE_LOG_DEST" value="file=/dev/log"/> - <env key="VBOX_RELEASE_LOG" value=""/> - <env key="VBOX_RELEASE_LOG_FLAGS" value="thread"/> - </config> - <route> - <service name="File_system" label="shared"> <parent label="shared"/> </service> - <service name="File_system"> <parent label="vm"/> </service> - <service name="ROM" label="capslock"> <parent label="capslock"/> </service> - <service name="ROM" label="platform_info"> <parent label="platform_info"/> </service> - <service name="ROM" label="VBoxSharedClipboard.so"> - <parent label="virtualbox6-sharedclipboard.lib.so"/> </service> - <service name="ROM" label="VBoxSharedFolders.so"> - <parent label="virtualbox6-sharedfolders.lib.so"/> </service> - <service name="ROM" label="mesa_gpu.lib.so"> - <parent label="mesa_gpu.lib.so"/> </service> - <service name="Nic"> <parent/> </service> - <service name="Report" label="shape"> <parent label="shape"/> </service> - <service name="ROM" label="clipboard"> <parent label="clipboard"/> </service> - <service name="Report" label="clipboard"> <parent label="clipboard"/> </service> - <service name="Gui"> <parent label=""/> </service> - <any-service> <parent/> </any-service> - </route> - </start> + <config vbox_file="machine.vbox6" xhci="yes" vm_name="linux" capslock="rom" ld_verbose="yes"> + <vfs> + <dir name="dev"> + <log/> <rtc/> <null/> <gpu/> <zero/> + <oss name="dsp" min_ofrag_size="8192" min_ifrag_size="8192"/> + </dir> + <dir name="pipe"> <pipe/> </dir> + <dir name="shared"> <fs label="shared" writeable="yes"/> </dir> + <rom name="VBoxSharedClipboard.so"/> + <rom name="VBoxSharedFolders.so"/> + <fs label="vm" writeable="yes"/> + </vfs> + <libc stdout="/dev/log" stderr="/dev/log" rtc="/dev/rtc" pipe="/pipe"> + <pthread placement="single-cpu"/> + </libc> + <arg value="virtualbox"/> + <env key="VBOX_USER_HOME" value="/"/> + <env key="VBOX_LOG_DEST" value="file=/dev/log"/> + <env key="VBOX_LOG" value="+dbgf+gim"/> + <env key="VBOX_LOG_FLAGS" value="thread"/> + <env key="VBOX_RELEASE_LOG_DEST" value="file=/dev/log"/> + <env key="VBOX_RELEASE_LOG" value=""/> + <env key="VBOX_RELEASE_LOG_FLAGS" value="thread"/> </config> <content> @@ -100,7 +51,6 @@ <rom label="expat.lib.so"/> <rom label="glapi.lib.so"/> <rom label="ld.lib.so"/> - <rom label="init"/> <rom label="virtualbox6"/> <rom label="jpeg.lib.so"/> <rom label="libc.lib.so"/> @@ -116,8 +66,8 @@ <rom label="vfs_oss.lib.so"/> <rom label="vfs_pipe.lib.so"/> <rom label="virtualbox6-shaderlib.lib.so"/> - <rom label="virtualbox6-sharedclipboard.lib.so"/> - <rom label="virtualbox6-sharedfolders.lib.so"/> + <rom label="virtualbox6-sharedclipboard.lib.so" as="VBoxSharedClipboard.so"/> + <rom label="virtualbox6-sharedfolders.lib.so" as="VBoxSharedFolders.so"/> <rom label="zlib.lib.so"/> </content> diff --git a/repos/ports/recipes/raw/system_shell/hash b/repos/ports/recipes/raw/system_shell/hash index 9b78064e4d..60b8f80899 100644 --- a/repos/ports/recipes/raw/system_shell/hash +++ b/repos/ports/recipes/raw/system_shell/hash @@ -1 +1 @@ -2021-10-14 6bd449b9b53a934bb0ae9dbab667f1beb6ed3d58 +2024-10-29 5ce626a0735a43ee1899dff5555375ebd7925eb1 diff --git a/repos/ports/recipes/raw/system_shell/system_shell.config b/repos/ports/recipes/raw/system_shell/system_shell.config index 047ceac944..d053f5b618 100644 --- a/repos/ports/recipes/raw/system_shell/system_shell.config +++ b/repos/ports/recipes/raw/system_shell/system_shell.config @@ -16,7 +16,7 @@ <default caps="100"/> <start name="terminal" caps="150"> - <resource name="RAM" quantum="16M"/> + <resource name="RAM" quantum="48M"/> <provides> <service name="Terminal"/> </provides> <config copy="yes" paste="yes"> <initial width="800" height="600"/> diff --git a/repos/ports/recipes/src/bash-minimal/hash b/repos/ports/recipes/src/bash-minimal/hash index e1ef58266c..68cabe0da3 100644 --- a/repos/ports/recipes/src/bash-minimal/hash +++ b/repos/ports/recipes/src/bash-minimal/hash @@ -1 +1 @@ -2024-08-28 9b6c29929a1123427f1934d39da13915b3a812c8 +2024-10-07 41ea091449832b11e250b7241100e326b14f8d12 diff --git a/repos/ports/recipes/src/bash/hash b/repos/ports/recipes/src/bash/hash index 62c31e1b50..76df4648d6 100644 --- a/repos/ports/recipes/src/bash/hash +++ b/repos/ports/recipes/src/bash/hash @@ -1 +1 @@ -2024-08-28 ff36bf51831fb9a77b33c018c8efa9ea57743829 +2024-10-07 7545f7e4a3297aa829621651c931bc51d4381d78 diff --git a/repos/ports/recipes/src/binutils_x86/hash b/repos/ports/recipes/src/binutils_x86/hash index f972e747b3..2b084f333e 100644 --- a/repos/ports/recipes/src/binutils_x86/hash +++ b/repos/ports/recipes/src/binutils_x86/hash @@ -1 +1 @@ -2024-08-28 5c8d4439c2359aeb8b518ad60e6e389934a9254f +2024-10-07 f69c9a8e21641fb524c22f4e462fc34244c2942d diff --git a/repos/ports/recipes/src/coreutils-minimal/hash b/repos/ports/recipes/src/coreutils-minimal/hash index 3459d31f79..f0c276c592 100644 --- a/repos/ports/recipes/src/coreutils-minimal/hash +++ b/repos/ports/recipes/src/coreutils-minimal/hash @@ -1 +1 @@ -2024-08-28 b6c770e9c11c446b9760c2d977a84568e44d6e15 +2024-10-07 4220c6dda032f4972234de32a4d49e05c022ca42 diff --git a/repos/ports/recipes/src/coreutils/hash b/repos/ports/recipes/src/coreutils/hash index 5b28a4a98f..4bcd73205a 100644 --- a/repos/ports/recipes/src/coreutils/hash +++ b/repos/ports/recipes/src/coreutils/hash @@ -1 +1 @@ -2024-08-28 42a27a2a3cb603b942a65e4ba19380f95cf10c58 +2024-10-07 16c5dc88342cc86eacf7d11213e62bd784a3998f diff --git a/repos/ports/recipes/src/diffutils/hash b/repos/ports/recipes/src/diffutils/hash index e2858c60fd..c74ddd1458 100644 --- a/repos/ports/recipes/src/diffutils/hash +++ b/repos/ports/recipes/src/diffutils/hash @@ -1 +1 @@ -2024-08-28 466e8e368502ba35bb20672e520ef5f45a107e88 +2024-10-07 8c6f275bc29f731d0074d9c4fed2cc4e15bb528d diff --git a/repos/ports/recipes/src/e2fsprogs-minimal/hash b/repos/ports/recipes/src/e2fsprogs-minimal/hash index eb1c178dda..7b44bd0afd 100644 --- a/repos/ports/recipes/src/e2fsprogs-minimal/hash +++ b/repos/ports/recipes/src/e2fsprogs-minimal/hash @@ -1 +1 @@ -2024-08-28 2d36df6b4252e787062b1821e890ec359b125597 +2024-10-07 6bfa7acf0be065529bd25d6df4bf89c4fdfc51d9 diff --git a/repos/ports/recipes/src/e2fsprogs/hash b/repos/ports/recipes/src/e2fsprogs/hash index 190da16f3c..9ea0f8ad58 100644 --- a/repos/ports/recipes/src/e2fsprogs/hash +++ b/repos/ports/recipes/src/e2fsprogs/hash @@ -1 +1 @@ -2024-08-28 502e44c1d4f0c41b317bee029c228f443f6098ac +2024-10-07 f7f3f28bebab2194ee72bfa5cf3183e318137ed7 diff --git a/repos/ports/recipes/src/findutils/hash b/repos/ports/recipes/src/findutils/hash index 92301dfbaa..4d83849430 100644 --- a/repos/ports/recipes/src/findutils/hash +++ b/repos/ports/recipes/src/findutils/hash @@ -1 +1 @@ -2024-08-28 503ce613e69d11ed61788b5d9e8d747444adc946 +2024-10-07 148484ede81072cf1da81d5ae807b158e04622ab diff --git a/repos/ports/recipes/src/gcc_x86/hash b/repos/ports/recipes/src/gcc_x86/hash index 8441feb6bf..c3d7fa2255 100644 --- a/repos/ports/recipes/src/gcc_x86/hash +++ b/repos/ports/recipes/src/gcc_x86/hash @@ -1 +1 @@ -2024-08-28 896e40df15aaee4d90ac00d4c0a7326fb4460365 +2024-10-07 c8c00ff1d2be72a689d6f4af9e945f092287e589 diff --git a/repos/ports/recipes/src/gdb_arm_64/hash b/repos/ports/recipes/src/gdb_arm_64/hash index 0bfd3b0d72..64e44c23ea 100644 --- a/repos/ports/recipes/src/gdb_arm_64/hash +++ b/repos/ports/recipes/src/gdb_arm_64/hash @@ -1 +1 @@ -2024-08-28 7932fb975a477c03f2e9a5fde2d71d2179e16d1c +2024-10-07 af4281be58dc7345184353442b065fab2fdbeea4 diff --git a/repos/ports/recipes/src/gdb_support/hash b/repos/ports/recipes/src/gdb_support/hash index b35b5cffab..08446bcec8 100644 --- a/repos/ports/recipes/src/gdb_support/hash +++ b/repos/ports/recipes/src/gdb_support/hash @@ -1 +1 @@ -2024-08-28 160525362e3e0172754d9498f67b949995cca665 +2024-12-10 62fe308b88c7790b0cb0d77820f1ce8be8c1891e diff --git a/repos/ports/recipes/src/gdb_x86/hash b/repos/ports/recipes/src/gdb_x86/hash index 65e37c813e..bc98ea3254 100644 --- a/repos/ports/recipes/src/gdb_x86/hash +++ b/repos/ports/recipes/src/gdb_x86/hash @@ -1 +1 @@ -2024-08-28 1cc48f86c6614b7e7cd1650a074a6dc3cd2ba87e +2024-10-07 a604c59503605324df91f0c6bcdaff0c662d7dbc diff --git a/repos/ports/recipes/src/gnumake/hash b/repos/ports/recipes/src/gnumake/hash index 4436582a6d..1e32cfe728 100644 --- a/repos/ports/recipes/src/gnumake/hash +++ b/repos/ports/recipes/src/gnumake/hash @@ -1 +1 @@ -2024-08-28 8690fe007d695a64c8308c027723899c032be33e +2024-10-07 2a76b398b7d7b015a2e1a37006e8a467571c5356 diff --git a/repos/ports/recipes/src/grep/hash b/repos/ports/recipes/src/grep/hash index a60a854223..ba8ecac8ce 100644 --- a/repos/ports/recipes/src/grep/hash +++ b/repos/ports/recipes/src/grep/hash @@ -1 +1 @@ -2024-08-28 5e30558b4743be8691f115f0657547ead7efab90 +2024-10-07 4706d7ca4889e66fe7fdacb3280405fbc8cdc231 diff --git a/repos/ports/recipes/src/less/hash b/repos/ports/recipes/src/less/hash index 55fbbfc7be..5328b6fb4c 100644 --- a/repos/ports/recipes/src/less/hash +++ b/repos/ports/recipes/src/less/hash @@ -1 +1 @@ -2024-08-28 679c10d6c9b26a6003e4d9d4994e3d658377d39e +2024-10-07 6910a003acd83f5627e960b413c598de0f4503ac diff --git a/repos/ports/recipes/src/lighttpd/hash b/repos/ports/recipes/src/lighttpd/hash index a05e8a435b..1aba45a406 100644 --- a/repos/ports/recipes/src/lighttpd/hash +++ b/repos/ports/recipes/src/lighttpd/hash @@ -1 +1 @@ -2024-08-28 6d0982dff4cdcd6befd92d32db9b50f4b42b3efb +2024-10-07 2c6397b43b92a78b5d260a372c8bdd9bef53770f diff --git a/repos/ports/recipes/src/sed/hash b/repos/ports/recipes/src/sed/hash index ebdafc88bc..aa452e585a 100644 --- a/repos/ports/recipes/src/sed/hash +++ b/repos/ports/recipes/src/sed/hash @@ -1 +1 @@ -2024-08-28 62a82a5180ac3851f666246cc97a232a7b233d4f +2024-10-07 dbea1c077c967a3df9e25fdfa1cb7b55c37185f8 diff --git a/repos/ports/recipes/src/socat/hash b/repos/ports/recipes/src/socat/hash index 3fdbffe213..312844fe5c 100644 --- a/repos/ports/recipes/src/socat/hash +++ b/repos/ports/recipes/src/socat/hash @@ -1 +1 @@ -2024-08-28 7d15fc79efbc8013b16d5276f790d22d0ba400f5 +2024-10-07 26cdfb5105878c87361d6865dc23f1ae7586570e diff --git a/repos/ports/recipes/src/tar/hash b/repos/ports/recipes/src/tar/hash index 1a4fecdd1f..a884162eed 100644 --- a/repos/ports/recipes/src/tar/hash +++ b/repos/ports/recipes/src/tar/hash @@ -1 +1 @@ -2024-08-28 287bb0eac40f29e808e480008a7dd8bba80b893d +2024-10-07 a7129f59052b49bdd8a08e15e6c348a186672860 diff --git a/repos/ports/recipes/src/tclsh/hash b/repos/ports/recipes/src/tclsh/hash index 39543313cb..da71f36e5a 100644 --- a/repos/ports/recipes/src/tclsh/hash +++ b/repos/ports/recipes/src/tclsh/hash @@ -1 +1 @@ -2024-08-28 8dc4d08e71190ca97bc5551420cbdad095e39471 +2024-10-07 02e9a1835903bff990783f4177c5e9e9276f77f2 diff --git a/repos/ports/recipes/src/vbox5-nova/hash b/repos/ports/recipes/src/vbox5-nova/hash index fbf700cc44..028bb1f668 100644 --- a/repos/ports/recipes/src/vbox5-nova/hash +++ b/repos/ports/recipes/src/vbox5-nova/hash @@ -1 +1 @@ -2024-08-28 f86a140163f52f4cc7c2e939bf2239e4aeb8af4a +2024-12-10 f8d89d7ba6b14fc168935dbe12b60dc304b952a8 diff --git a/repos/ports/recipes/src/vbox6/hash b/repos/ports/recipes/src/vbox6/hash index ab2c2679dc..14dc25110e 100644 --- a/repos/ports/recipes/src/vbox6/hash +++ b/repos/ports/recipes/src/vbox6/hash @@ -1 +1 @@ -2024-08-28 02ef881acb967b01541c1d22d3d98b10b3b0b1b8 +2024-12-10 218fc040e12e4ac66c344f585d582766330dcf57 diff --git a/repos/ports/recipes/src/verify/hash b/repos/ports/recipes/src/verify/hash index b7a4e493fb..054e8e6b39 100644 --- a/repos/ports/recipes/src/verify/hash +++ b/repos/ports/recipes/src/verify/hash @@ -1 +1 @@ -2024-08-28 72cec1781db63c8916cc112bcc606fddd181cdcf +2024-12-10 b99d4ac8541bbc9f07ecfff259dffbde2fdf6e58 diff --git a/repos/ports/recipes/src/vim-minimal/hash b/repos/ports/recipes/src/vim-minimal/hash index 8648c4d4fc..4994e7384c 100644 --- a/repos/ports/recipes/src/vim-minimal/hash +++ b/repos/ports/recipes/src/vim-minimal/hash @@ -1 +1 @@ -2024-08-28 fb72690406412c2c74cc3a94fa79e5a3877ddf70 +2024-10-07 365ebf28a7f24544afdaf0faa3f86afdd78409ce diff --git a/repos/ports/recipes/src/vim/hash b/repos/ports/recipes/src/vim/hash index 2a9b1f6bfe..51b85ac97a 100644 --- a/repos/ports/recipes/src/vim/hash +++ b/repos/ports/recipes/src/vim/hash @@ -1 +1 @@ -2024-08-28 c6be30ba52f1d330330e2cba646c93d7a951b132 +2024-10-07 eab4ea05f9b2b70855f0bc20890bea3ac1f9e262 diff --git a/repos/ports/recipes/src/which/hash b/repos/ports/recipes/src/which/hash index adad9f3289..0abb4e7ff0 100644 --- a/repos/ports/recipes/src/which/hash +++ b/repos/ports/recipes/src/which/hash @@ -1 +1 @@ -2024-08-28 b10eb92c70d57004792ee05d122a02d092b2eef2 +2024-10-07 576e4bff550079314235748f3cd4c6df98ed09e0 diff --git a/repos/ports/run/netperf.inc b/repos/ports/run/netperf.inc index 4173f6abd3..16df043016 100644 --- a/repos/ports/run/netperf.inc +++ b/repos/ports/run/netperf.inc @@ -244,8 +244,8 @@ if { $use_wifi_driver } { <ram/> <import> <inline name="wifi_config"> -<wifi_config connected_scan_interval="0" scan_interval="10" rfkill="no" verbose="no" verbose_state="no">} -append config "<network ssid=\"$wifi_ssid\" protection=\"WPA2\" passphrase=\"$wifi_psk\"/>" +<wifi_config>} +append config "<network ssid=\"$wifi_ssid\" protection=\"WPA2\" passphrase=\"$wifi_psk\" auto_connect=\"true\"/>" append config { </wifi_config> </inline> </import> diff --git a/repos/ports/run/vbox5_genode_usb_hid_raw.run b/repos/ports/run/vbox6_genode_usb_hid_raw.run similarity index 67% rename from repos/ports/run/vbox5_genode_usb_hid_raw.run rename to repos/ports/run/vbox6_genode_usb_hid_raw.run index 113fd93ab7..a91223290b 100644 --- a/repos/ports/run/vbox5_genode_usb_hid_raw.run +++ b/repos/ports/run/vbox6_genode_usb_hid_raw.run @@ -16,13 +16,17 @@ if { [have_include "power_on/qemu"] || ![have_spec nova] || ![have_spec x86_64]} create_boot_directory import_from_depot [depot_user]/src/[base_src] \ [depot_user]/src/acpi \ + [depot_user]/src/black_hole \ + [depot_user]/src/expat \ [depot_user]/src/fs_rom \ [depot_user]/src/init \ [depot_user]/src/jpeg \ [depot_user]/src/libc \ + [depot_user]/src/libdrm \ [depot_user]/src/libiconv \ [depot_user]/src/libyuv \ [depot_user]/src/log_terminal \ + [depot_user]/src/mesa \ [depot_user]/src/nitpicker \ [depot_user]/src/pc_usb_host \ [depot_user]/src/pci_decode \ @@ -31,9 +35,10 @@ import_from_depot [depot_user]/src/[base_src] \ [depot_user]/src/ps2 \ [depot_user]/src/report_rom \ [depot_user]/src/stdcxx \ - [depot_user]/src/vbox5-nova \ + [depot_user]/src/vbox6 \ [depot_user]/src/vesa_fb \ [depot_user]/src/vfs \ + [depot_user]/src/vfs_gpu \ [depot_user]/src/vfs_import \ [depot_user]/src/vfs_pipe \ [depot_user]/src/zlib @@ -49,12 +54,18 @@ install_config { <service name="RM"/> <service name="CPU"/> <service name="LOG"/> + <service name="VM"/> </parent-provides> <default-route> <any-service> <parent/> <any-child/> </any-service> </default-route> <default caps="150"/> + <start name="timer"> + <resource name="RAM" quantum="1M"/> + <provides> <service name="Timer"/> </provides> + </start> + <start name="report_rom" priority="-1"> <resource name="RAM" quantum="1M"/> <provides> <service name="Report"/> <service name="ROM"/> </provides> @@ -67,7 +78,7 @@ install_config { </start> <start name="acpi" caps="250"> - <resource name="RAM" quantum="4M"/> + <resource name="RAM" quantum="8M"/> <route> <service name="Report"> <child name="report_rom"/> </service> <any-service> <parent/> <any-child/> </any-service> @@ -92,65 +103,50 @@ install_config { <any-service> <parent/> <any-child/> </any-service> </route> <config> - <policy label_prefix="ps2"> <device name="ps2"/> </policy> - <policy label_prefix="fb" info="yes"> <pci class="VGA"/> </policy> - <policy label_prefix="usb" info="yes"> <pci class="USB"/> </policy> + <policy label_prefix="usb" info="yes"> <pci class="USB"/> </policy> </config> </start> - <start name="timer"> - <resource name="RAM" quantum="1M"/> - <provides><service name="Timer"/></provides> - </start> - <start name="usb" priority="-1"> <binary name="pc_usb_host"/> <resource name="RAM" quantum="16M"/> <provides> <service name="Usb"/> </provides> <config> <report devices="yes" config="yes"/> - <policy label_prefix="virtualbox"><device class="0x3"/></policy> + <policy label_prefix="virtualbox"> <device class="0x3"/> </policy> </config> <route> - <service name="IRQ"><child name="acpi" /></service> - <service name="Report"> <child name="report_rom" /> </service> + <service name="IRQ"> <child name="acpi"/> </service> + <service name="Report"> <child name="report_rom"/> </service> <any-service> <parent/> <any-child/> </any-service> </route> </start> <start name="nitpicker" priority="-1"> <resource name="RAM" quantum="12M"/> - <provides> - <service name="Gui"/> <service name="Capture"/> <service name="Event"/> - </provides> - <route> - <service name="Report"> <child name="report_rom" /> </service> - <any-service> <parent/> <any-child /> </any-service> - </route> + <provides> <service name="Gui"/> </provides> <config> - <capture/> <event/> <report focus="yes" hover="yes" /> - <domain name="pointer" layer="1" content="client" label="no" origin="pointer" /> - <domain name="cpu_load" layer="2" content="client" label="no" /> - <domain name="" layer="3" content="client" label="no" focus="click" hover="always" /> + <domain name="" layer="3" content="client" label="no" focus="click" hover="always"/> - <policy label_prefix="pointer" domain="pointer"/> - <policy label_prefix="cpu_load_display" domain="cpu_load"/> <default-policy domain=""/> </config> + <route> + <service name="Report"> <child name="report_rom"/> </service> + <any-service> <parent/> <any-child /> </any-service> + </route> </start> - <start name="pointer" priority="-1"> - <resource name="RAM" quantum="2M"/> - <provides> <service name="Report"/> </provides> - <config shapes="yes"/> - <route> - <service name="Gui"> <child name="nitpicker"/> </service> - <service name="ROM" label="hover"> <child name="report_rom"/> </service> - <service name="ROM" label="xray"> <child name="report_rom"/> </service> - <any-service> <parent/> </any-service> - </route> + <start name="black_hole"> + <resource name="RAM" quantum="1M"/> + <provides> + <service name="Event"/> + <service name="Nic"/> + </provides> + <config> + <event/> <nic/> + </config> </start> <start name="log_terminal" priority="-1"> @@ -161,19 +157,27 @@ install_config { </start> <start name="virtualbox" caps="800" priority="-2"> - <binary name="virtualbox5-nova"/> - <resource name="RAM" quantum="448M"/> - <config vbox_file="vm_genode_usb_hid_raw.vbox" vm_name="TestVM" xhci="yes"> + <binary name="virtualbox6"/> + <resource name="RAM" quantum="1024M"/> + <config vbox_file="vbox6_genode_usb_hid_raw.vbox" vm_name="TestVM" xhci="yes"> <vfs> <dir name="dev"> - <log/> <terminal/> + <log/> <terminal/> <null/> <inline name="rtc">2022-08-10 00:01</inline> </dir> <dir name="pipe"> <pipe/> </dir> - <rom name="vm_genode_usb_hid_raw.vbox" /> - <rom name="usb_hid_raw.iso" /> + <rom name="vbox6_genode_usb_hid_raw.vbox"/> + <rom name="usb_hid_raw.iso"/> </vfs> <libc stdout="/dev/log" stderr="/dev/log" pipe="/pipe" rtc="/dev/rtc"/> + <arg value="virtualbox"/> + <env key="VBOX_USER_HOME" value="/"/> + <env key="VBOX_LOG_DEST" value="file=/dev/log"/> + <env key="VBOX_LOG" value=""/> + <env key="VBOX_LOG_FLAGS" value="thread"/> + <env key="VBOX_RELEASE_LOG_DEST" value="file=/dev/log"/> + <env key="VBOX_RELEASE_LOG" value=""/> + <env key="VBOX_RELEASE_LOG_FLAGS" value="thread"/> </config> <route> <service name="Report"><child name="report_rom" /></service> @@ -208,19 +212,42 @@ exec -ignorestderr \ --include image/iso \ --include [repository_contains run/usb_hid_raw.run]/run/usb_hid_raw.run -exec ln -sf ${genode_dir}/repos/ports/run/vm_genode_usb_hid_raw.vbox bin/ +exec ln -sf ${genode_dir}/repos/ports/run/vbox6_genode_usb_hid_raw.vbox bin/ exec ln -sf ../../usb_hid_raw.iso bin/ -build_boot_image { usb_hid_raw.iso vm_genode_usb_hid_raw.vbox } +set boot_components [build_artifacts] + +append boot_components { usb_hid_raw.iso vbox6_genode_usb_hid_raw.vbox } + +build_boot_image $boot_components if { ![get_cmd_switch --autopilot] } { run_genode_until forever } # autopilot test -run_genode_until {\[init -\> log_terminal\] \[init -\> event_dump\] Input event #11\t} 150 +run_genode_until {\[init -\> log_terminal\] \[init -\> event_dump\] Input event #0\t} 90 -# pay only attention to the output of event_dump -grep_output {^\[init -\> log_terminal\] \[init -\> event_dump\]} +# remove everything before the first interesting line +regexp {(\[init -\> log_terminal\] \[init -\> event_dump\] Input event #0\t.*)} $output all output + +run_genode_until {.*\[init -\> event_dump\] Input event #11.*\n} 60 [output_spawn_id] + +# pay only attention to the output of init and its children +grep_output {^\[init } + +unify_output {(?n)^\[init -\> log_terminal\] \[init -\> usb_hid\] usb usb-[0-9]-[0-9]: input irq status -19 received} "" +unify_output {(?n) on usb-usbbus.*$} "" +unify_output {(?n) at usb-usbbus.*\)} ")" +unify_output {(?n)hid-generic.*input:} "hid-generic: input:" +unify_output {(?n)usb-[0-9]-[0-9]: USB disconnect, device number [0-9]} "usb-X-X: USB disconnect, device number X" +unify_output {(?n)device number [0-9]+} "device number X" +unify_output {(?n)input[0-9]} "inputX" +unify_output {(?n) as /devices/.*} "" +unify_output {(?n)^\[init -\> usb.*} "" +unify_output {(?n)^\[init -\> log_terminal\] \[init -\> usb.*} "" +unify_output {(?n)^.*dangling allocation.*$} "" +unify_output {(?n)^.*usbfs: process .* did not claim interface.*$} "" +trim_lines compare_output_to { [init -> log_terminal] [init -> event_dump] Input event #0 PRESS KEY_X 65534 key count: 1 diff --git a/repos/ports/run/vbox6_genode_usb_hid_raw.vbox b/repos/ports/run/vbox6_genode_usb_hid_raw.vbox new file mode 100644 index 0000000000..6f575ac33b --- /dev/null +++ b/repos/ports/run/vbox6_genode_usb_hid_raw.vbox @@ -0,0 +1,70 @@ +<?xml version="1.0"?> +<!-- +** DO NOT EDIT THIS FILE. +** If you make changes to this file while any VirtualBox related application +** is running, your changes will be overwritten later, without taking effect. +** Use VBoxManage or the VirtualBox Manager GUI to make changes. +--> +<VirtualBox xmlns="http://www.virtualbox.org/" version="1.18-genode"> + <Machine uuid="{dc7344b5-a8ab-4da6-8e95-be856b753b0b}" name="Ubuntu-22.04" OSType="Ubuntu_64" snapshotFolder="Snapshots" lastStateChange="2017-02-02T23:56:49Z"> + <MediaRegistry> + <DVDImages> + <Image uuid="{81763434-9a51-49e8-9444-528a5a28c4bc}" location="usb_hid_raw.iso"/> + </DVDImages> + </MediaRegistry> + <Hardware> + <CPU count="1" hotplug="false"> + <PAE enabled="true"/> + <LongMode enabled="true"/> + <HardwareVirtExLargePages enabled="false"/> + </CPU> + <Memory RAMSize="256"/> + <HID Pointing="PS2Mouse" Keyboard="PS2Keyboard"/> + <Boot> + <Order position="1" device="DVD"/> + <Order position="2" device="HardDisk"/> + <Order position="3" device="None"/> + <Order position="4" device="None"/> + </Boot> + <Display controller="VMSVGA" VRAMSize="128" monitorCount="1" accelerate3D="false"/> + <VideoCapture enabled="false"/> + <RemoteDisplay enabled="false"/> + <Paravirt provider="KVM"/> + <HPET enabled="false"/> + <Chipset type="ICH9"/> + <BIOS> + <IOAPIC enabled="true"/> + </BIOS> + <USB> + <Controllers> + <Controller name="OHCI" type="OHCI"/> + </Controllers> + </USB> + <Network> + <Adapter slot="0" enabled="true" MACAddress="080027235455" cable="false" speed="0" type="82540EM"> + <HostInterface/> + </Adapter> + </Network> + <UART> + <Port slot="0" enabled="true" IOBase="0x3f8" IRQ="4" path="/dev/terminal" hostMode="HostDevice"/> + <Port slot="1" enabled="false" IOBase="0x2f8" IRQ="3" hostMode="Disconnected"/> + </UART> + <LPT> + <Port slot="0" enabled="false" IOBase="0x378" IRQ="7"/> + <Port slot="1" enabled="false" IOBase="0x378" IRQ="7"/> + </LPT> + <AudioAdapter controller="HDA" driver="oss" enabled="false" enabledIn="false" enabledOut="false"/> + <RTC localOrUTC="UTC"/> + <SharedFolders/> + <Clipboard mode="Disabled"/> + <DragAndDrop mode="Disabled"/> + </Hardware> + <StorageControllers> + <StorageController name="SATA" type="AHCI" PortCount="2" useHostIOCache="true" Bootable="true"> + <AttachedDevice passthrough="false" tempeject="true" type="DVD" port="1" device="0"> + <Image uuid="{81763434-9a51-49e8-9444-528a5a28c4bc}"/> + </AttachedDevice> + </StorageController> + </StorageControllers> + </Machine> +</VirtualBox> diff --git a/repos/ports/run/vm_genode_usb_hid_raw.vbox b/repos/ports/run/vm_genode_usb_hid_raw.vbox deleted file mode 100644 index 0ee4948ccc..0000000000 --- a/repos/ports/run/vm_genode_usb_hid_raw.vbox +++ /dev/null @@ -1,163 +0,0 @@ -<?xml version="1.0"?> -<!-- -** DO NOT EDIT THIS FILE. -** If you make changes to this file while any VirtualBox related application -** is running, your changes will be overwritten later, without taking effect. -** Use VBoxManage or the VirtualBox Manager GUI to make changes. ---> -<VirtualBox xmlns="http://www.innotek.de/VirtualBox-settings" version="1.14-linux"> - <Machine uuid="{410f6221-6237-4833-b02c-a54000b7b190}" name="Genode" OSType="Other" snapshotFolder="Snapshots" lastStateChange="2014-10-30T13:26:17Z"> - <MediaRegistry> - <HardDisks/> - <DVDImages> - <Image uuid="{81763434-9a51-49e8-9444-528a5a28c4bc}" location="usb_hid_raw.iso"/> - </DVDImages> - <FloppyImages/> - </MediaRegistry> - <ExtraData> - <ExtraDataItem name="GUI/LastGuestSizeHint" value="720,400"/> - <ExtraDataItem name="GUI/LastNormalWindowPosition" value="513,100,720,422"/> - </ExtraData> - <Hardware version="2"> - <CPU count="1" hotplug="false"> - <HardwareVirtEx enabled="true"/> - <HardwareVirtExNestedPaging enabled="true"/> - <HardwareVirtExVPID enabled="true"/> - <HardwareVirtExUX enabled="false"/> - <PAE enabled="true"/> - <LongMode enabled="true"/> - <HardwareVirtExLargePages enabled="false"/> - <HardwareVirtForce enabled="false"/> - </CPU> - <Memory RAMSize="256" PageFusion="false"/> - <HID Pointing="PS2Mouse" Keyboard="PS2Keyboard"/> - <HPET enabled="false"/> - <Chipset type="ICH9"/> - <Boot> - <Order position="1" device="Floppy"/> - <Order position="2" device="DVD"/> - <Order position="3" device="HardDisk"/> - <Order position="4" device="None"/> - </Boot> - <Display VRAMSize="12" monitorCount="1" accelerate3D="false" accelerate2DVideo="false"/> - <VideoCapture enabled="false" screens="18446744073709551615" horzRes="1024" vertRes="768" rate="512" fps="25"/> - <RemoteDisplay enabled="false" authType="Null" authTimeout="5000"/> - <BIOS> - <ACPI enabled="true"/> - <IOAPIC enabled="true"/> - <Logo fadeIn="true" fadeOut="true" displayTime="0"/> - <BootMenu mode="MessageAndMenu"/> - <TimeOffset value="0"/> - <PXEDebug enabled="false"/> - </BIOS> - <USB> - <Controllers> - <Controller name="OHCI" type="OHCI"/> - </Controllers> - <DeviceFilters/> - </USB> - <Network> - <Adapter slot="0" enabled="false" MACAddress="08002785385E" cable="true" speed="0" type="82540EM"> - <DisabledModes> - <InternalNetwork name="intnet"/> - <NATNetwork name="NatNetwork"/> - </DisabledModes> - <NAT> - <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> - <Alias logging="false" proxy-only="false" use-same-ports="false"/> - </NAT> - </Adapter> - <Adapter slot="1" enabled="false" MACAddress="0800273AD0BB" cable="true" speed="0" type="82540EM"> - <DisabledModes> - <NAT> - <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> - <Alias logging="false" proxy-only="false" use-same-ports="false"/> - </NAT> - </DisabledModes> - </Adapter> - <Adapter slot="2" enabled="false" MACAddress="0800270786C1" cable="true" speed="0" type="82540EM"> - <DisabledModes> - <NAT> - <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> - <Alias logging="false" proxy-only="false" use-same-ports="false"/> - </NAT> - </DisabledModes> - </Adapter> - <Adapter slot="3" enabled="false" MACAddress="0800279B9C1E" cable="true" speed="0" type="82540EM"> - <DisabledModes> - <NAT> - <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> - <Alias logging="false" proxy-only="false" use-same-ports="false"/> - </NAT> - </DisabledModes> - </Adapter> - <Adapter slot="4" enabled="false" MACAddress="080027B94C18" cable="true" speed="0" type="82540EM"> - <DisabledModes> - <NAT> - <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> - <Alias logging="false" proxy-only="false" use-same-ports="false"/> - </NAT> - </DisabledModes> - </Adapter> - <Adapter slot="5" enabled="false" MACAddress="080027E38E65" cable="true" speed="0" type="82540EM"> - <DisabledModes> - <NAT> - <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> - <Alias logging="false" proxy-only="false" use-same-ports="false"/> - </NAT> - </DisabledModes> - </Adapter> - <Adapter slot="6" enabled="false" MACAddress="0800275A8627" cable="true" speed="0" type="82540EM"> - <DisabledModes> - <NAT> - <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> - <Alias logging="false" proxy-only="false" use-same-ports="false"/> - </NAT> - </DisabledModes> - </Adapter> - <Adapter slot="7" enabled="false" MACAddress="0800271CE60A" cable="true" speed="0" type="82540EM"> - <DisabledModes> - <NAT> - <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> - <Alias logging="false" proxy-only="false" use-same-ports="false"/> - </NAT> - </DisabledModes> - </Adapter> - </Network> - <UART> - <Port slot="0" enabled="true" IOBase="0x3f8" IRQ="4" path="/dev/terminal" hostMode="HostDevice"/> - <Port slot="1" enabled="false" IOBase="0x2f8" IRQ="3" hostMode="Disconnected"/> - </UART> - <LPT> - <Port slot="0" enabled="false" IOBase="0x378" IRQ="7"/> - <Port slot="1" enabled="false" IOBase="0x378" IRQ="7"/> - </LPT> - <AudioAdapter controller="AC97" driver="Pulse" enabled="false"/> - <RTC localOrUTC="UTC"/> - <SharedFolders/> - <Clipboard mode="Disabled"/> - <DragAndDrop mode="Disabled"/> - <IO> - <IoCache enabled="true" size="5"/> - <BandwidthGroups/> - </IO> - <HostPci> - <Devices/> - </HostPci> - <EmulatedUSB> - <CardReader enabled="false"/> - </EmulatedUSB> - <Guest memoryBalloonSize="0"/> - <GuestProperties> - <GuestProperty name="/VirtualBox/HostInfo/GUI/LanguageID" value="en_US" timestamp="1414675524029545000" flags=""/> - </GuestProperties> - </Hardware> - <StorageControllers> - <StorageController name="IDE" type="PIIX4" PortCount="2" useHostIOCache="true" Bootable="true"> - <AttachedDevice passthrough="false" tempeject="true" type="DVD" port="1" device="0"> - <Image uuid="{81763434-9a51-49e8-9444-528a5a28c4bc}"/> - </AttachedDevice> - </StorageController> - </StorageControllers> - </Machine> -</VirtualBox> diff --git a/repos/ports/src/app/netperf/netlib.patch b/repos/ports/src/app/netperf/netlib.patch index f99cd1a929..d572e213b6 100644 --- a/repos/ports/src/app/netperf/netlib.patch +++ b/repos/ports/src/app/netperf/netlib.patch @@ -1,28 +1,3 @@ -+++ src/app/netperf/src/netlib.c -@@ -1095,8 +1095,13 @@ - - #endif /* WIN32 */ - -+#ifdef GENODE_BUILD -+void -+start_do_not_use_timer(int time) -+#else - void - start_timer(int time) -+#endif - { - - #ifdef WIN32 -@@ -3059,7 +3063,9 @@ - (which == SEND_BUFFER) ? "SO_SNDBUF" : "SO_RCVBUF", - errno); - fflush(where); -+#ifndef GENODE_BUILD - exit(1); -+#endif - } - if (debug > 1) { - fprintf(where, "netperf: set_sock_buffer: %s of %d requested.\n", +++ src/app/netperf/src/netlib.h @@ -368,7 +368,7 @@ /* Let's define a macro to hide all of this. */ diff --git a/repos/ports/src/app/netperf/omni.patch b/repos/ports/src/app/netperf/omni.patch index 56747cba66..47c2091edf 100644 --- a/repos/ports/src/app/netperf/omni.patch +++ b/repos/ports/src/app/netperf/omni.patch @@ -83,32 +83,3 @@ index 826167a..3c10d0a 100644 int timed_out = 0; int pad_time = 0; -@@ -5312,6 +5312,28 @@ recv_omni() - need_to_accept = 0; - connected = 1; - -+#ifdef GENODE_BUILD -+ /* -+ * We don't support setitimer which uses signals. Instead set timeouts on -+ * the send and recv socket functions to be able to terminate if the host -+ * went away. -+ */ -+ struct timeval timeout; -+ /* XXX LWIP expect ms instead of seconds */ -+ timeout.tv_sec = 10 * 1000; -+ timeout.tv_usec = 0; -+ -+ int sock_error = setsockopt(data_socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, -+ sizeof(timeout)); -+ if (sock_error) -+ fprintf(where, "could not send timeout for send - test may not terminate\n"); -+ -+ sock_error = setsockopt(data_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, -+ sizeof(timeout)); -+ if (sock_error) -+ fprintf(where, "could not send timeout for recv - test may not terminate\n"); -+#endif -+ - #ifdef KLUDGE_SOCKET_OPTIONS - /* this is for those systems which *INCORRECTLY* fail to pass - attributes across an accept() call. Including this goes diff --git a/repos/ports/src/app/netperf/target.mk b/repos/ports/src/app/netperf/target.mk index cae4fa29c3..b2b5baa808 100644 --- a/repos/ports/src/app/netperf/target.mk +++ b/repos/ports/src/app/netperf/target.mk @@ -9,17 +9,14 @@ SRC_C = netserver.c netlib.c netsh.c nettest_bsd.c dscp.c SRC_C += nettest_omni.c net_uuid.c SRC_C += netsys_none.c netsec_none.c netdrv_none.c netrt_none.c netslot_none.c netcpu_none.c -SRC_CC += timer.cc - INC_DIR += $(PRG_DIR) -CC_OPT += -DHAVE_CONFIG_H -DGENODE_BUILD +CC_OPT += -DHAVE_CONFIG_H CC_WARN = -Wall -Wno-unused -Wno-maybe-uninitialized -Wno-format-truncation \ -Wno-stringop-truncation -Wno-stringop-overflow CC_CXX_WARN_STRICT = -vpath timer.cc $(PRG_DIR) -vpath %.c $(NETPERF_DIR)/src +vpath %.c $(NETPERF_DIR)/src # vi: set ft=make : diff --git a/repos/ports/src/app/netperf/timer.cc b/repos/ports/src/app/netperf/timer.cc deleted file mode 100644 index 6121ceea29..0000000000 --- a/repos/ports/src/app/netperf/timer.cc +++ /dev/null @@ -1,78 +0,0 @@ -/* - * \brief Timeout handling for netperf, based on test/alarm - * \author Alexander Boettcher - * \date 2014-01-10 - */ - -/* - * Copyright (C) 2014-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#include <pthread.h> -#include <unistd.h> -#include <base/log.h> - -/* defined in "ports/contrib/netperf/src/netlib.c" */ -extern "C" int times_up; - -namespace { - - struct Timer_thread - { - pthread_t _pthread { }; - pthread_attr_t _attr { }; - pthread_mutex_t _mutex { PTHREAD_MUTEX_INITIALIZER }; - - int _seconds_left = 0; - - void _entry() - { - for (;;) { - sleep(1); - - pthread_mutex_lock(&_mutex); - if (_seconds_left) { - --_seconds_left; - if (_seconds_left == 0) { - times_up = true; - } - } - pthread_mutex_unlock(&_mutex); - } - } - - static void *_entry(void *arg) - { - Timer_thread &myself = *(Timer_thread *)arg; - myself._entry(); - - return nullptr; - } - - Timer_thread() - { - pthread_mutex_init(&_mutex, nullptr); - pthread_create(&_pthread, &_attr, _entry, this); - } - - void schedule_timeout(int seconds) - { - pthread_mutex_lock(&_mutex); - times_up = false; - _seconds_left = seconds; - pthread_mutex_unlock(&_mutex); - } - }; -} - - -extern "C" void -start_timer(int time) -{ - static Timer_thread timer_thread { }; - - timer_thread.schedule_timeout(time); -} diff --git a/repos/ports/src/virtualbox5/frontend/console.cc b/repos/ports/src/virtualbox5/frontend/console.cc index e8ba72f4ca..e3cc5f410f 100644 --- a/repos/ports/src/virtualbox5/frontend/console.cc +++ b/repos/ports/src/virtualbox5/frontend/console.cc @@ -291,7 +291,13 @@ void GenodeConsole::_handle_mode_change() Genodefb *fb = dynamic_cast<Genodefb *>(pFramebuffer); - fb->update_mode(_gui.mode()); + Gui::Rect const gui_win = _gui.window().convert<Gui::Rect>( + [&] (Gui::Rect rect) { return rect; }, + [&] (Gui::Undefined) { return _gui.panorama().convert<Gui::Rect>( + [&] (Gui::Rect rect) { return rect; }, + [&] (Gui::Undefined) { return Gui::Rect { { }, { 800, 600 } }; }); }); + + fb->update_mode(gui_win); update_video_mode(); } @@ -340,7 +346,7 @@ void GenodeConsole::init_backends(IKeyboard * gKeyboard, IMouse * gMouse) HRESULT rc = i_getDisplay()->QueryFramebuffer(0, &pFramebuffer); Assert(SUCCEEDED(rc) && pFramebuffer); - _gui.mode_sigh(_mode_change_signal_dispatcher); + _gui.info_sigh(_mode_change_signal_dispatcher); _handle_mode_change(); } diff --git a/repos/ports/src/virtualbox5/frontend/fb.h b/repos/ports/src/virtualbox5/frontend/fb.h index 89e332779d..34ed4ce607 100644 --- a/repos/ports/src/virtualbox5/frontend/fb.h +++ b/repos/ports/src/virtualbox5/frontend/fb.h @@ -34,13 +34,13 @@ class Genodefb : Genode::Env &_env; Gui::Connection &_gui; Gui::Top_level_view _view { _gui }; - Fb_Genode::Mode _fb_mode { .area = { 1024, 768 } }; + Gui::Rect _gui_win { .at = { }, .area = { 1024, 768 } }; /* * The mode currently used by the VM. Can be smaller than the * framebuffer mode. */ - Fb_Genode::Mode _virtual_fb_mode; + Gui::Area _virtual_fb_mode; void *_attach() { @@ -64,23 +64,23 @@ class Genodefb : { if (!_fb_base) return; - size_t const max_h = Genode::min(_fb_mode.area.h, _virtual_fb_mode.area.h); - size_t const num_pixels = _fb_mode.area.w * max_h; - memset(_fb_base, 0, num_pixels * _fb_mode.bytes_per_pixel()); - _gui.framebuffer.refresh(0, 0, _virtual_fb_mode.area.w, _virtual_fb_mode.area.h); + size_t const max_h = Genode::min(_gui_win.area.h, _virtual_fb_mode.h); + size_t const num_pixels = _gui_win.area.w * max_h; + memset(_fb_base, 0, num_pixels * sizeof(Genode::Pixel_rgb888)); + _gui.framebuffer.refresh({ _gui_win.at, _virtual_fb_mode }); } void _adjust_buffer() { - _gui.buffer(_fb_mode, false); - _view.area(_fb_mode.area); + _gui.buffer({ .area = _gui_win.area, .alpha = false }); + _view.geometry(_gui_win); } - Fb_Genode::Mode _initial_setup() + Gui::Area _initial_setup() { _adjust_buffer(); _view.front(); - return _fb_mode; + return _gui_win.area; } public: @@ -96,14 +96,14 @@ class Genodefb : Assert(rc == VINF_SUCCESS); } - int w() const { return _fb_mode.area.w; } - int h() const { return _fb_mode.area.h; } + int w() const { return _gui_win.area.w; } + int h() const { return _gui_win.area.h; } - void update_mode(Fb_Genode::Mode mode) + void update_mode(Gui::Rect const gui_win) { Lock(); - _fb_mode = mode; + _gui_win = gui_win; if (_fb_base) _env.rm().detach(Genode::addr_t(_fb_base)); @@ -135,32 +135,32 @@ class Genodefb : /* save the new bitmap reference */ _display->QuerySourceBitmap(screen, _display_bitmap.asOutParam()); - bool const ok = (w <= (ULONG)_fb_mode.area.w) && - (h <= (ULONG)_fb_mode.area.h); + bool const ok = (w <= (ULONG)_gui_win.area.w) && + (h <= (ULONG)_gui_win.area.h); - bool const changed = (w != (ULONG)_virtual_fb_mode.area.w) || - (h != (ULONG)_virtual_fb_mode.area.h); + bool const changed = (w != (ULONG)_virtual_fb_mode.w) || + (h != (ULONG)_virtual_fb_mode.h); if (ok && changed) { Genode::log("fb resize : [", screen, "] ", - _virtual_fb_mode.area, " -> ", + _virtual_fb_mode, " -> ", w, "x", h, - " (host: ", _fb_mode.area, ")"); + " (host: ", _gui_win.area, ")"); - if ((w < (ULONG)_fb_mode.area.w) || - (h < (ULONG)_fb_mode.area.h)) { + if ((w < (ULONG)_gui_win.area.w) || + (h < (ULONG)_gui_win.area.h)) { /* clear the old content around the new, smaller area. */ _clear_screen(); } - _virtual_fb_mode = Fb_Genode::Mode { .area = { w, h } }; + _virtual_fb_mode = { w, h }; result = S_OK; } else if (changed) { Genode::log("fb resize : [", screen, "] ", - _virtual_fb_mode.area, " -> ", + _virtual_fb_mode, " -> ", w, "x", h, " ignored" - " (host: ", _fb_mode.area, ")"); + " (host: ", _gui_win.area, ")"); } Unlock(); @@ -213,8 +213,8 @@ class Genodefb : &ulBytesPerLine, &bitmapFormat); - Gui::Area const area_fb = Gui::Area(_fb_mode.area.w, - _fb_mode.area.h); + Gui::Area const area_fb = Gui::Area(_gui_win.area.w, + _gui_win.area.h); Gui::Area const area_vm = Gui::Area(ulWidth, ulHeight); using namespace Genode; @@ -251,7 +251,7 @@ class Genodefb : Lock(); - Gui::Area const area_fb = _fb_mode.area; + Gui::Area const area_fb = _gui_win.area; Gui::Area const area_vm = Gui::Area(width, height); using namespace Genode; @@ -290,8 +290,8 @@ class Genodefb : if (!supported) return E_POINTER; - *supported = ((width <= (ULONG)_fb_mode.area.w) && - (height <= (ULONG)_fb_mode.area.h)); + *supported = ((width <= (ULONG)_gui_win.area.w) && + (height <= (ULONG)_gui_win.area.h)); return S_OK; } diff --git a/repos/ports/src/virtualbox5/spec/nova/vcpu.h b/repos/ports/src/virtualbox5/spec/nova/vcpu.h index 216b91a2fd..38b735ab80 100644 --- a/repos/ports/src/virtualbox5/spec/nova/vcpu.h +++ b/repos/ports/src/virtualbox5/spec/nova/vcpu.h @@ -85,7 +85,7 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher<Genode::Thread>, private: - X86FXSTATE _emt_fpu_state __attribute__((aligned(0x10))); + X86FXSTATE _emt_fpu_state __attribute__((aligned(64))); pthread _pthread; pthread_cond_t _cond_wait; @@ -968,7 +968,7 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher<Genode::Thread>, /* save current FPU state */ fpu_save(reinterpret_cast<char *>(&_emt_fpu_state)); /* write FPU state from pCtx to utcb */ - memcpy(utcb->fpu, pCtx->pXStateR3, sizeof(utcb->fpu)); + memcpy(utcb->fpu, pCtx->pXStateR3, sizeof(X86FXSTATE)); /* tell kernel to transfer current fpu registers to vCPU */ utcb->mtd |= Mtd::FPU; @@ -984,7 +984,7 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher<Genode::Thread>, _current_vcpu = 0; /* write FPU state of vCPU in utcb to pCtx */ - static_assert(sizeof(X86FXSTATE) == sizeof(utcb->fpu), "fpu size mismatch"); + static_assert(sizeof(X86FXSTATE) <= sizeof(utcb->fpu), "fpu size mismatch"); Genode::memcpy(pCtx->pXStateR3, utcb->fpu, sizeof(X86FXSTATE)); /* load saved FPU state of EMT thread */ diff --git a/repos/ports/src/virtualbox6/include/fb.h b/repos/ports/src/virtualbox6/include/fb.h index f1db4d66a0..7e5db31934 100644 --- a/repos/ports/src/virtualbox6/include/fb.h +++ b/repos/ports/src/virtualbox6/include/fb.h @@ -33,13 +33,13 @@ class Genodefb : Genode::Env &_env; Gui::Connection &_gui; Gui::Top_level_view _view { _gui }; - Fb_Genode::Mode _fb_mode { .area = { 1024, 768 } }; + Gui::Rect _gui_win { { }, { 1024, 768 } }; /* * The mode currently used by the VM. Can be smaller than the * framebuffer mode. */ - Fb_Genode::Mode _virtual_fb_mode; + Gui::Area _virtual_fb_area; void *_attach() { @@ -62,23 +62,23 @@ class Genodefb : { if (!_fb_base) return; - size_t const max_h = Genode::min(_fb_mode.area.h, _virtual_fb_mode.area.h); - size_t const num_pixels = _fb_mode.area.w * max_h; - memset(_fb_base, 0, num_pixels * _fb_mode.bytes_per_pixel()); - _gui.framebuffer.refresh(0, 0, _virtual_fb_mode.area.w, _virtual_fb_mode.area.h); + size_t const max_h = Genode::min(_gui_win.area.h, _virtual_fb_area.h); + size_t const num_pixels = _gui_win.area.w * max_h; + memset(_fb_base, 0, num_pixels * sizeof(Genode::Pixel_rgb888)); + _gui.framebuffer.refresh({ _gui_win.at, _virtual_fb_area }); } void _adjust_buffer() { - _gui.buffer(_fb_mode, false); - _view.area(_fb_mode.area); + _gui.buffer({ .area = _gui_win.area, .alpha = false }); + _view.area(_gui_win.area); } - Fb_Genode::Mode _initial_setup() + Gui::Area _initial_setup() { _adjust_buffer(); _view.front(); - return _fb_mode; + return _gui_win.area; } public: @@ -89,7 +89,7 @@ class Genodefb : : _env(env), _gui(gui), - _virtual_fb_mode(_initial_setup()), + _virtual_fb_area(_initial_setup()), _display(display) { int rc = RTCritSectInit(&_fb_lock); @@ -98,14 +98,14 @@ class Genodefb : virtual ~Genodefb() { } - int w() const { return _fb_mode.area.w; } - int h() const { return _fb_mode.area.h; } + int w() const { return _gui_win.area.w; } + int h() const { return _gui_win.area.h; } - void update_mode(Fb_Genode::Mode mode) + void update_mode(Gui::Rect gui_win) { Lock(); - _fb_mode = mode; + _gui_win = gui_win; if (_fb_base) _env.rm().detach(Genode::addr_t(_fb_base)); @@ -137,32 +137,32 @@ class Genodefb : /* save the new bitmap reference */ _display->QuerySourceBitmap(screen, _display_bitmap.asOutParam()); - bool const ok = (w <= (ULONG)_fb_mode.area.w) && - (h <= (ULONG)_fb_mode.area.h); + bool const ok = (w <= (ULONG)_gui_win.area.w) && + (h <= (ULONG)_gui_win.area.h); - bool const changed = (w != (ULONG)_virtual_fb_mode.area.w) || - (h != (ULONG)_virtual_fb_mode.area.h); + bool const changed = (w != (ULONG)_virtual_fb_area.w) || + (h != (ULONG)_virtual_fb_area.h); if (ok && changed) { Genode::log("fb resize : [", screen, "] ", - _virtual_fb_mode.area, " -> ", + _virtual_fb_area, " -> ", w, "x", h, - " (host: ", _fb_mode.area, ")"); + " (host: ", _gui_win.area, ")"); - if ((w < (ULONG)_fb_mode.area.w) || - (h < (ULONG)_fb_mode.area.h)) { + if ((w < (ULONG)_gui_win.area.w) || + (h < (ULONG)_gui_win.area.h)) { /* clear the old content around the new, smaller area. */ _clear_screen(); } - _virtual_fb_mode = Fb_Genode::Mode { .area = { w, h } }; + _virtual_fb_area = { w, h }; result = S_OK; } else if (changed) { Genode::log("fb resize : [", screen, "] ", - _virtual_fb_mode.area, " -> ", + _virtual_fb_area, " -> ", w, "x", h, " ignored" - " (host: ", _fb_mode.area, ")"); + " (host: ", _gui_win.area, ")"); } Unlock(); @@ -215,8 +215,8 @@ class Genodefb : &ulBytesPerLine, &bitmapFormat); - Gui::Area const area_fb = Gui::Area(_fb_mode.area.w, - _fb_mode.area.h); + Gui::Area const area_fb = Gui::Area(_gui_win.area.w, + _gui_win.area.h); Gui::Area const area_vm = Gui::Area(ulWidth, ulHeight); using namespace Genode; @@ -253,7 +253,7 @@ class Genodefb : Lock(); - Gui::Area const area_fb = _fb_mode.area; + Gui::Area const area_fb = _gui_win.area; Gui::Area const area_vm = Gui::Area(width, height); using namespace Genode; @@ -292,8 +292,8 @@ class Genodefb : if (!supported) return E_POINTER; - *supported = ((width <= (ULONG)_fb_mode.area.w) && - (height <= (ULONG)_fb_mode.area.h)); + *supported = ((width <= (ULONG)_gui_win.area.w) && + (height <= (ULONG)_gui_win.area.h)); return S_OK; } diff --git a/repos/ports/src/virtualbox6/main.cc b/repos/ports/src/virtualbox6/main.cc index 96a58a635c..6735edcc03 100644 --- a/repos/ports/src/virtualbox6/main.cc +++ b/repos/ports/src/virtualbox6/main.cc @@ -302,7 +302,7 @@ struct Main : Event_handler Gui::Connection &gui = *new Registered<Gui::Connection>(_gui_connections, _env, label.string()); gui.input.sigh(_input_handler); - gui.mode_sigh(_fb_mode_handler); + gui.info_sigh(_fb_mode_handler); Genodefb *fb = new Genodefb(_env, gui, _idisplay); @@ -411,7 +411,7 @@ void Main::_sync_capslock() void Main::_handle_input() { auto handle_one_event = [&] (Input::Event const &ev) { - /* don't confuse guests and drop CapsLock events in ROM mode */ + /* don't confuse guests and drop CapsLock events in ROM mode */ if (_capslock.mode == Capslock::Mode::ROM) { if (ev.key_press(Input::KEY_CAPSLOCK) || ev.key_release(Input::KEY_CAPSLOCK)) @@ -438,7 +438,11 @@ void Main::_handle_fb_mode() Genodefb *fb = dynamic_cast<Genodefb *>(pFramebuffer); - fb->update_mode(gui.mode()); + Gui::Rect const gui_win = gui.window().convert<Gui::Rect>( + [&] (Gui::Rect rect) { return rect; }, + [&] (Gui::Undefined) { return Gui::Rect { { }, { 1024, 768 } }; }); + + fb->update_mode(gui_win); if ((fb->w() <= 1) && (fb->h() <= 1)) { /* interpret a size of 0x0 as indication to quit VirtualBox */ diff --git a/repos/ports/src/virtualbox6/patches/avx.patch b/repos/ports/src/virtualbox6/patches/avx.patch new file mode 100644 index 0000000000..542d132a87 --- /dev/null +++ b/repos/ports/src/virtualbox6/patches/avx.patch @@ -0,0 +1,75 @@ +--- a/src/virtualbox6/src/VBox/VMM/VMMR3/CPUMR3CpuId.cpp ++++ b/src/virtualbox6/src/VBox/VMM/VMMR3/CPUMR3CpuId.cpp +@@ -2470,6 +2470,8 @@ + pCpum->GuestFeatures.cbMaxExtendedState), + VERR_CPUM_IPE_1); + pVCpu0->cpum.s.Guest.aoffXState[iComponent] = pSubLeaf->uEbx; ++ /* store uEax to later on detect compact mode */ ++// pVCpu0->cpum.s.Guest.aoffXState[iComponent] = pSubLeaf->uEax; + } + + /* Copy the CPU #0 data to the other CPUs. */ +@@ -3558,6 +3560,8 @@ + VERR_CPUM_IPE_2); + continue; + case 1: ++ /* permit compact AVX mode, Intel: 13.2 ENUMERATION OF CPU SUPPORT FOR XSAVE INSTRUCTIONS AND XSAVE- SUPPORTED FEATURES */ ++// pCurLeaf->uEax &= 1 | 2; + pCurLeaf->uEax &= 0; + pCurLeaf->uEcx &= 0; + pCurLeaf->uEdx &= 0; +@@ -4285,7 +4289,8 @@ + rc = cpumR3CpuIdReadIsaExtCfgLegacy(pVM, pIsaExts, pCpumCfg, "SSE4.2", &pConfig->enmSse42, true); + AssertLogRelRCReturn(rc, rc); + +- bool const fMayHaveXSave = fNestedPagingAndFullGuestExec ++ bool const fEnforceHWusage = true; ++ bool const fMayHaveXSave = fEnforceHWusage + && pVM->cpum.s.HostFeatures.fXSaveRstor + && pVM->cpum.s.HostFeatures.fOpSysXSaveRstor; + uint64_t const fXStateHostMask = pVM->cpum.s.fXStateHostMask; +@@ -4296,7 +4301,7 @@ + * unrestricted guest execution mode. Not possible to force this one without + * host support at the moment. + */ +- rc = cpumR3CpuIdReadIsaExtCfgEx(pVM, pIsaExts, "XSAVE", &pConfig->enmXSave, fNestedPagingAndFullGuestExec, ++ rc = cpumR3CpuIdReadIsaExtCfgEx(pVM, pIsaExts, "XSAVE", &pConfig->enmXSave, fEnforceHWusage, + fMayHaveXSave /*fAllowed*/); + AssertLogRelRCReturn(rc, rc); + +@@ -4305,7 +4310,7 @@ + * XSAVE is exposed too. For the time being the default is to only expose this + * to VMs with nested paging and AMD-V or unrestricted guest execution mode. + */ +- rc = cpumR3CpuIdReadIsaExtCfgEx(pVM, pIsaExts, "AVX", &pConfig->enmAvx, fNestedPagingAndFullGuestExec, ++ rc = cpumR3CpuIdReadIsaExtCfgEx(pVM, pIsaExts, "AVX", &pConfig->enmAvx, fEnforceHWusage, + fMayHaveXSave && pConfig->enmXSave && (fXStateHostMask & XSAVE_C_YMM) /*fAllowed*/); + AssertLogRelRCReturn(rc, rc); + +@@ -4314,7 +4319,7 @@ + * XSAVE is exposed too. For the time being the default is to only expose this + * to VMs with nested paging and AMD-V or unrestricted guest execution mode. + */ +- rc = cpumR3CpuIdReadIsaExtCfgEx(pVM, pIsaExts, "AVX2", &pConfig->enmAvx2, fNestedPagingAndFullGuestExec /* temporarily */, ++ rc = cpumR3CpuIdReadIsaExtCfgEx(pVM, pIsaExts, "AVX2", &pConfig->enmAvx2, fEnforceHWusage /* temporarily */, + fMayHaveXSave && pConfig->enmXSave && (fXStateHostMask & XSAVE_C_YMM) /*fAllowed*/); + AssertLogRelRCReturn(rc, rc); + +@@ -4323,7 +4328,7 @@ + * default is to only do this for VMs with nested paging and AMD-V or + * unrestricted guest mode. + */ +- rc = cpumR3CpuIdReadIsaExtCfg(pVM, pIsaExts, "AESNI", &pConfig->enmAesNi, fNestedPagingAndFullGuestExec); ++ rc = cpumR3CpuIdReadIsaExtCfg(pVM, pIsaExts, "AESNI", &pConfig->enmAesNi, fEnforceHWusage); + AssertLogRelRCReturn(rc, rc); + + /** @cfgm{/CPUM/IsaExts/PCLMUL, isaextcfg, depends} +@@ -4425,7 +4430,7 @@ + * being the default is to only do this for VMs with nested paging and AMD-V or + * unrestricted guest mode. + */ +- rc = cpumR3CpuIdReadIsaExtCfg(pVM, pIsaExts, "SSE4A", &pConfig->enmSse4A, fNestedPagingAndFullGuestExec); ++ rc = cpumR3CpuIdReadIsaExtCfg(pVM, pIsaExts, "SSE4A", &pConfig->enmSse4A, fEnforceHWusage); + AssertLogRelRCReturn(rc, rc); + + /** @cfgm{/CPUM/IsaExts/MISALNSSE, isaextcfg, depends} diff --git a/repos/ports/src/virtualbox6/patches/mousebuttons.patch b/repos/ports/src/virtualbox6/patches/mousebuttons.patch new file mode 100644 index 0000000000..2a50a0a16d --- /dev/null +++ b/repos/ports/src/virtualbox6/patches/mousebuttons.patch @@ -0,0 +1,189 @@ +--- a/src/virtualbox6/src/VBox/Devices/VMMDev/VMMDev.cpp ++++ b/src/virtualbox6/src/VBox/Devices/VMMDev/VMMDev.cpp +@@ -150,6 +150,90 @@ + #define VMMDEV_HEARTBEAT_DEFAULT_INTERVAL (2U*RT_NS_1SEC_64) + + ++/* ++ * Mouse-button event tracking ++ * ++ * If mouse press and release events are reported in quick succession (e.g., ++ * with Genode <button-scroll> detection enabled), the guest may miss events if ++ * fButtons is not collected quick enough. ++ */ ++ ++bool VMMDEV::MouseButtons::Button::pending() const ++{ ++ return _pending != Pending::NONE; ++} ++ ++bool VMMDEV::MouseButtons::Button::record(bool const press) ++{ ++ /* ++ * We begin recording only if the state changes, but keep recording ++ * afterwards until nothing is pending anymore. ++ */ ++ if (_pending == Pending::NONE && _pressed == press) ++ return false; ++ ++ switch (_pending) { ++ case Pending::NONE: _pending = press ? Pending::PRESS : Pending::RELEASE; break; ++ case Pending::PRESS: _pending = press ? Pending::PRESS : Pending::PRESS_RELEASE; break; ++ case Pending::PRESS_RELEASE: _pending = press ? Pending::PRESS : Pending::PRESS_RELEASE; break; ++ case Pending::RELEASE: _pending = !press ? Pending::RELEASE : Pending::RELEASE_PRESS; break; ++ case Pending::RELEASE_PRESS: _pending = !press ? Pending::RELEASE : Pending::RELEASE_PRESS; break; ++ } ++ ++ return true; ++} ++ ++bool VMMDEV::MouseButtons::Button::next() ++{ ++ switch (_pending) { ++ case Pending::NONE: break; ++ ++ case Pending::PRESS: _pending = Pending::NONE; _pressed = true; break; ++ case Pending::PRESS_RELEASE: _pending = Pending::RELEASE; _pressed = true; break; ++ case Pending::RELEASE: _pending = Pending::NONE; _pressed = false; break; ++ case Pending::RELEASE_PRESS: _pending = Pending::PRESS; _pressed = false; break; ++ } ++ ++ return _pressed; ++} ++ ++bool VMMDEV::MouseButtons::pending() const ++{ ++ return l.pending() || r.pending() || m.pending() || x1.pending() || x2.pending(); ++} ++ ++void VMMDEV::MouseButtons::clear() ++{ ++ l = r = m = x1 = x2 = { Pending::NONE, 0 }; ++} ++ ++bool VMMDEV::MouseButtons::record(unsigned fButtons) ++{ ++ bool pending = false; ++ ++ pending |= l.record(!!(fButtons & VMMDEV_MOUSE_BUTTON_LEFT)); ++ pending |= r.record(!!(fButtons & VMMDEV_MOUSE_BUTTON_RIGHT)); ++ pending |= m.record(!!(fButtons & VMMDEV_MOUSE_BUTTON_MIDDLE)); ++ pending |= x1.record(!!(fButtons & VMMDEV_MOUSE_BUTTON_X1)); ++ pending |= x2.record(!!(fButtons & VMMDEV_MOUSE_BUTTON_X2)); ++ ++ return pending; ++} ++ ++unsigned VMMDEV::MouseButtons::next() ++{ ++ unsigned next = 0; ++ ++ next |= l.next() ? VMMDEV_MOUSE_BUTTON_LEFT : 0; ++ next |= r.next() ? VMMDEV_MOUSE_BUTTON_RIGHT : 0; ++ next |= m.next() ? VMMDEV_MOUSE_BUTTON_MIDDLE : 0; ++ next |= x1.next() ? VMMDEV_MOUSE_BUTTON_X1 : 0; ++ next |= x2.next() ? VMMDEV_MOUSE_BUTTON_X2 : 0; ++ ++ return next; ++} ++ ++ + #ifndef VBOX_DEVICE_STRUCT_TESTCASE + #ifdef IN_RING3 + +@@ -1079,7 +1163,7 @@ + * @param pThis The VMMDev shared instance data. + * @param pReqHdr The header of the request to handle. + */ +-static int vmmdevReqHandler_GetMouseStatusEx(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr) ++static int vmmdevReqHandler_GetMouseStatusEx(PPDMDEVINS pDevIns, PVMMDEV pThis, PVMMDEVCC pThisCC, VMMDevRequestHeader *pReqHdr) + { + VMMDevReqMouseStatusEx *pReq = (VMMDevReqMouseStatusEx *)pReqHdr; + AssertMsgReturn(pReq->Core.header.size == sizeof(*pReq), ("%u\n", pReq->Core.header.size), VERR_INVALID_PARAMETER); +@@ -1099,7 +1183,14 @@ + pReq->Core.pointerYPos = pThis->yMouseAbs; + pReq->dz = pThis->dzMouse; + pReq->dw = pThis->dwMouse; +- pReq->fButtons = pThis->fMouseButtons; ++ ++ /* accumulated relative wheel motion consumed */ ++ pThis->dzMouse = 0; pThis->dwMouse = 0; ++ ++ pReq->fButtons = pThis->mouseButtons.next(); ++ if (pThis->mouseButtons.pending()) ++ vmmdevNotifyGuestWorker(pDevIns, pThis, pThisCC, VMMDEV_EVENT_MOUSE_POSITION_CHANGED); ++ + LogRel2(("VMMDev: vmmdevReqHandler_GetMouseStatusEx: mouseFeatures=%#x, xAbs=%d, yAbs=%d, zAbs=%d, wMouseRel=%d, fButtons=0x%x\n", + pReq->Core.mouseFeatures, pReq->Core.pointerXPos, pReq->Core.pointerYPos, pReq->dz, pReq->dw, pReq->fButtons)); + return VINF_SUCCESS; +@@ -2753,7 +2844,7 @@ + break; + + case VMMDevReq_GetMouseStatusEx: +- pReqHdr->rc = vmmdevReqHandler_GetMouseStatusEx(pThis, pReqHdr); ++ pReqHdr->rc = vmmdevReqHandler_GetMouseStatusEx(pDevIns, pThis, pThisCC, pReqHdr); + break; + + case VMMDevReq_SetMouseStatus: +@@ -3588,16 +3679,17 @@ + || pThis->yMouseAbs != yAbs + || dz + || dw +- || pThis->fMouseButtons != fButtons) ++ || pThis->mouseButtons.record(fButtons)) + { + Log2(("vmmdevIPort_SetAbsoluteMouse : settings absolute position to x = %d, y = %d, z = %d, w = %d, fButtons = 0x%x\n", + xAbs, yAbs, dz, dw, fButtons)); + + pThis->xMouseAbs = xAbs; + pThis->yMouseAbs = yAbs; +- pThis->dzMouse = dz; +- pThis->dwMouse = dw; +- pThis->fMouseButtons = fButtons; ++ ++ /* accumulate relative wheel motion */ ++ pThis->dzMouse += dz; ++ pThis->dwMouse += dw; + + VMMDevNotifyGuest(pDevIns, pThis, pThisCC, VMMDEV_EVENT_MOUSE_POSITION_CHANGED); + } +@@ -4114,7 +4206,7 @@ + * into saved state, but rather initialize to zeroes on load. */ + pThis->dzMouse = 0; + pThis->dwMouse = 0; +- pThis->fMouseButtons = 0; ++ pThis->mouseButtons.clear(); + + pHlp->pfnSSMGetBool(pSSM, &pThis->fNewGuestFilterMaskValid); + pHlp->pfnSSMGetU32(pSSM, &pThis->fNewGuestFilterMask); +--- a/src/virtualbox6/src/VBox/Devices/VMMDev/VMMDevState.h ++++ b/src/virtualbox6/src/VBox/Devices/VMMDev/VMMDevState.h +@@ -134,7 +134,27 @@ + int32_t yMouseAbs; + int32_t dzMouse; + int32_t dwMouse; +- uint32_t fMouseButtons; ++ ++ struct MouseButtons ++ { ++ enum class Pending { NONE, PRESS, PRESS_RELEASE, RELEASE, RELEASE_PRESS }; ++ ++ struct Button ++ { ++ Pending _pending; ++ bool _pressed; ++ ++ bool pending() const; ++ bool record(bool state); ++ bool next(); ++ } l, r, m, x1, x2; ++ ++ bool pending() const; ++ void clear(); ++ bool record(unsigned fButtons); ++ unsigned next(); ++ } mouseButtons; ++ + /** @} */ + /** Does the guest currently want the host pointer to be shown? */ + uint32_t fHostCursorRequested; diff --git a/repos/ports/src/virtualbox6/patches/rdrand.patch b/repos/ports/src/virtualbox6/patches/rdrand.patch new file mode 100644 index 0000000000..8826800a64 --- /dev/null +++ b/repos/ports/src/virtualbox6/patches/rdrand.patch @@ -0,0 +1,20 @@ +--- a/src/virtualbox6/src/VBox/VMM/VMMR3/CPUMR3CpuId.cpp ++++ b/src/virtualbox6/src/VBox/VMM/VMMR3/CPUMR3CpuId.cpp +@@ -4358,7 +4358,7 @@ + * the default is to only do this for VMs with nested paging and AMD-V or + * unrestricted guest mode. + */ +- rc = cpumR3CpuIdReadIsaExtCfg(pVM, pIsaExts, "RDRAND", &pConfig->enmRdRand, fNestedPagingAndFullGuestExec); ++ rc = cpumR3CpuIdReadIsaExtCfg(pVM, pIsaExts, "RDRAND", &pConfig->enmRdRand, fEnforceHWusage); + AssertLogRelRCReturn(rc, rc); + + /** @cfgm{/CPUM/IsaExts/RDSEED, isaextcfg, depends} +@@ -4366,7 +4366,7 @@ + * the default is to only do this for VMs with nested paging and AMD-V or + * unrestricted guest mode. + */ +- rc = cpumR3CpuIdReadIsaExtCfg(pVM, pIsaExts, "RDSEED", &pConfig->enmRdSeed, fNestedPagingAndFullGuestExec); ++ rc = cpumR3CpuIdReadIsaExtCfg(pVM, pIsaExts, "RDSEED", &pConfig->enmRdSeed, fEnforceHWusage); + AssertLogRelRCReturn(rc, rc); + + /** @cfgm{/CPUM/IsaExts/CLFLUSHOPT, isaextcfg, depends} diff --git a/repos/ports/src/virtualbox6/patches/series b/repos/ports/src/virtualbox6/patches/series index 45963c123e..4dba77e48f 100644 --- a/repos/ports/src/virtualbox6/patches/series +++ b/repos/ports/src/virtualbox6/patches/series @@ -14,3 +14,6 @@ pgmphys.patch sup_ioctl_query_func_size.patch disk_geometry.patch stack_size.patch +avx.patch +rdrand.patch +mousebuttons.patch diff --git a/repos/ports/src/virtualbox6/sup_vcpu.cc b/repos/ports/src/virtualbox6/sup_vcpu.cc index cff44179bb..b4af51dcba 100644 --- a/repos/ports/src/virtualbox6/sup_vcpu.cc +++ b/repos/ports/src/virtualbox6/sup_vcpu.cc @@ -265,12 +265,27 @@ template <typename VIRT> void Sup::Vcpu_impl<VIRT>::_transfer_state_to_vcpu(CPUM state.tpr_threshold.charge(pending_priority); } - /* export FPU state */ - AssertCompile(sizeof(Vcpu_state::Fpu::State) >= sizeof(X86FXSTATE)); + /* export FPU state - start */ + state.xcr0.charge(ctx.aXcr[0]); - _state->ref.fpu.charge([&](Vcpu_state::Fpu::State &fpu) { - ::memcpy(fpu._buffer, ctx.pXStateR3, sizeof(fpu)); + { + ::uint64_t ia32_xss = 0; + auto const rc = CPUMQueryGuestMsr(&_vmcpu, 0xDA0 /* MSR_IA32_XSS */, + &ia32_xss); + + if (rc == VINF_SUCCESS) + state.xss.charge(ia32_xss); + } + + _state->ref.fpu.charge([&](Vcpu_state::Fpu::State &fpu) { + unsigned fpu_size = min(_vm.cpum.s.HostFeatures.cbMaxExtendedState, + sizeof(fpu._buffer)); + + ::memcpy(fpu._buffer, ctx.pXStateR3, fpu_size); + + return fpu_size; }); + /* export FPU state - end */ { ::uint64_t tsc_aux = 0; @@ -413,12 +428,21 @@ template <typename VIRT> void Sup::Vcpu_impl<VIRT>::_transfer_state_to_vbox(CPUM APICSetTpr(pVCpu, tpr); - /* import FPU state */ + /* import FPU state - start */ _state->ref.fpu.with_state([&](Vcpu_state::Fpu::State const &fpu) { - ::memcpy(ctx.pXStateR3, fpu._buffer, sizeof(X86FXSTATE)); + unsigned fpu_size = min(_vm.cpum.s.HostFeatures.cbMaxExtendedState, + sizeof(fpu._buffer)); + + ::memcpy(ctx.pXStateR3, fpu._buffer, fpu_size); + return true; }); + CPUMSetGuestMsr (pVCpu, 0xDA0 /* MSR_IA32_XSS */, state.xss.value()); + CPUMSetGuestXcr0(pVCpu, state.xcr0.value()); + + /* import FPU state - end */ + /* do SVM/VMX-specific transfers */ VIRT::transfer_state_to_vbox(state, _vmcpu, ctx); } diff --git a/repos/ports/src/virtualbox6/sup_vcpu_svm.h b/repos/ports/src/virtualbox6/sup_vcpu_svm.h index 53f38ee497..39068661e5 100644 --- a/repos/ports/src/virtualbox6/sup_vcpu_svm.h +++ b/repos/ports/src/virtualbox6/sup_vcpu_svm.h @@ -77,6 +77,7 @@ Genode::Vm_connection::Exit_config const Sup::Svm::exit_config { /* ... */ }; | SVM_CTRL_INTERCEPT_WBINVD | SVM_CTRL_INTERCEPT_MONITOR | SVM_CTRL_INTERCEPT_RDTSCP + | SVM_CTRL_INTERCEPT_XSETBV | SVM_CTRL_INTERCEPT_MWAIT; unsigned Sup::Svm::ctrl_primary() diff --git a/repos/ports/src/virtualbox6/sup_vcpu_vmx.h b/repos/ports/src/virtualbox6/sup_vcpu_vmx.h index 21d2f73bb0..b6236accd4 100644 --- a/repos/ports/src/virtualbox6/sup_vcpu_vmx.h +++ b/repos/ports/src/virtualbox6/sup_vcpu_vmx.h @@ -81,6 +81,7 @@ unsigned Sup::Vmx::ctrl_secondary() | VMX_PROC_CTLS2_RDTSCP | VMX_PROC_CTLS2_EPT | VMX_PROC_CTLS2_INVPCID + | VMX_PROC_CTLS2_XSAVES_XRSTORS ; } diff --git a/tool/autopilot.list b/tool/autopilot.list index 406e3471d1..a5da125d99 100644 --- a/tool/autopilot.list +++ b/tool/autopilot.list @@ -86,7 +86,6 @@ tz_vmm usb_block usb_hid_raw usb_hid_reconnect -vbox5_genode_usb_hid_raw vbox5_ubuntu_16_04_32 vbox5_ubuntu_16_04_64 vbox5_win10_64 @@ -95,6 +94,7 @@ vbox5_win7_64 vbox5_win7_64_multiple vbox5_win7_64_raw vbox5_win7_64_share +vbox6_genode_usb_hid_raw verify vfs_cfg vfs_import diff --git a/tool/builddir/build.conf/repos_arm_v6 b/tool/builddir/build.conf/repos_arm_v6 index a00b0e1309..9e010ed15c 100644 --- a/tool/builddir/build.conf/repos_arm_v6 +++ b/tool/builddir/build.conf/repos_arm_v6 @@ -1,4 +1,6 @@ + # # Board support for Raspberry Pi family # #REPOSITORIES += $(GENODE_DIR)/repos/rpi + diff --git a/tool/builddir/build.conf/repos_arm_v7 b/tool/builddir/build.conf/repos_arm_v7 index a708c1522b..86ee83ee7f 100644 --- a/tool/builddir/build.conf/repos_arm_v7 +++ b/tool/builddir/build.conf/repos_arm_v7 @@ -1,3 +1,4 @@ + # # Board-support for Xilinx Zynq-7000 SoC # diff --git a/tool/builddir/build.conf/repos_arm_v8 b/tool/builddir/build.conf/repos_arm_v8 index 8bdd984dc9..7793e54b10 100644 --- a/tool/builddir/build.conf/repos_arm_v8 +++ b/tool/builddir/build.conf/repos_arm_v8 @@ -1,3 +1,4 @@ + # # Board support for i.MX SoC family # @@ -12,3 +13,4 @@ # Board support for Allwinner SoC family # #REPOSITORIES += $(GENODE_DIR)/repos/allwinner + diff --git a/tool/builddir/build.conf/repos_riscv b/tool/builddir/build.conf/repos_riscv index 2141a9716d..a0c0333057 100644 --- a/tool/builddir/build.conf/repos_riscv +++ b/tool/builddir/build.conf/repos_riscv @@ -1,3 +1,4 @@ + # # Board support for RISC-V Qemu / MiG-V # diff --git a/tool/builddir/build.conf/repos_x86 b/tool/builddir/build.conf/repos_x86 index 67d9230eb7..d41ebfd37a 100644 --- a/tool/builddir/build.conf/repos_x86 +++ b/tool/builddir/build.conf/repos_x86 @@ -1,3 +1,4 @@ + # # Drivers for x86 PC # diff --git a/tool/create_builddir b/tool/create_builddir index f465fbf49b..d78c9c0375 100755 --- a/tool/create_builddir +++ b/tool/create_builddir @@ -85,13 +85,13 @@ endif $(BUILD_DIR)/etc: @mkdir -p $@ -BUILD_CONF_X86 := run_x86 run_boot_dir repos repos_x86 -BUILD_CONF_ARM_V6 := run_arm_v6 run_boot_dir repos repos_arm_v6 -BUILD_CONF_ARM_V7 := run_arm_v7 run_boot_dir repos repos_arm_v7 +BUILD_CONF_X86 := run_x86 run_boot_dir repos_x86 repos +BUILD_CONF_ARM_V6 := run_arm_v6 run_boot_dir repos_arm_v6 repos +BUILD_CONF_ARM_V7 := run_arm_v7 run_boot_dir repos_arm_v7 repos BUILD_CONF(arm_v6) := $(BUILD_CONF_ARM_V6) BUILD_CONF(arm_v7a) := $(BUILD_CONF_ARM_V7) -BUILD_CONF(arm_v8a) := run_arm_v8 run_boot_dir repos repos_arm_v8 -BUILD_CONF(riscv) := run_riscv run_boot_dir repos repos_riscv +BUILD_CONF(arm_v8a) := run_arm_v8 run_boot_dir repos_arm_v8 repos +BUILD_CONF(riscv) := run_riscv run_boot_dir repos_riscv repos BUILD_CONF(x86_32) := run_x86_32 $(BUILD_CONF_X86) BUILD_CONF(x86_64) := run_x86_64 $(BUILD_CONF_X86) diff --git a/tool/depot/build b/tool/depot/build index a2d5855ecd..17a7965abc 100755 --- a/tool/depot/build +++ b/tool/depot/build @@ -159,9 +159,39 @@ execute_generated_build_mk_file: $(BUILD_MK_FILE) $(VERBOSE)$(MAKE) -j64 $(if $(VERBOSE),--quiet) -f $(BUILD_MK_FILE) \ -C $(DEPOT_DIR) VERBOSE=$(VERBOSE) +# +# Utilities to check consistency of bin archives with their src and used APIS +# +_eq = $(and $(findstring x$(1),x$(2)), $(findstring x$(2),x$(1))) +_libapi = $(if $(wildcard $(DEPOT_DIR)/$1/api),$(call file_content,$(DEPOT_DIR)/$1/api),) +_apis_of_src = $(call _libapi,$1) $(call file_content,$(DEPOT_DIR)/$1/used_apis) +_api_archives_of_src = $(addprefix $(call archive_user,$1)/api/,$(call _apis_of_src,$1)) +_api_hashes = $(foreach A,$(call _api_archives_of_src,$1),$(call file_content,$(DEPOT_DIR)/$A.hash)) +_src_hash = $(call file_content,$(DEPOT_DIR)/$1.hash) +_src_and_api_hashes = $(call _src_hash,$1) $(call _api_hashes,$1) +_src_of_bin = $(call archive_user,$1)/src/$(call bin_archive_recipe,$1)/$(call bin_archive_version,$1) +_bin_ingredient_hashes = $(call _src_and_api_hashes,$(call _src_of_bin,$1)) +_bin_hashes = $(call file_content,$(DEPOT_DIR)/$1.hash) +_bin_exists = $(wildcard $(DEPOT_DIR)/$1) +_bin_inconsistent = $(if $(call _bin_exists,$1),\ + $(if $(call _eq,$(call _bin_ingredient_hashes,$1),$(call _bin_hashes,$1)),,$1)) + ifneq ($(REBUILD),) execute_generated_build_mk_file: wipe_existing_archives +else +INCONSISTENT_BIN_ARCHIVES = $(strip $(foreach I,${ARCHIVES(bin)},$(call _bin_inconsistent,$I))) +ifneq ($(INCONSISTENT_BIN_ARCHIVES),) +execute_generated_build_mk_file: report_bin_src_inconsistencies endif +endif # REBUILD + +report_bin_src_inconsistencies: + @( \ + echo -e "\nError: the following bin archives do not match their src and apis:\n"; \ + for i in $(INCONSISTENT_BIN_ARCHIVES); do echo -e " $$i"; done; \ + echo -e "\nYou may consider removing those binary archives from the depot.\n" \ + ) + @false $(MAKECMDGOALS): execute_generated_build_mk_file @true diff --git a/tool/depot/mk/build_bin_archive b/tool/depot/mk/build_bin_archive index 78f4d82263..3970dcb336 100755 --- a/tool/depot/mk/build_bin_archive +++ b/tool/depot/mk/build_bin_archive @@ -125,6 +125,7 @@ endif DEPOT_BIN_ARCHIVE_DIR := $(DEPOT_BIN_DIR)/$(SPEC)/$(VERSIONED_ARCHIVE) DEPOT_DBG_ARCHIVE_DIR := $(DEPOT_DBG_DIR)/$(SPEC)/$(VERSIONED_ARCHIVE) DEPOT_ARCHIVE_BUILD_DIR := $(addsuffix .build,$(DEPOT_BIN_ARCHIVE_DIR)) +DEPOT_BIN_HASH_FILE := $(addsuffix .hash,$(DEPOT_BIN_ARCHIVE_DIR)) # @@ -230,7 +231,13 @@ $(DEPOT_DBG_ARCHIVE_DIR): $(DEPOT_ARCHIVE_BUILD_DIR)/debug $(VERBOSE)find $< -name *.debug -exec cp {} $@/ \; @$(ECHO) "$(DARK_COL)created$(DEFAULT_COL) $(USER)/dbg/$(SPEC)/$(VERSIONED_ARCHIVE)" -$(TARGET): $(DEPOT_BIN_ARCHIVE_DIR) +INGREDIENTS := $(addprefix src/,$(ARCHIVE)) $(addprefix api/,$(USED_APIS)) +INGREDIENTS_HASHES := $(foreach I,$(INGREDIENTS),$(call file_content,$(DEPOT_DIR)/$(USER)/$I.hash)) + +$(DEPOT_BIN_HASH_FILE): $(DEPOT_BIN_ARCHIVE_DIR) + $(VERBOSE)echo "$(INGREDIENTS_HASHES)" > $@ + +$(TARGET): $(DEPOT_BIN_HASH_FILE) ifneq ($(DBG),) $(TARGET): $(DEPOT_DBG_ARCHIVE_DIR) diff --git a/tool/depot/mk/extract.inc b/tool/depot/mk/extract.inc index e2390e0a89..192c9889c3 100644 --- a/tool/depot/mk/extract.inc +++ b/tool/depot/mk/extract.inc @@ -131,7 +131,7 @@ _rename_to_final_archive: _check_hash hint=" $(BRIGHT_COL)(new version)$(DEFAULT_COL)"; \ test $$hash = $(ORIG_RECIPE_HASH_VALUE) || \ $(VERSION_UPDATED_CMD); \ - rm -f $(DEPOT_ARCHIVE_DIR).hash; \ + mv $(DEPOT_ARCHIVE_DIR).hash $(DEPOT_SUB_DIR)/$$final_name.hash; \ $(ECHO) "$(DARK_COL)created$(DEFAULT_COL)" \ "$(USER)/$(notdir $(DEPOT_SUB_DIR))/$$final_name$$hint"; \ true; diff --git a/tool/ports/metadata b/tool/ports/metadata index 9bcdb64db7..d1018ae394 100755 --- a/tool/ports/metadata +++ b/tool/ports/metadata @@ -13,15 +13,15 @@ endif export GENODE_DIR := $(realpath $(dir $(MAKEFILE_LIST))/../..) usage: - @$(ECHO) - @$(ECHO) "Tool for retrieving version information of port sources" - @$(ECHO) - @$(ECHO) "usage:" - @$(ECHO) - @$(ECHO) " $(notdir $(MAKEFILE_LIST)) <ports>" - @$(ECHO) - @$(ECHO) " <ports> whitespace-separated list of ports" - @$(ECHO) + @echo + @echo "Tool for retrieving version information of port sources" + @echo + @echo "usage:" + @echo + @echo " $(notdir $(MAKEFILE_LIST)) <ports>" + @echo + @echo " <ports> whitespace-separated list of ports" + @echo TARGETS = $(sort $(MAKECMDGOALS)) diff --git a/tool/run/amt.inc b/tool/run/amt.inc index 62d887caec..4fc882df2b 100644 --- a/tool/run/amt.inc +++ b/tool/run/amt.inc @@ -23,6 +23,10 @@ proc is_amt_available { {host "" } {password "" } } { return true } + if {[have_installed meshcmd]} { + return true + } + puts "No support for Intel's AMT detected." return false } diff --git a/tool/run/bender.inc b/tool/run/bender.inc new file mode 100644 index 0000000000..5251f470e4 --- /dev/null +++ b/tool/run/bender.inc @@ -0,0 +1,28 @@ +# +# Return Bender option that configures Bender's Intel HWP plugin +# +# \param --bender-intel-hwp-mode Run the Intel HWP plugin of Bender in the +# given mode. Valid argument values are +# "off", +# "performance", +# "balanced", and +# "power_saving" +# The argument value defaults to +# "performance". +# +proc bender_intel_hwp_mode_option { } { + + set opt [get_cmd_arg_first --bender-intel-hwp-mode "performance"] + if {$opt == "off"} { + return "intel_hwp_off" + } elseif {$opt == "performance"} { + return "intel_hwp_performance" + } elseif {$opt == "balanced"} { + return "intel_hwp_balanced" + } elseif {$opt == "power_saving"} { + return "intel_hwp_power_saving" + } else { + return "intel_hwp_performance" + } +} + diff --git a/tool/run/boot_dir/fiasco b/tool/run/boot_dir/fiasco index e7f7b86174..21ed900915 100644 --- a/tool/run/boot_dir/fiasco +++ b/tool/run/boot_dir/fiasco @@ -10,6 +10,7 @@ proc core_link_address { } { return "0x01000000" } proc boot_output { } { return "serial" } +proc grub_menuentry { } { return "'Genode on L4/Fiasco'" } ## # Populate boot directory with binaries on fiasco @@ -66,7 +67,7 @@ proc run_boot_dir {binaries} { # The core binary is part of the 'binaries' list but it must # appear right after 'sigma0' as boot module. Hence the special case. # - puts $fh "menuentry 'Genode on L4/Fiasco' {" + puts $fh "menuentry [grub_menuentry] {" puts $fh " insmod multiboot" puts $fh " multiboot /boot/bender [boot_output]" puts $fh " module /boot/bootstrap -serial" diff --git a/tool/run/boot_dir/foc b/tool/run/boot_dir/foc index 35c4be2ed8..564eb4997f 100644 --- a/tool/run/boot_dir/foc +++ b/tool/run/boot_dir/foc @@ -1,3 +1,5 @@ +source [genode_dir]/tool/run/bender.inc + proc binary_name_ld_lib_so { } { return "ld-foc.lib.so" } proc binary_name_core_a { } { return "core-foc-[board].a" } proc binary_name_timer { } { return "foc_timer" } @@ -26,6 +28,8 @@ proc fiasco_serial_esc_arg { } { return "-serial_esc " } proc boot_output { } { return "serial" } +proc grub_menuentry { } { return "'Genode on Fiasco.OC'" } + ## # Reset the target system via the Fiasco.OC kernel debugger @@ -92,7 +96,9 @@ proc run_boot_dir_x86 {binaries} { exec mv [run_dir]/image.elf [run_dir]/boot/image.elf - if {[have_include "image/iso"] || [have_include "image/disk"]} { + set options_bender "[boot_output] [bender_intel_hwp_mode_option]" + + if {[have_include "image/iso"] || [have_include "image/disk"] || [have_include image/uefi]} { if {[have_include "image/disk"]} { install_disk_bootloader_to_run_dir @@ -102,6 +108,11 @@ proc run_boot_dir_x86 {binaries} { install_iso_bootloader_to_run_dir } + if {[have_include image/uefi]} { + install_uefi_bootloader_to_run_dir + append options_bender " serial_fallback" + } + # # Generate GRUB2 config file # @@ -110,9 +121,9 @@ proc run_boot_dir_x86 {binaries} { # The core binary is part of the 'binaries' list but it must # appear right after 'sigma0' as boot module. Hence the special case. # - puts $fh "menuentry 'Genode on Fiasco.OC' {" + puts $fh "menuentry [grub_menuentry] {" puts $fh " insmod multiboot" - puts $fh " multiboot /boot/bender [boot_output]" + puts $fh " multiboot /boot/bender $options_bender" puts $fh " module /boot/bootstrap" puts $fh " module /boot/kernel fiasco [fiasco_serial_esc_arg]" puts $fh " module /boot/sigma0" @@ -126,7 +137,7 @@ proc run_boot_dir_x86 {binaries} { # run_image - if {[have_include "load/tftp"]} { + if {[have_spec x86] && [have_include "load/tftp"]} { # # Install PXE bootloader pulsar # @@ -136,7 +147,7 @@ proc run_boot_dir_x86 {binaries} { # Generate pulsar config file # set fh [open "[run_dir]/config-52-54-00-12-34-56" "WRONLY CREAT TRUNC"] - puts $fh " exec /boot/bender [boot_output]" + puts $fh " exec /boot/bender $options_bender" puts $fh " load /boot/bootstrap" puts $fh " load /boot/kernel -serial_esc" puts $fh " load /boot/sigma0" @@ -146,7 +157,7 @@ proc run_boot_dir_x86 {binaries} { generate_tftp_config } - if {[have_include "load/ipxe"]} { + if {[have_spec x86] && [have_include "load/ipxe"]} { create_ipxe_config update_ipxe_boot_dir create_symlink_for_iso diff --git a/tool/run/boot_dir/hw b/tool/run/boot_dir/hw index 469a90be50..e342d92a9e 100644 --- a/tool/run/boot_dir/hw +++ b/tool/run/boot_dir/hw @@ -1,3 +1,5 @@ +source [genode_dir]/tool/run/bender.inc + proc binary_name_ld_lib_so { } { return "ld-hw.lib.so" } proc binary_name_core_a { } { return "core-hw.a" } proc binary_name_timer { } { return "hw_timer" } @@ -8,6 +10,8 @@ proc run_boot_string { } { return "\nkernel initialized" } proc boot_output { } { return "serial" } +proc grub_menuentry { } { return "'Genode on base-hw'" } + proc bootstrap_link_address { } { @@ -75,6 +79,7 @@ proc run_boot_dir {binaries} { if {[file exists debug/core-hw-[board].a]} { build_core debug/core-hw-[board].a {} [run_dir].core [core_link_address] build_core [run_dir]/genode/$bootstrap_obj {} [run_dir].bootstrap [bootstrap_link_address] + exec [cross_dev_prefix]objcopy --only-keep-debug [run_dir].core [run_dir].core.debug } # determine modules to be incorporated into the core image @@ -102,7 +107,7 @@ proc run_boot_dir {binaries} { exec mkdir -p [run_dir]/boot exec mv [run_dir]/image-hw.elf [run_dir]/boot/image-hw.elf - set options_bender "[boot_output] " + set options_bender "[boot_output] [bender_intel_hwp_mode_option]" if {[have_include "image/iso"] || [have_include "image/disk"] || [have_include image/uefi]} { # @@ -128,7 +133,7 @@ proc run_boot_dir {binaries} { # set fh [create_header_grub2_config] - puts $fh "menuentry 'Genode on base-hw' {" + puts $fh "menuentry [grub_menuentry] {" puts $fh " insmod multiboot2" puts $fh " multiboot2 /boot/bender $options_bender" puts $fh " module2 /boot/image-hw.elf.gz image-hw.elf" diff --git a/tool/run/boot_dir/linux b/tool/run/boot_dir/linux index c45f6fe46a..bdca40b561 100644 --- a/tool/run/boot_dir/linux +++ b/tool/run/boot_dir/linux @@ -2,6 +2,7 @@ proc binary_name_ld_lib_so { } { return "ld-linux.lib.so" } proc binary_name_core { } { return "core-linux" } proc binary_name_timer { } { return "linux_timer" } +proc grub_menuentry { } { return "'Genode on Linux'" } ## # Populate boot directory with binaries on Linux @@ -56,7 +57,7 @@ proc run_boot_dir {binaries} { set fh [open "[run_dir]/boot/grub/grub.cfg" "WRONLY CREAT TRUNC"] puts $fh "set timeout=0" - puts $fh "menuentry 'Genode on Linux' {" + puts $fh "menuentry [grub_menuentry] {" puts $fh " insmod linux" puts $fh " linux /vmlinuz console=ttyS0,115200 amd_iommu=off intel_iommu=off" puts $fh " initrd /initrd" diff --git a/tool/run/boot_dir/nova b/tool/run/boot_dir/nova index 720189004f..41cb168521 100644 --- a/tool/run/boot_dir/nova +++ b/tool/run/boot_dir/nova @@ -1,30 +1,4 @@ -# -# Return Bender option that configures Bender's Intel HWP plugin -# -# \param --bender-intel-hwp-mode Run the Intel HWP plugin of Bender in the -# given mode. Valid argument values are -# "off", -# "performance", -# "balanced", and -# "power_saving" -# The argument value defaults to -# "performance". -# -proc bender_intel_hwp_mode_option { } { - - set opt [get_cmd_arg_first --bender-intel-hwp-mode "performance"] - if {$opt == "off"} { - return "intel_hwp_off" - } elseif {$opt == "performance"} { - return "intel_hwp_performance" - } elseif {$opt == "balanced"} { - return "intel_hwp_balanced" - } elseif {$opt == "power_saving"} { - return "intel_hwp_power_saving" - } else { - return "intel_hwp_performance" - } -} +source [genode_dir]/tool/run/bender.inc proc binary_name_ld_lib_so { } { return "ld-nova.lib.so" } proc binary_name_core_a { } { return "core-nova.a" } @@ -35,6 +9,8 @@ proc kernel_output { } { return "serial" } proc boot_output { } { return "serial" } +proc grub_menuentry { } { return "'Genode on NOVA'" } + proc run_boot_string { } { return "\nHypervisor NOVA " } @@ -122,7 +98,7 @@ proc run_boot_dir {binaries} { # set fh [create_header_grub2_config] - puts $fh "menuentry 'Genode on NOVA' {" + puts $fh "menuentry [grub_menuentry] {" puts $fh " insmod multiboot2" puts $fh " insmod gzio" puts $fh " multiboot2 /boot/bender $options_bender" diff --git a/tool/run/boot_dir/okl4 b/tool/run/boot_dir/okl4 index 8ccf0ce370..953d9752eb 100644 --- a/tool/run/boot_dir/okl4 +++ b/tool/run/boot_dir/okl4 @@ -6,6 +6,8 @@ proc kernel_files { } { return okl4 } proc boot_output { } { return "serial" } +proc grub_menuentry { } { return "'Genode on OKL4'" } + ## # Get the base-okl4 repository # @@ -177,7 +179,7 @@ proc run_boot_dir {binaries} { # The core binary is part of the 'binaries' list but it must # appear right after 'sigma0' as boot module. Hence the special case. # - puts $fh "menuentry 'Genode on OKL4' {" + puts $fh "menuentry [grub_menuentry] {" puts $fh " insmod multiboot" puts $fh " multiboot /boot/bender [boot_output]" puts $fh " module /boot/image.elf" diff --git a/tool/run/boot_dir/pistachio b/tool/run/boot_dir/pistachio index b59c0b842f..948ce10fda 100644 --- a/tool/run/boot_dir/pistachio +++ b/tool/run/boot_dir/pistachio @@ -9,6 +9,9 @@ proc core_link_address { } { return "0x02000000" } proc boot_output { } { return "serial" } +proc grub_menuentry { } { return "'Genode on L4ka::Pistachio'" } + + ## # Populdate boot directory with binaries on pistachio # @@ -64,7 +67,7 @@ proc run_boot_dir {binaries} { # The core binary is part of the 'binaries' list but it must # appear right after 'sigma0' as boot module. Hence the special case. # - puts $fh "menuentry 'Genode on L4ka::Pistachio' {" + puts $fh "menuentry [grub_menuentry] {" puts $fh " insmod multiboot" puts $fh " multiboot /boot/bender [boot_output]" puts $fh " module /boot/kickstart" diff --git a/tool/run/boot_dir/sel4 b/tool/run/boot_dir/sel4 index 992ac2818d..c2cc03c92f 100644 --- a/tool/run/boot_dir/sel4 +++ b/tool/run/boot_dir/sel4 @@ -1,3 +1,5 @@ +source [genode_dir]/tool/run/bender.inc + proc binary_name_ld_lib_so { } { return "ld-sel4.lib.so" } proc binary_name_core_a { } { return "core-sel4.a" } proc binary_name_timer { } { @@ -12,6 +14,8 @@ proc kernel_files { } { return sel4 } proc boot_output { } { return "serial" } +proc grub_menuentry { } { return "'Genode on seL4'" } + proc run_boot_string { } { return "\nBooting all finished, dropped to user space" } proc core_link_address { } { return "0x02000000" } @@ -55,7 +59,7 @@ proc run_boot_dir {binaries} { exec mv [run_dir]/image.elf [run_dir]/boot/image.elf - set options_bender "[boot_output] phys_max=256M" + set options_bender "[boot_output] [bender_intel_hwp_mode_option] phys_max=256M" if {[have_include "image/iso"] || [have_include "image/disk"] || [have_include image/uefi]} { @@ -69,7 +73,7 @@ proc run_boot_dir {binaries} { if {[have_include image/uefi]} { install_uefi_bootloader_to_run_dir - set options_bender " serial_fallback" + append options_bender " serial_fallback" } # @@ -77,7 +81,7 @@ proc run_boot_dir {binaries} { # set fh [create_header_grub2_config] - puts $fh "menuentry 'Genode on seL4' {" + puts $fh "menuentry [grub_menuentry] {" puts $fh " insmod multiboot2" puts $fh " multiboot2 /boot/bender $options_bender" puts $fh " module2 /boot/sel4 sel4 disable_iommu" diff --git a/tool/run/depot.inc b/tool/run/depot.inc index a1ed8974d3..9658a29d93 100644 --- a/tool/run/depot.inc +++ b/tool/run/depot.inc @@ -233,7 +233,10 @@ proc _depot_auto_update { archives } { puts "update depot: $cmd" - exec {*}$cmd >@ stdout 2>@ stderr + if {[catch {exec {*}$cmd >@ stdout 2>@ stderr}]} { + puts stderr "\nError: tool/depot/create during depot-auto-update failed\n" + exit 1 + } } diff --git a/tool/run/image/uboot b/tool/run/image/uboot index 8871bb759e..12f4cfef2d 100644 --- a/tool/run/image/uboot +++ b/tool/run/image/uboot @@ -36,6 +36,7 @@ proc image_uboot_gzip_opt { } { # Build U-boot bootloader specific uImage # proc run_image { } { + set dtc [installed_command dtc] set elf_img [file join [run_dir] boot [kernel_specific_binary image.elf]] @@ -67,8 +68,18 @@ proc run_image { } { if {[image_uboot_use_fit]} { # create image.itb set uboot_img [file join [run_dir] boot image.itb] + + # create dummy dtb for version of u-boot requiring it in the fit image + set fd [open [run_dir]/dummy.dts w] + puts $fd "/dts-v1/;\n / {};" + close $fd + exec $dtc [run_dir]/dummy.dts -o [run_dir]/dummy.dtb + exec mkimage -f auto -A $arch -O linux -T kernel -C $compress_type -a $load_addr \ - -e $entrypoint -d $bin_img$bin_ext $uboot_img + -e $entrypoint -b [run_dir]/dummy.dtb -d $bin_img$bin_ext $uboot_img + + # cleanup dummy files + file delete -force [run_dir]/dummy.dts [run_dir]/dummy.dtb } else { # create uImage set uboot_img [file join [run_dir] boot uImage] diff --git a/tool/run/load.inc b/tool/run/load.inc index 4d540248ed..6f5e196696 100644 --- a/tool/run/load.inc +++ b/tool/run/load.inc @@ -3,5 +3,7 @@ # proc load_spawn_id { } { global load_spawn_id - return $load_spawn_id + if {[info exists load_spawn_id]} { + return $load_spawn_id } + return -1 } diff --git a/tool/run/load/fastboot b/tool/run/load/fastboot index f41d99379a..f47808dfa1 100644 --- a/tool/run/load/fastboot +++ b/tool/run/load/fastboot @@ -34,8 +34,27 @@ proc run_load { } { set device [load_fastboot_device] set uimg [file join [run_dir] boot uImage] - # sleep a bit, board might need some time to come up - sleep 8 + # show boot log up to the life sign of U-boot's fastboot driver + puts stderr "Waiting for U-boot's fastboot driver message" + spawn /bin/sh -c "[log_serial_cmd]" + set timeout 60 + set boot_loader_failed false + expect { + -re {.*musb-hdrc.*\n} { } + eof { + puts stderr "Aborting, boot log received EOF" + set boot_loader_failed true + } + timeout { + puts stderr "Loading of boot loader timed out" + set boot_loader_failed true + } + } + close + if {$boot_loader_failed} { + return false } + + puts stderr "U-boot fastboot driver is up" set fastboot_cmd [list fastboot] if {$device != ""} { @@ -47,14 +66,14 @@ proc run_load { } { set load_spawn_id $spawn_id set timeout 80 expect { - "finished. total time:" { return true; } + {[fF]inished. [tT]otal time:} { return true; } eof { - puts stderr "fastboot command process died unexpectedly"; - return false; + puts stderr "Fastboot command process died unexpectedly" + return false } timeout { - puts stderr "Loading timed out"; - return false; + puts stderr "Loading timed out" + return false } } } diff --git a/tool/run/log/amt b/tool/run/log/amt index f20b015a8d..0f95758051 100644 --- a/tool/run/log/amt +++ b/tool/run/log/amt @@ -44,11 +44,11 @@ proc run_log { wait_for_re timeout_value } { return false } - set amt_tool [get_cmd_arg --amt-tool "wsman"] + set amt_tool [get_cmd_arg --amt-tool "default"] # Check that SOL is correctly configured if wsman is available - if {![log_amt_skip_test]} { - if {[have_installed wsman] && $amt_tool=="wsman" } { + if {![log_amt_skip_test] && ( $amt_tool == "wsman" || $amt_tool == "default" )} { + if {[have_installed wsman]} { puts "Test for working AMT SOL redirection service ..." set redir_state [exec wsman get http://intel.com/wbem/wscim/1/amt-schema/1/AMT_RedirectionService -h [log_amt_host] -P 16992 -u admin -p [log_amt_password]] set redir_state [regexp -inline {ListenerEnabled.*ListenerEnabled} $redir_state] @@ -62,21 +62,6 @@ proc run_log { wait_for_re timeout_value } { } else { puts " Warning: could not check AMT SOL redirection service because of missing wsman tool, --amt-tool==$amt_tool" } - } else { - puts "Skipping test for working AMT SOL redirection service" - } - - # - # password via environment variable for amtterm will not show up in logs - # - set ::env(AMT_PASSWORD) [log_amt_password] - - # - # grab output - # - set amt_cmd "amtterm -u admin -v [log_amt_host]" - if {[get_cmd_switch --log-amt-filter]} { - set amt_cmd "$amt_cmd | [log_amt_filter]" } if {$wait_for_re == "forever"} { @@ -86,7 +71,30 @@ proc run_log { wait_for_re timeout_value } { } set exit_result 1 - lassign [retry 30 "/bin/sh -c \"$amt_cmd\"" ".*session authentication" 0.5] retry_output output_spawn_id + # + # prepare command + # + if {[have_installed meshcmd] && ( $amt_tool == "meshcmd" )} { + set amt_cmd "meshcmd amtterm --host [log_amt_host] --password [log_amt_password]" + set amt_log ".*Connected" + } else { + # + # password via environment variable for amtterm will not show up in logs + # + set ::env(AMT_PASSWORD) [log_amt_password] + + set amt_cmd "amtterm -u admin -v [log_amt_host]" + set amt_log ".*session authentication" + } + + if {[get_cmd_switch --log-amt-filter]} { + set amt_cmd "$amt_cmd | [log_amt_filter]" + } + + # + # grab output + # + lassign [retry 30 "/bin/sh -c \"$amt_cmd\"" "$amt_log" 2] retry_output output_spawn_id if {$retry_output == ""} { puts stderr "Aborting, AMT SOL not accessible" diff --git a/tool/run/log/serial b/tool/run/log/serial index 02baa7ce11..ab60eeabc3 100644 --- a/tool/run/log/serial +++ b/tool/run/log/serial @@ -8,7 +8,7 @@ source [genode_dir]/tool/run/log.inc -set default_serial_cmd "picocom -b 115200 /dev/ttyUSB0" +set default_serial_cmd "picocom --quiet -b 115200 /dev/ttyUSB0" proc log_serial_cmd { } { diff --git a/tool/run/power_on/amt b/tool/run/power_on/amt index c9d9f2ac7c..da31f6e97f 100644 --- a/tool/run/power_on/amt +++ b/tool/run/power_on/amt @@ -102,6 +102,20 @@ proc amt_reset_wsman { } { } +## +# Reset via meshcmd +# Executes a power on or power cycle depending on the current power state +# +proc amt_reset_meshcmd { } { + set power_state [exec meshcmd amtpower --reset --host [power_on_amt_host] --password [power_on_amt_password]] + if { $power_state == "Current power state: Soft off" } { + exec meshcmd amtpower --powercycle --host [power_on_amt_host] --password [power_on_amt_password] + } else { + exec meshcmd amtpower --poweron --host [power_on_amt_host] --password [power_on_amt_password] + } +} + + ## # Reset the test machine using Intel's AMT # @@ -111,7 +125,7 @@ proc run_power_on { } { } # - # amttool and wsman are supported for reset + # amttool, wsman and meshcmd are supported for reset # set amt_tool [get_cmd_arg --amt-tool "default"] @@ -121,14 +135,14 @@ proc run_power_on { } { if {[have_installed wsman] && ( $amt_tool == "wsman" || $amt_tool == "default") } { amt_reset_wsman + } elseif {[have_installed meshcmd] && ( $amt_tool == "meshcmd" )} { + amt_reset_meshcmd + } elseif {[have_installed amttool] && + ( $amt_tool == "amttool" || $amt_tool == "default") } { + amt_reset_soap_eoi } else { - if {[have_installed amttool] && - ($amt_tool == "amttool" || $amt_tool == "default") } { - amt_reset_soap_eoi - } else { - puts stderr "specified tool \"$amt_tool\" for using Intel AMT is unknown or is not installed" - exit -1 - } + puts stderr "specified tool \"$amt_tool\" for using Intel AMT is unknown or is not installed" + exit -1 } puts "wait [power_on_amt_timeout] seconds for power on" diff --git a/tool/sdk/genode-base.pc.in b/tool/sdk/genode-base.pc.in deleted file mode 100644 index 9a19f9981f..0000000000 --- a/tool/sdk/genode-base.pc.in +++ /dev/null @@ -1,15 +0,0 @@ -prefix=!SDK_DIR! -lddir=${prefix}/ld -libdir=${prefix}/lib -toolchaindir=!TOOLCHAIN_DIR! -cc=${toolchaindir}/bin/genode-x86-gcc -cxx=${toolchaindir}/bin/genode-x86-g++ -ld=${toolchaindir}/bin/genode-x86-ld -ar=${toolchaindir}/bin/genode-x86-ar -ranlib=${toolchaindir}/bin/genode-x86-ranlib - -Name: genode-base -Description: Genode base compiler definitions -URL: https://genode.org/ -Version: !VERSION! -Cflags: -nostdinc -fPIC -I${prefix}/include/genode -I${toolchaindir}/lib/gcc/x86_64-pc-elf/6.3.0/include diff --git a/tool/sdk/genode-lib.pc.in b/tool/sdk/genode-lib.pc.in deleted file mode 100644 index 88101b4217..0000000000 --- a/tool/sdk/genode-lib.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=!SDK_DIR! -lddir=${prefix}/ld -libdir=${prefix}/lib -toolchaindir=!TOOLCHAIN_DIR! - -Name: genode-lib -Description: Flags for linking Genode libraries -URL: https://genode.org/ -Version: !VERSION! -Requires: genode-base -Libs: -shared --eh-frame-hdr -melf_x86_64 -gc-sections -z max-page-size=0x1000 -T ${lddir}/genode_rel.ld --entry=0x0 ${libdir}/ldso-startup.lib.a ${toolchaindir}/lib/gcc/x86_64-pc-elf/6.3.0/64/libgcc.a diff --git a/tool/sdk/genode-libc.pc.in b/tool/sdk/genode-libc.pc.in deleted file mode 100644 index cd92710cee..0000000000 --- a/tool/sdk/genode-libc.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=!SDK_DIR! -includedir=${prefix}/include/libc -libdir=${prefix}/lib - -Name: genode-libc -Description: Genode C runtime library -URL: https://genode.org/ -Version: !VERSION! -Requires: genode-base genode-vfs -Cflags: -D__FreeBSD__=8 -D__ISO_C_VISIBLE=1999 -fno-builtin-sin -fno-builtin-cos -fno-builtin-sinf -fno-builtin-cosf -I${includedir} -I${includedir}/libc -I${includedir}/libc/libc -I${includedir}/libc-genode -Libs: ${libdir}/libc.lib.so ${libdir}/libm.lib.so diff --git a/tool/sdk/genode-posix.pc.in b/tool/sdk/genode-posix.pc.in deleted file mode 100644 index 40f7dbcf08..0000000000 --- a/tool/sdk/genode-posix.pc.in +++ /dev/null @@ -1,10 +0,0 @@ -prefix=!SDK_DIR! -includedir=${prefix}/include/libc -libdir=${prefix}/lib - -Name: genode-posix -Description: Genode POSIX entrypoint library -URL: https://genode.org/ -Version: !VERSION! -Requires: genode-libc -Libs: ${libdir}/posix.lib.so diff --git a/tool/sdk/genode-prg.pc b/tool/sdk/genode-prg.pc deleted file mode 100644 index 725e81c499..0000000000 --- a/tool/sdk/genode-prg.pc +++ /dev/null @@ -1,11 +0,0 @@ -prefix=!SDK_DIR! -lddir=${prefix}/ld -libdir=${prefix}/lib -toolchaindir=!TOOLCHAIN_DIR! -ld=${toolchaindir}/bin/genode-x86-ld - -Name: genode-prg -Description: Flags for dynamically-linked Genode programs -URL: https://genode.org/ -Version: !VERSION! -Libs: -melf_x86_64 -gc-sections -z max-page-size=0x1000 --dynamic-list=${lddir}/genode_dyn.dl -nostdlib -Ttext=0x01000000 --dynamic-linker=ld.lib.so --eh-frame-hdr -rpath-link=. -T ${lddir}/genode_dyn.ld ${libdir}/ld.lib.so ${toolchaindir}/lib/gcc/x86_64-pc-elf/6.3.0/64/libgcc.a diff --git a/tool/sdk/genode-prg.pc.in b/tool/sdk/genode-prg.pc.in deleted file mode 100644 index 725e81c499..0000000000 --- a/tool/sdk/genode-prg.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=!SDK_DIR! -lddir=${prefix}/ld -libdir=${prefix}/lib -toolchaindir=!TOOLCHAIN_DIR! -ld=${toolchaindir}/bin/genode-x86-ld - -Name: genode-prg -Description: Flags for dynamically-linked Genode programs -URL: https://genode.org/ -Version: !VERSION! -Libs: -melf_x86_64 -gc-sections -z max-page-size=0x1000 --dynamic-list=${lddir}/genode_dyn.dl -nostdlib -Ttext=0x01000000 --dynamic-linker=ld.lib.so --eh-frame-hdr -rpath-link=. -T ${lddir}/genode_dyn.ld ${libdir}/ld.lib.so ${toolchaindir}/lib/gcc/x86_64-pc-elf/6.3.0/64/libgcc.a diff --git a/tool/sdk/genode-stdcxx.pc.in b/tool/sdk/genode-stdcxx.pc.in deleted file mode 100644 index 9e2c85c62e..0000000000 --- a/tool/sdk/genode-stdcxx.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=!SDK_DIR! -includedir=${prefix}/include/stdcxx/stdcxx -libdir=${prefix}/lib - -Name: genode-stdcxx -Description: Genode Standard C++ library -URL: https://genode.org/ -Version: !VERSION! -Requires: genode-libc -Cflags: -D_GLIBCXX_HAVE_MBSTATE_T -D_GLIBCXX_ATOMIC_BUILTINS_4 -I${includedir} -I${includedir}/std -I${includedir}/c_global -Libs: ${libdir}/stdcxx.lib.so diff --git a/tool/sdk/genode-vfs.pc.in b/tool/sdk/genode-vfs.pc.in deleted file mode 100644 index c29f7caf62..0000000000 --- a/tool/sdk/genode-vfs.pc.in +++ /dev/null @@ -1,9 +0,0 @@ -prefix=!SDK_DIR! -libdir=${prefix}/lib - -Name: genode-vfs -Description: Genode Virtual File-System library -URL: https://genode.org/ -Version: !VERSION! -Requires: genode-base -Libs: ${libdir}/vfs.lib.so