Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/ashwio/arm64-sysreg-lib
Header-only C library for reading/writing 64-bit Arm registers, automatically generated by parsing the AArch64 System Register XML.
https://github.com/ashwio/arm64-sysreg-lib
aarch64 aarch64v8 arm arm64 arm64-v8a arm64v8 armv8 armv8-a armv8-assembly armv8a assembly assembly-language assembly-language-programming c library
Last synced: 3 days ago
JSON representation
Header-only C library for reading/writing 64-bit Arm registers, automatically generated by parsing the AArch64 System Register XML.
- Host: GitHub
- URL: https://github.com/ashwio/arm64-sysreg-lib
- Owner: ashwio
- License: mit
- Created: 2020-07-24T16:18:36.000Z (over 4 years ago)
- Default Branch: master
- Last Pushed: 2021-04-26T21:10:50.000Z (almost 4 years ago)
- Last Synced: 2025-02-15T05:09:24.174Z (4 days ago)
- Topics: aarch64, aarch64v8, arm, arm64, arm64-v8a, arm64v8, armv8, armv8-a, armv8-assembly, armv8a, assembly, assembly-language, assembly-language-programming, c, library
- Language: C
- Homepage:
- Size: 166 KB
- Stars: 30
- Watchers: 2
- Forks: 8
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Arm64 System Register Library
- [Introduction](#introduction)
- [Prerequisites](#prerequisites)
- [High-level functionality](#high-level-functionality)
- [Bit structs](#bit-structs)
- [Safe values](#safe-values)
- [Reads](#reads)
- [Writes](#writes)
- [Unsafe write](#unsafe-write)
- [Safe write](#safe-write)
- [Read-modify-write](#read-modify-write)
- [Building and testing the library](#building-and-testing-the-library)
- [Step 1) Obtain AArch64 System Register XML](#step-1-obtain-aarch64-system-register-xml)
- [Step 2) Build](#step-2-build)
- [Step 3) Test](#step-3-test)
- [Known issues and limitations](#known-issues-and-limitations)
## Introduction
`arm64-sysreg-lib` is a header-only C library for reading/writing 64-bit Arm
registers, automatically generated by parsing the AArch64 System Register XML.Key features:
- Bit structs defined for 263 system registers
- Safe values defined for all writeable registers, with all currently/previously `RES1` bits set to `1` and all currently/previously `RES0` bits cleared to `0`
- Accessors for read, unsafe write, safe write, and read-modify-write sequences defined according to register accessibility
- All library calls optimise down to an average of between one and four A64 assembly instructions and are inlined with no branches and no static storage
- Support for both `gcc` and `clang`, each with `-Wall -Wextra -pedantic -Werror` flags and supporting both `-std=c99` and `-std=c11`## Prerequisites
To build the library:
- Python 3.8+
- Beautiful Soup 4 (`pip3.8 install beautifulsoup4`)To use the library in your own projects:
- C compiler supporting at least C99 with C11 extensionsKnown working compilers:
* aarch64-none-elf-gcc (GCC) 7.2.0:
- C99: `-Wall -Wextra -pedantic -Werror -std=c99 -O2`
- C11: `-Wall -Wextra -pedantic -Werror -std=c11 -O2`* Apple clang version 11.0.3 (clang-1103.0.32.62): *
- C99: `-Wall -Wextra -pedantic -Werror -std=c99 -O2 --target=aarch64-none-elf`
- C11: `-Wall -Wextra -pedantic -Werror -std=c11 -O2 --target=aarch64-none-elf`\* Apple Clang also tested with `--target=aarch64-linux-gnu`.
## High-level functionality
### Bit structs
Availability: All system registers.All parsed system registers define a `union` of the form:
union sctlr_el1
{
u64 _;
struct
{
u64 m : 1;
u64 a : 1;
u64 c : 1;
u64 sa : 1;
...
};
};The `._` member allows for raw access to the underlying register value while the
anonymous `struct` member allows for manipulation of the register's constituent
bit fields.### Safe values
Availability: All writeable system registers.The safe value for a writeable system register has all currently or previously
`RES1` fields set to `1` and all currently or previously `RES0` fields cleared
to `0`. These values are used by the `safe_write_()` convenience macros,
or you can use them yourself when manually constructing a value to write into
a register using `unsafe_write_()`.Example:
static const union sctlr_el3 SCTLR_EL3_SAFEVAL =
{
.res1_5_4 = 3,
.eos = 1,
.res1_16 = 1,
.res1_18 = 1,
.eis = 1,
.res1_23 = 1,
.res1_29_28 = 3,
};Some of these fields are currently `RES1` bits, such as `.res1_5_4` for bits
\[5:4\] and `.res1_16` for bit \[16\]. Setting these to `1` in the safe value
ensures portability when running on future CPU implementations where those bits
have been repurposed into new fields, as in these cases a value of `1` will give
the old behaviour while a value of `0` will give the new behaviour, and we
don't want to inadvertently enable the new behaviour by clearing them.This is why the `.eos` and `.eis` fields are also set to `1`; these fields were
previosuly `RES1` bits but were repurposed into new fields in later revisions
of the architecture. The user can choose to clear these to `0` explicitly if
they want the new behaviour, but the library defaults to setting them to `1` in
the safe value and, by extension, the `safe_write_()` convenience macro.### Reads
Availability: All readable system registers.Read the current value of a system register into a field-accessible structure:
/* C code */
#include "sysreg/mpidr_el1.h"
u64 foo( void )
{
return read_mpidr_el1().aff0;
}/* Compiler output */
mrs x8, mpidr_el1
and x0, x8, #0xff
ret### Writes
#### Unsafe write
Availability: All writeable system registers.Write a field-accessible structure into a system register. This function is
prefixed `unsafe_` to emphasise the fact that it has no provision for helping to ensure that any currently or previously `RES1` fields are set to `1`; when using
this function it is the responsibility of the programmer to ensure that any such
bits are set appropriately so as to ensure both correct behaviour and future portability. For this reason, it is recommended that you instead use
`safe_write_()` wherever possible, or use `_SAFEVAL` as a basis for
the value being constructed./* C code */
#include "sysreg/sctlr_el1.h"
void foo( void )
{
union sctlr_el1 val = { .m=1, .c=1, .i=1 };
unsafe_write_sctlr_el1(val);
}/* Compiler output */
mov w8, #0x1005 // Danger! No RES1 bits set! See safe_write_()
msr sctlr_el1, x8
retUse the `union`'s `._` member to write a raw value:
/* C code */
#include "sysreg/sctlr_el1.h"
void foo( u64 raw )
{
union sctlr_el1 val = { ._=raw };
unsafe_write_sctlr_el1(val);
}/* Compiler output */
msr sctlr_el1, x0
ret#### Safe write
Availability: All writeable system registers.Use `safe_write_()` to set a variadic list of fields. Any fields not
specified in the variadic list that are currently or previously `RES1` will be
set to `1`, and all other fields will be cleared to `0`.For example:
/* C code */
#include "sysreg/sctlr_el1.h"
void foo( void )
{
safe_write_sctlr_el1( .m=1, .c=1, .i=1 );
}/* compiler output */
mov w8, #0x1985
movk w8, #0x30d0, lsl #16
msr sctlr_el1, x8
retNote how while we only specified `.m=1`, `.c=1`, and `.i=1`, the value written
to `SCTLR_EL1` also has all currently or previously `RES1` fields set to `1`,
such as `.itd=1`, `.sed=1`, `.eos=1`, etc.Repeating the same, but this time explicitly clearing one of those currently or previously `RES1` fields to `0` in the variadic list:
/* in C */
#include "sysreg/sctlr_el1.h"
void foo( void )
{
safe_write_sctlr_el1( .m=1, .c=1, .i=1, .itd=0 );
}/* compiler output */
mov w8, #0x1905
movk w8, #0x30d0, lsl #16
msr sctlr_el1, x8
retHere we can see bit \[7\] corresponding to `.itd` in the first `MOV` has been
cleared; the value moved into `w8` is now `0x1905` vs `0x1985` in the earlier
example.### Read-modify-write
Availability: All system registers that are both readable and writeable.Use `read_modify_write_()` to read the current value of a system register,
set a variadic list of fields in that value, then write the result back./* in C */
void foo( void )
{
read_modify_write_sctlr_el1( .m=1, .c=1, .i=1 );
}/* compiler output */
mrs x8, sctlr_el1
mov w9, #0x1005
orr x8, x8, x9
msr sctlr_el1, x8
retNOTE: Many AArch64 system registers have architecturally UNKNOWN values at
reset, meaning you should *not* perform a read-modify-write sequence when first
initializing them. Instead, use `safe_write_()` to guarantee that all
currently or previously `RES1` fields are set to `1` and all other unspecified
fields are cleared to `0`.## Building and testing the library
NOTE: The library has already been built for you using the June 2020 release of
the AArch64 System Register XML (SysReg_xml_v86A-2020-06). You can simply add
`-I/path/to/arm64-sysreg-lib/include` to your compiler flags to begin using the
library in your own projects straight away. You can also run the `run-tests.py`
script to build the compilation tests using your chosen compiler. More detailed
instructions for running the compilation tests can be found at the end of this
document.
### Step 1) Obtain AArch64 System Register XML
Download and extract the AArch64 System Register XML from the
[Arm A-Profile CPU architecture exploration tools page](https://developer.arm.com/architectures/cpu-architecture/a-profile/exploration-tools).Alternatively, use `curl` to download the Armv8.6-A XML published in June 2020:
curl -O https://developer.arm.com/-/media/developer/products/architecture/armv8-a-architecture/2020-06/SysReg_xml_v86A-2020-06.tar.gz
tar xf SysReg_xml_v86A-2020-06.tar.gz### Step 2) Build
Run the provided `run-build.py` script, pointing it at the AArch64 System Register
XML downloaded and extracted earlier:python3.8 run-build.py /path/to/SysReg_xml_v86A-2020-06
### Step 3) Test
Run the provided `run-tests.py` script, pointing it at your chosen compiler:
python3.8 run-tests.py [--keep] COMPILER_PATH [COMPILER_FLAGS]
For example:
python3.8 run-tests.py /path/to/aarch64-none-elf-gcc
It is assumed the compiler uses the same switches as `gcc` and `clang`, and the
script always invokes the compiler with the following flags:-Wall -Wextra -pedantic -Werror
You may pass additional flags to the `run-tests.py` script which will be passed
in turn to the compiler, for example:python3.8 run-tests.py /path/to/aarch64-none-elf-gcc -std=c99 -O3
If no `-std` flag is provided, the script defaults to `-std=c11`.
If no `-O` flag is provided, the script defaults to `-O2`.
If the compiler path contains substring `clang` and no `--target` flag is provided,
the script defaults to `--target=aarch64-none-elf`.By default the script will cleanup the generated `.o` object files after finishing
the test run; pass the `--keep` flag before the compiler path if you wish to keep
these files.## Known issues and limitations
This library is still in development and is not yet able to parse all files
included in the AArch64 System Register XML.Of the 485 `AArch64-*` files included in the `SysReg_xml_v86A-2020-06` release
that actually describe system register encodings:
- 126 are skipped as they correspond to instructions that use the system register
encoding space (`ic`, `dc`, `tlbi`, `at`, `cfp`, `cpp`, and `dvp`)
- 263 successfully build
- 96 fail to parseOf the 96 that fail to parse:
- 43 fail as their fields vary, such a when a bit in another register is set to `1`
- 19 fail due to being an arrayed register (``)
- 23 fail due to having arrayed fields (``, ``, or ``)
- 11 fail due to having variable length fieldsSupport for these registers will be added in a future release.
Not counted above are external system registers such as `GICD_*` and `GICR_*`,
support for which will also be added later.