{"id":31288987,"url":"https://github.com/lelegard/arm-cpusysregs","last_synced_at":"2026-01-21T22:27:54.213Z","repository":{"id":129407701,"uuid":"592872331","full_name":"lelegard/arm-cpusysregs","owner":"lelegard","description":"Access Arm64 CPU system registers","archived":false,"fork":false,"pushed_at":"2025-08-25T14:16:15.000Z","size":1585,"stargazers_count":107,"open_issues_count":1,"forks_count":13,"subscribers_count":9,"default_branch":"main","last_synced_at":"2025-09-24T13:05:01.206Z","etag":null,"topics":["arm64","control-flow-integrity","cpu-registers","kernel-driver","kernel-extension","kernel-module","pointer-authentication-codes-arm"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lelegard.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-01-24T18:06:24.000Z","updated_at":"2025-09-23T21:15:40.000Z","dependencies_parsed_at":"2023-07-05T01:47:48.080Z","dependency_job_id":"7e5bc7aa-16a4-4b0b-89cd-547cb8e37d85","html_url":"https://github.com/lelegard/arm-cpusysregs","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/lelegard/arm-cpusysregs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lelegard%2Farm-cpusysregs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lelegard%2Farm-cpusysregs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lelegard%2Farm-cpusysregs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lelegard%2Farm-cpusysregs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lelegard","download_url":"https://codeload.github.com/lelegard/arm-cpusysregs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lelegard%2Farm-cpusysregs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28645548,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-21T21:29:11.980Z","status":"ssl_error","status_checked_at":"2026-01-21T21:24:31.872Z","response_time":86,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["arm64","control-flow-integrity","cpu-registers","kernel-driver","kernel-extension","kernel-module","pointer-authentication-codes-arm"],"created_at":"2025-09-24T13:01:54.384Z","updated_at":"2026-01-21T22:27:49.201Z","avatar_url":"https://github.com/lelegard.png","language":"C++","funding_links":[],"categories":["C++"],"sub_categories":[],"readme":"# Access Arm64 CPU system registers\n\nThe 64-bit Arm architecture (a.k.a. \"arm64\", \"aarch64\") defines a large quantity\nof special system registers. Many of them are inaccessible from userland. When a\nsystem register name ends in `_EL1`, it is accessible only at EL1 (kernel mode).\nSimilarly, system registers in `_EL2` are accessible only in hypervisor mode and\n`_EL3` in monitor mode.\n\nThis educational project provides a way to return the exact content of a few Arm64\nsystem registers to userland through a dedicated loadable kernel module, on Linux,\nmacOS, and Windows. Some application programs are provided to display an analysis\nof the contents of these registers.\n\nMore generally, this project provides some notes, examples, and information on the\nthe Arm64 architecture for developers.\n\n**Contents:**\n\n* [Accessing the system registers](#accessing-the-system-registers)\n* [Build instructions](#build-instructions)\n* [Usage instructions](#usage-instructions)\n* [Focus on Pointer Authentication Code (PAC)](#focus-on-pointer-authentication-code-pac)\n* [List of accessible registers](#list-of-accessible-registers)\n\n## Accessing the system registers\n\nReading and writing system registers is done using the special instructions\n`MRS` and `MSR`, respectively. Each system register has a dedicated exception\nlevel, EL0 to EL3. Trying to access a system register from an outer level\nresults in an \"illegal instruction\" exception.\n\nOn Linux, there is a special feature in the kernel which allows a limited access\nto a few `_EL1` system registers from user mode (EL0). The kernel intercepts the\n`SIGILL` exception which results from the invalid access to a system register\nusing an `MRS` instruction. If the requested system register is one of a few\nselected allowed registers, the kernel reads the system register and returns it\nto the process, as if the `MRS` instruction executed correctly.\n\nThis is [explained in details here](https://www.kernel.org/doc/html/latest/arch/arm64/cpu-feature-registers.html).\nAs a general requirement, no sensitive security information is returned.\nIn some cases, some parts of the register content are blacked out.\n\nThis is a Linux-only feature and it is limited to a few registers, or a subpart of\nthem. This means that we are never really sure of what the physical register was.\n\nThis project provides Linux, macOS, and Windows kernel modules to read and write\nselected system registers from user applications.\n\n**Warning:** This project is for educational purpose only, for people wanting to\nincrease their knowledge in the Arm64 architecture. Loading a custom kernel\nmodule may always have unexpected side effects, including:\n\n- Security effects: the content of the system registers could be used to gain\n  information on the system, including the pointer authentication keys on Linux\n  (they are better protected on macOS).\n- Stability effects:\n  - Accessing Arm system registers is not only a matter of exception level.\n    The Arm architecture reference manual describes in details the pseudo-code\n    to access each register. There are many specific configuration options,\n    usually set by the hypervisor (EL2) or monitor (EL3) which filter or\n    protect access to the register. In specific configurations, depending on\n    the operating system or the platform, accessing a system register from\n    the kernel may either work or crash the system.\n  - Modifying the PACIA key using a kernel which is built with pointer\n    authentication crashes the system since the return pointer of the kernel\n    functions are authenticated with a different key as used by the previous\n    PACIA (believe me, I tried...)\n\nSee the file [docs/references.md](docs/references.md) for a list of reference\ndocumentations on the Arm64 architecture, its system registers and pointer\nauthentication features.\n\n## Build instructions\n\nFor Linux and macOS:\n- `make` : Build the kernel module and the applications.\n- `make install` : Install the kernel module in the system tree.\n- `make load` : Load the kernel module.\n- `make unload` : Unload the kernel module.\n- `make show` : Show the loaded kernel module.\n\nFor Windows, see the directory [msbuild](msbuild).\n\nSee also more details in the README files of the [apps](apps) and [kernel](kernel)\nsubdirectories.\n\n##  Usage instructions\n\nThe C++ application `sysregs` is a generic tool to read and write the system registers.\nWith option `-v` (verbose), most system registers are structured using bit-fields of various\nsizes and interpretation.\n~~~\nSyntax: sysregs [options]\n\n  -r name       : read the content of the named register\n  -w name value : write the specified hexadecimal value in the named register\n  -d name value : display the specified value in the named register format\n\n  -a : read all supported Arm64 system registers\n  -b : display register value in binary (default: hex)\n  -f : force read/write register, even if not supposed to (risk of system crash)\n  -h : display this help text\n  -l : list the names of all supported Arm64 system registers\n  -p : summary of supported PAC features\n  -s : summary of CPU features\n  -S : same as -s but read registers at EL0 (maybe partial, may fail)\n  -v : verbose, display register analysis and fields\n~~~\n\nSee more details in:\n\n- The [apps](apps) subdirectory for other command line tools.\n- The [kernel](kernel) subdirectory for programming guidelines.\n\n## Focus on Pointer Authentication Code (PAC)\n\nOne of the motivations for this project was a better understanding of the\nPointer Authentication Code (PAC) feature, as introduced in the Armv8.3-A\narchitecture. PAC is one of the clever \"defensive security\" features which\nwere designed by Arm (the other one is BTI, the Branch Target Indentification\nin Armv8.5-A).\n\nUnderstanding PAC is harder than it may seem. There are many configuration\noptions which depend on the operating system or the platform. Predicting the\nsize, position and value of a PAC is not trivial. We need to read several\nmemory management system registers and correctly interpret the complex Arm\npseudo-code (or emulate it as done in this project). The command `sysregs -p`\nsummarizes this.\n\nThere are several documents in the [docs](docs) subdirectory containing the\nsummary of observations about the PAC on different platforms. The subdirectory\n[collect](collect) contains informations which were collected on these\nplatforms, Linux, macOS, Windows, using various Arm64-based processor chips\nimplementing Armv8.3-A or higher versions of the architecture.\n\nSpecifically, this project was the main tool to support the writing of the white paper\n\"[Control Flow Integrity, anti-malware active protection on Arm64 systems](https://sipearl.com/wp-content/uploads/2023/10/SiPearl-WP-CFI-on-Arm64.pdf)\"\nfrom [SiPearl](https://sipearl.com/).\n\n\n## List of accessible registers\n\nThe reference list of registers which can be accessed by this project is given by\nthe list of `CSR_REG_xxx` and `CSR_REG2_xxx` constants in file\n[kernel/cpusysregs.h](kernel/cpusysregs.h).\n\nSome _EL0 registers can be protected by the kernel using _EL1 control registers.\nReading these _EL0 registers in user mode raises an illegal instruction exception.\nIn that case, they can be accessed from kernel mode using the kernel module.\n\n| Register         | Access  | Description\n| ---------------- | ------- | -----------\n| APDAKey_EL1      | R/W [1] | Pointer Authentication Key A for Data (Hi/Lo pair)\n| APDBKey_EL1      | R/W [1] | Pointer Authentication Key B for Data (Hi/Lo pair)\n| APGAKey_EL1      | R/W [1] | Pointer Authentication Generic Key (Hi/Lo pair)\n| APIAKey_EL1      | R/W [1] | Pointer Authentication Key A for Instructions (Hi/Lo pair)\n| APIBKey_EL1      | R/W [1] | Pointer Authentication Key B for Instructions (Hi/Lo pair)\n| CNTFRQ_EL0       | R       | Counter-timer Frequency register\n| CNTKCTL_EL1      | R/W     | Counter-timer Kernel Control register\n| CNTPCT_EL0       | R       | Counter-timer Physical Count register\n| CNTPS_CTL_EL1    | R/W     | Counter-timer Physical Secure Timer Control register\n| CNTVCT_EL0       | R       | Counter-timer Virtual Count register\n| CTR_EL0          | R   [5] | Cache Type Register\n| HCR_EL2          | R   [2] | Hypervisor Configuration Register\n| ID_AA64AFR0_EL1  | R       | AArch64 Auxiliary Feature Register 0\n| ID_AA64AFR1_EL1  | R       | AArch64 Auxiliary Feature Register 1\n| ID_AA64DFR0_EL1  | R       | AArch64 Debug Feature Register 0\n| ID_AA64DFR1_EL1  | R       | AArch64 Debug Feature Register 1\n| ID_AA64DFR2_EL1  | R       | AArch64 Debug Feature Register 2\n| ID_AA64FPFR0_EL1 | R       | AArch64 Floating-point Feature Register 0\n| ID_AA64ISAR0_EL1 | R       | AArch64 Instruction Set Attribute Register 0\n| ID_AA64ISAR1_EL1 | R       | AArch64 Instruction Set Attribute Register 1\n| ID_AA64ISAR2_EL1 | R       | AArch64 Instruction Set Attribute Register 2\n| ID_AA64ISAR3_EL1 | R       | AArch64 Instruction Set Attribute Register 3\n| ID_AA64MMFR0_EL1 | R       | AArch64 Memory Model Feature Register 0\n| ID_AA64MMFR1_EL1 | R       | AArch64 Memory Model Feature Register 1\n| ID_AA64MMFR2_EL1 | R       | AArch64 Memory Model Feature Register 2\n| ID_AA64MMFR3_EL1 | R       | AArch64 Memory Model Feature Register 3\n| ID_AA64MMFR4_EL1 | R       | AArch64 Memory Model Feature Register 4\n| ID_AA64PFR0_EL1  | R       | AArch64 Processor Feature Register 0\n| ID_AA64PFR1_EL1  | R       | AArch64 Processor Feature Register 1\n| ID_AA64PFR2_EL1  | R       | AArch64 Processor Feature Register 2\n| ID_AA64SMFR0_EL1 | R       | SME Feature ID register 0\n| ID_AA64ZFR0_EL1  | R       | SVE Feature ID register 0\n| ID_ISAR0_EL1     | R       | AArch32 Instruction Set Attribute Register 0\n| ID_ISAR1_EL1     | R       | AArch32 Instruction Set Attribute Register 1\n| ID_ISAR2_EL1     | R       | AArch32 Instruction Set Attribute Register 2\n| ID_ISAR3_EL1     | R       | AArch32 Instruction Set Attribute Register 3\n| ID_ISAR4_EL1     | R       | AArch32 Instruction Set Attribute Register 4\n| ID_ISAR5_EL1     | R       | AArch32 Instruction Set Attribute Register 5\n| ID_ISAR6_EL1     | R       | AArch32 Instruction Set Attribute Register 6\n| ID_MMFR0_EL1     | R       | AArch32 Memory Model Feature Register 0\n| ID_MMFR1_EL1     | R       | AArch32 Memory Model Feature Register 1\n| ID_MMFR2_EL1     | R       | AArch32 Memory Model Feature Register 2\n| ID_MMFR3_EL1     | R       | AArch32 Memory Model Feature Register 3\n| ID_MMFR4_EL1     | R       | AArch32 Memory Model Feature Register 4\n| ID_MMFR5_EL1     | R       | AArch32 Memory Model Feature Register 5\n| ID_PFR0_EL1      | R       | AArch32 Processor Feature Register 0\n| ID_PFR1_EL1      | R       | AArch32 Processor Feature Register 1\n| ID_PFR2_EL1      | R       | AArch32 Processor Feature Register 2\n| MAIR_EL1         | R       | Memory Attribute Indirection Register (EL1)\n| MAIR2_EL1        | R       | Extended Memory Attribute Indirection Register (EL1)\n| MIDR_EL1         | R       | Main ID Register\n| MPAMIDR_EL1      | R       | MPAM ID Register (EL1)\n| MPIDR_EL1        | R       | Multiprocessor Affinity Register\n| PIR_EL1          | R       | Permission Indirection Register 1 (EL1)\n| PIRE0_EL1        | R       | Permission Indirection Register 0 (EL1)\n| PMCCFILTR_EL0    | R       | Performance Monitors Cycle Count Filter Register\n| PMCCNTR_EL0      | R       | Performance Monitors Cycle Count Register\n| PMCR_EL0         | R       | Performance Monitors Control Register\n| PMMIR_EL1        | R       | Performance Monitors Machine Identification Register\n| PMSIDR_EL1       | R   [4] | Sampling Profiling ID Register\n| PMUSERENR_EL0    | R       | Performance Monitors User Enable Register\n| REVIDR_EL1       | R       | Revision ID Register\n| RNDR             | R       | Random Number\n| RNDRRS           | R       | Reseeded Random Number\n| SCR_EL3          |     [3] | Secure Configuration Register (EL3)\n| SCTLR_EL1        | R/W     | System Control Register (EL1)\n| SCTLR2_EL1       | R/W     | System Control Register 2 (EL1)\n| SCXTNUM_EL0      | R/W     | EL0 Read/Write Software Context Number\n| SCXTNUM_EL1      | R/W     | EL1 Read/Write Software Context Number\n| TCR_EL1          | R       | Translation Control Register (EL1)\n| TCR2_EL1         | R       | Extended Translation Control Register (EL1)\n| TPIDR_EL0        | R/W [5] | EL0 Read/Write Software Thread ID Register\n| TPIDR_EL1        | R/W [5] | EL1 Software Thread ID Register\n| TPIDRRO_EL0      | R/W [5] | EL0 Read-Only Software Thread ID Register\n| TRBIDR_EL1       | R       | Trace Buffer ID Register\n| TRCDEVARCH       | R       | Trace Device Architecture Register\n| TTBR0_EL1        | R       | Translation Table Base Register 0 (EL1)\n| TTBR1_EL1        | R       | Translation Table Base Register 1 (EL1)\n\n[1] The Pointer Authentication Key registers are usually readable and writeable at EL1 (kernel).\nThis is the case on Linux. On macOS, however, in the default configuration, the PAC key registers\ncan be accessed at EL3 only. This is explained in file [docs/arm64e-on-macos.md](docs/arm64e-on-macos.md).\nAccessing the PAC key registers at EL1 crashes macOS.\n\n[2] HCR_EL2 is readable at EL1 on macOS. Access not allowed in a Linux VM and crashes the system.\n\n[3] SCR_EL3 cannot by read/write at EL1. It is supported to format its possible values only.\n\n[4] PMSIDR_EL1 cannot be read on Linux at EL1, even when FEAT_SPE is implemented.\n\n[5] These registers cannot be accessed on Windows. Reading or writing them crashes the system.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flelegard%2Farm-cpusysregs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flelegard%2Farm-cpusysregs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flelegard%2Farm-cpusysregs/lists"}