{"id":25396980,"url":"https://github.com/ashwio/arm64-sysreg-lib","last_synced_at":"2025-10-30T21:30:16.734Z","repository":{"id":52515857,"uuid":"282265893","full_name":"ashwio/arm64-sysreg-lib","owner":"ashwio","description":"Header-only C library for reading/writing 64-bit Arm registers, automatically generated by parsing the AArch64 System Register XML.","archived":false,"fork":false,"pushed_at":"2021-04-26T21:10:50.000Z","size":170,"stargazers_count":30,"open_issues_count":0,"forks_count":8,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-15T05:09:24.174Z","etag":null,"topics":["aarch64","aarch64v8","arm","arm64","arm64-v8a","arm64v8","armv8","armv8-a","armv8-assembly","armv8a","assembly","assembly-language","assembly-language-programming","c","library"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ashwio.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-07-24T16:18:36.000Z","updated_at":"2025-02-11T06:02:41.000Z","dependencies_parsed_at":"2022-08-31T14:20:45.478Z","dependency_job_id":null,"html_url":"https://github.com/ashwio/arm64-sysreg-lib","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ashwio%2Farm64-sysreg-lib","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ashwio%2Farm64-sysreg-lib/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ashwio%2Farm64-sysreg-lib/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ashwio%2Farm64-sysreg-lib/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ashwio","download_url":"https://codeload.github.com/ashwio/arm64-sysreg-lib/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239058167,"owners_count":19574746,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aarch64","aarch64v8","arm","arm64","arm64-v8a","arm64v8","armv8","armv8-a","armv8-assembly","armv8a","assembly","assembly-language","assembly-language-programming","c","library"],"created_at":"2025-02-15T21:26:56.049Z","updated_at":"2025-10-30T21:30:16.096Z","avatar_url":"https://github.com/ashwio.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Arm64 System Register Library\n\n- [Introduction](#introduction)\n- [Prerequisites](#prerequisites)\n- [High-level functionality](#high-level-functionality)\n  - [Bit structs](#bit-structs)\n  - [Safe values](#safe-values)\n  - [Reads](#reads)\n  - [Writes](#writes)\n    - [Unsafe write](#unsafe-write)\n    - [Safe write](#safe-write)\n  - [Read-modify-write](#read-modify-write)\n- [Building and testing the library](#building-and-testing-the-library)\n  - [Step 1) Obtain AArch64 System Register XML](#step-1-obtain-aarch64-system-register-xml)\n  - [Step 2) Build](#step-2-build)\n  - [Step 3) Test](#step-3-test)\n- [Known issues and limitations](#known-issues-and-limitations)\n  \n\n## Introduction\n`arm64-sysreg-lib` is a header-only C library for reading/writing 64-bit Arm\nregisters, automatically generated by parsing the AArch64 System Register XML.\n\nKey features:\n- Bit structs defined for 263 system registers\n- 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`\n- Accessors for read, unsafe write, safe write, and read-modify-write sequences defined according to register accessibility\n- 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\n- Support for both `gcc` and `clang`, each with `-Wall -Wextra -pedantic -Werror` flags and supporting both `-std=c99` and `-std=c11`\n\n\n## Prerequisites\n\nTo build the library:\n- Python 3.8+\n- Beautiful Soup 4 (`pip3.8 install beautifulsoup4`)\n\nTo use the library in your own projects:\n- C compiler supporting at least C99 with C11 extensions\n\nKnown working compilers:\n* aarch64-none-elf-gcc (GCC) 7.2.0:\n  - C99: `-Wall -Wextra -pedantic -Werror -std=c99 -O2`\n  - C11: `-Wall -Wextra -pedantic -Werror -std=c11 -O2`\n\n* Apple clang version 11.0.3 (clang-1103.0.32.62): *\n  - C99: `-Wall -Wextra -pedantic -Werror -std=c99 -O2 --target=aarch64-none-elf`\n  - C11: `-Wall -Wextra -pedantic -Werror -std=c11 -O2 --target=aarch64-none-elf`\n\n\\* Apple Clang also tested with `--target=aarch64-linux-gnu`.\n\n\n## High-level functionality\n\n### Bit structs\nAvailability: All system registers.\n\nAll parsed system registers define a `union` of the form:\n\n    union sctlr_el1\n    {\n        u64 _;\n        struct\n        {\n            u64 m : 1;\n            u64 a : 1;\n            u64 c : 1;\n            u64 sa : 1;\n            ...\n        };\n    };\n\nThe `._` member allows for raw access to the underlying register value while the\nanonymous `struct` member allows for manipulation of the register's constituent\nbit fields.\n\n\n### Safe values\nAvailability: All writeable system registers.\n\nThe safe value for a writeable system register has all currently or previously\n`RES1` fields set to `1` and all currently or previously `RES0` fields cleared\nto `0`. These values are used by the `safe_write_\u003creg\u003e()` convenience macros,\nor you can use them yourself when manually constructing a value to write into\na register using `unsafe_write_\u003creg\u003e()`.\n\nExample:\n\n    static const union sctlr_el3 SCTLR_EL3_SAFEVAL =\n    {\n        .res1_5_4 = 3,\n        .eos = 1,\n        .res1_16 = 1,\n        .res1_18 = 1,\n        .eis = 1,\n        .res1_23 = 1,\n        .res1_29_28 = 3,\n    };\n\nSome of these fields are currently `RES1` bits, such as `.res1_5_4` for bits\n\\[5:4\\] and `.res1_16` for bit \\[16\\]. Setting these to `1` in the safe value\nensures portability when running on future CPU implementations where those bits\nhave been repurposed into new fields, as in these cases a value of `1` will give\nthe old behaviour while a value of `0` will give the new behaviour, and we\ndon't want to inadvertently enable the new behaviour by clearing them.\n\nThis is why the `.eos` and `.eis` fields are also set to `1`; these fields were\npreviosuly `RES1` bits but were repurposed into new fields in later revisions\nof the architecture. The user can choose to clear these to `0` explicitly if\nthey want the new behaviour, but the library defaults to setting them to `1` in\nthe safe value and, by extension, the `safe_write_\u003creg\u003e()` convenience macro.\n\n\n### Reads\nAvailability: All readable system registers.\n\nRead the current value of a system register into a field-accessible structure:\n\n    /* C code */\n    #include \"sysreg/mpidr_el1.h\"\n    u64 foo( void )\n    {\n        return read_mpidr_el1().aff0;\n    }\n\n    /* Compiler output */\n    mrs     x8, mpidr_el1\n    and     x0, x8, #0xff\n    ret\n\n\n### Writes\n\n#### Unsafe write\nAvailability: All writeable system registers.\n\nWrite a field-accessible structure into a system register. This function is\nprefixed `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\nthis function it is the responsibility of the programmer to ensure that any such\nbits are set appropriately so as to ensure both correct behaviour and future portability. For this reason, it is recommended that you instead use\n`safe_write_\u003creg\u003e()` wherever possible, or use `\u003cREG\u003e_SAFEVAL` as a basis for\nthe value being constructed.\n\n    /* C code */\n    #include \"sysreg/sctlr_el1.h\"\n    void foo( void )\n    {\n        union sctlr_el1 val = { .m=1, .c=1, .i=1 };\n        unsafe_write_sctlr_el1(val);\n    }\n\n    /* Compiler output */\n    mov     w8, #0x1005         // Danger! No RES1 bits set! See safe_write_\u003creg\u003e()\n    msr     sctlr_el1, x8\n    ret\n\nUse the `union`'s `._` member to write a raw value:\n\n    /* C code */\n    #include \"sysreg/sctlr_el1.h\"\n    void foo( u64 raw )\n    {\n        union sctlr_el1 val = { ._=raw };\n        unsafe_write_sctlr_el1(val);\n    }\n\n    /* Compiler output */\n    msr     sctlr_el1, x0\n    ret\n\n\n#### Safe write\nAvailability: All writeable system registers.\n\nUse `safe_write_\u003creg\u003e()` to set a variadic list of fields. Any fields not\nspecified in the variadic list that are currently or previously `RES1` will be\nset to `1`, and all other fields will be cleared to `0`.\n\nFor example:\n\n    /* C code */\n    #include \"sysreg/sctlr_el1.h\"\n    void foo( void )\n    {\n        safe_write_sctlr_el1( .m=1, .c=1, .i=1 );\n    }\n\n    /* compiler output */\n    mov     w8, #0x1985\n    movk    w8, #0x30d0, lsl #16\n    msr     sctlr_el1, x8\n    ret\n\nNote how while we only specified `.m=1`, `.c=1`, and `.i=1`, the value written\nto `SCTLR_EL1` also has all currently or previously `RES1` fields set to `1`,\nsuch as `.itd=1`, `.sed=1`, `.eos=1`, etc.\n\nRepeating the same, but this time explicitly clearing one of those currently or previously `RES1` fields to `0` in the variadic list:\n\n    /* in C */\n    #include \"sysreg/sctlr_el1.h\"\n    void foo( void )\n    {\n        safe_write_sctlr_el1( .m=1, .c=1, .i=1, .itd=0 );\n    }\n\n    /* compiler output */\n    mov     w8, #0x1905\n    movk    w8, #0x30d0, lsl #16\n    msr     sctlr_el1, x8\n    ret\n\nHere we can see bit \\[7\\] corresponding to `.itd` in the first `MOV` has been\ncleared; the value moved into `w8` is now `0x1905` vs `0x1985` in the earlier\nexample.\n\n\n### Read-modify-write\nAvailability: All system registers that are both readable and writeable.\n\nUse `read_modify_write_\u003creg\u003e()` to read the current value of a system register,\nset a variadic list of fields in that value, then write the result back.\n\n    /* in C */\n    void foo( void )\n    {\n        read_modify_write_sctlr_el1( .m=1, .c=1, .i=1 );\n    }\n\n    /* compiler output */\n    mrs     x8, sctlr_el1\n    mov     w9, #0x1005\n    orr     x8, x8, x9\n    msr     sctlr_el1, x8\n    ret\n\nNOTE: Many AArch64 system registers have architecturally UNKNOWN values at\nreset, meaning you should *not* perform a read-modify-write sequence when first\ninitializing them. Instead, use `safe_write_\u003creg\u003e()` to guarantee that all\ncurrently or previously `RES1` fields are set to `1` and all other unspecified\nfields are cleared to `0`.\n\n\n## Building and testing the library\n\nNOTE: The library has already been built for you using the June 2020 release of\nthe AArch64 System Register XML (SysReg_xml_v86A-2020-06). You can simply add\n`-I/path/to/arm64-sysreg-lib/include` to your compiler flags to begin using the\nlibrary in your own projects straight away. You can also run the `run-tests.py`\nscript to build the compilation tests using your chosen compiler. More detailed\ninstructions for running the compilation tests can be found at the end of this\ndocument.\n \n\n### Step 1) Obtain AArch64 System Register XML\n\nDownload and extract the AArch64 System Register XML from the\n[Arm A-Profile CPU architecture exploration tools page](https://developer.arm.com/architectures/cpu-architecture/a-profile/exploration-tools).\n\nAlternatively, use `curl` to download the Armv8.6-A XML published in June 2020:\n\n    curl -O https://developer.arm.com/-/media/developer/products/architecture/armv8-a-architecture/2020-06/SysReg_xml_v86A-2020-06.tar.gz\n    tar xf SysReg_xml_v86A-2020-06.tar.gz\n\n### Step 2) Build\n\nRun the provided `run-build.py` script, pointing it at the AArch64 System Register\nXML downloaded and extracted earlier:\n\n    python3.8 run-build.py /path/to/SysReg_xml_v86A-2020-06\n\n### Step 3) Test\n\nRun the provided `run-tests.py` script, pointing it at your chosen compiler:\n\n    python3.8 run-tests.py [--keep] COMPILER_PATH [COMPILER_FLAGS]\n\nFor example:\n\n    python3.8 run-tests.py /path/to/aarch64-none-elf-gcc \n\nIt is assumed the compiler uses the same switches as `gcc` and `clang`, and the\nscript always invokes the compiler with the following flags:\n\n    -Wall -Wextra -pedantic -Werror\n\nYou may pass additional flags to the `run-tests.py` script which will be passed\nin turn to the compiler, for example:\n\n    python3.8 run-tests.py /path/to/aarch64-none-elf-gcc -std=c99 -O3  \n\nIf no `-std` flag is provided, the script defaults to `-std=c11`.\n\nIf no `-O` flag is provided, the script defaults to `-O2`.\n\nIf the compiler path contains substring `clang` and no `--target` flag is provided,\nthe script defaults to `--target=aarch64-none-elf`.\n\nBy default the script will cleanup the generated `.o` object files after finishing\nthe test run; pass the `--keep` flag before the compiler path if you wish to keep\nthese files.\n\n## Known issues and limitations\n\nThis library is still in development and is not yet able to parse all files\nincluded in the AArch64 System Register XML.\n\nOf the 485 `AArch64-*` files included in the `SysReg_xml_v86A-2020-06` release\nthat actually describe system register encodings:\n- 126 are skipped as they correspond to instructions that use the system register\n  encoding space (`ic`, `dc`, `tlbi`, `at`, `cfp`, `cpp`, and `dvp`)\n- 263 successfully build\n- 96 fail to parse\n\nOf the 96 that fail to parse:\n- 43 fail as their fields vary, such a when a bit in another register is set to `1`\n- 19 fail due to being an arrayed register (`\u003cn\u003e`)\n- 23 fail due to having arrayed fields (`\u003cm\u003e`, `\u003cn\u003e`, or `\u003cx\u003e`)\n- 11 fail due to having variable length fields\n\nSupport for these registers will be added in a future release.\n\nNot counted above are external system registers such as `GICD_*` and `GICR_*`,\nsupport for which will also be added later.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fashwio%2Farm64-sysreg-lib","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fashwio%2Farm64-sysreg-lib","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fashwio%2Farm64-sysreg-lib/lists"}