serenity/Kernel/Arch/aarch64/Registers.h
Daniel Bertalan bd93b4984b Kernel/aarch64: Use unsigned values in the register bitfields
This resolves the various "implicit truncation from int to a one-bit
wide bit-field changes value from 1 to -1" warnings produced by Clang
16+ when assigning to single-bit bitfields.
2023-07-05 08:17:51 +01:00

1375 lines
37 KiB
C++

/*
* Copyright (c) 2021, James Mintram <me@jamesrm.com>
* Copyright (c) 2021, Marcin Undak <mcinek@gmail.com>
* Copyright (c) 2022, Konrad <konrad@serenityos.org>
* Copyright (c) 2022, the SerenityOS developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/StringView.h>
#include <AK/Types.h>
namespace Kernel::Aarch64 {
// https://developer.arm.com/documentation/ddi0601/2022-09/AArch64-Registers/ID-AA64ISAR0-EL1--AArch64-Instruction-Set-Attribute-Register-0?lang=en
// ID_AA64ISAR0_EL1, AArch64 Instruction Set Attribute Register 0
struct alignas(u64) ID_AA64ISAR0_EL1 {
u64 : 4;
u64 AES : 4;
u64 SHA1 : 4;
u64 SHA2 : 4;
u64 CRC32 : 4;
u64 Atomic : 4;
u64 TME : 4;
u64 RDM : 4;
u64 SHA3 : 4;
u64 SM3 : 4;
u64 SM4 : 4;
u64 DP : 4;
u64 FHM : 4;
u64 TS : 4;
u64 TLB : 4;
u64 RNDR : 4;
static inline ID_AA64ISAR0_EL1 read()
{
ID_AA64ISAR0_EL1 feature_register;
asm volatile("mrs %[value], ID_AA64ISAR0_EL1"
: [value] "=r"(feature_register));
return feature_register;
}
};
static_assert(sizeof(ID_AA64ISAR0_EL1) == 8);
// https://developer.arm.com/documentation/ddi0601/2022-12/AArch64-Registers/ID-AA64ISAR1-EL1--AArch64-Instruction-Set-Attribute-Register-1
// ID_AA64ISAR1_EL1, AArch64 Instruction Set Attribute Register 1
struct alignas(u64) ID_AA64ISAR1_EL1 {
u64 DPB : 4;
u64 APA : 4;
u64 API : 4;
u64 JSCVT : 4;
u64 FCMA : 4;
u64 LRCPC : 4;
u64 GPA : 4;
u64 GPI : 4;
u64 FRINTTS : 4;
u64 SB : 4;
u64 SPECRES : 4;
u64 BF16 : 4;
u64 DGH : 4;
u64 I8MM : 4;
u64 XS : 4;
u64 LS64 : 4;
static inline ID_AA64ISAR1_EL1 read()
{
ID_AA64ISAR1_EL1 feature_register;
asm volatile("mrs %[value], ID_AA64ISAR1_EL1"
: [value] "=r"(feature_register));
return feature_register;
}
};
static_assert(sizeof(ID_AA64ISAR1_EL1) == 8);
// https://developer.arm.com/documentation/ddi0601/2022-12/AArch64-Registers/ID-AA64ISAR2-EL1--AArch64-Instruction-Set-Attribute-Register-2
// ID_AA64ISAR2_EL1, AArch64 Instruction Set Attribute Register 2
struct alignas(u64) ID_AA64ISAR2_EL1 {
u64 WFxT : 4;
u64 RPRES : 4;
u64 GPA3 : 4;
u64 APA3 : 4;
u64 MOPS : 4;
u64 BC : 4;
u64 PAC_frac : 4;
u64 CLRBHB : 4;
u64 SYSREG_128 : 4;
u64 SYSINSTR_128 : 4;
u64 PRFMSLC : 4;
u64 : 4;
u64 RPRFM : 4;
u64 CSSC : 4;
u64 : 8;
static inline ID_AA64ISAR2_EL1 read()
{
ID_AA64ISAR2_EL1 feature_register;
asm volatile("mrs %[value], ID_AA64ISAR2_EL1"
: [value] "=r"(feature_register));
return feature_register;
}
};
static_assert(sizeof(ID_AA64ISAR2_EL1) == 8);
// https://developer.arm.com/documentation/ddi0601/2022-12/AArch64-Registers/ID-AA64PFR0-EL1--AArch64-Processor-Feature-Register-0
// ID_AA64PFR0_EL1, AArch64 Processor Feature Register 0
struct alignas(u64) ID_AA64PFR0_EL1 {
u64 EL0 : 4;
u64 EL1 : 4;
u64 EL2 : 4;
u64 EL3 : 4;
u64 FP : 4;
u64 AdvSIMD : 4;
u64 GIC : 4;
u64 RAS : 4;
u64 SVE : 4;
u64 SEL2 : 4;
u64 MPAM : 4;
u64 AMU : 4;
u64 DIT : 4;
u64 RME : 4;
u64 CSV2 : 4;
u64 CSV3 : 4;
static inline ID_AA64PFR0_EL1 read()
{
ID_AA64PFR0_EL1 feature_register;
asm volatile("mrs %[value], ID_AA64PFR0_EL1"
: [value] "=r"(feature_register));
return feature_register;
}
};
static_assert(sizeof(ID_AA64PFR0_EL1) == 8);
// https://developer.arm.com/documentation/ddi0601/2022-12/AArch64-Registers/ID-AA64PFR1-EL1--AArch64-Processor-Feature-Register-1
// ID_AA64PFR1_EL1, AArch64 Processor Feature Register 1
struct alignas(u64) ID_AA64PFR1_EL1 {
u64 BT : 4;
u64 SSBS : 4;
u64 MTE : 4;
u64 RAS_frac : 4;
u64 MPAM_frac : 4;
u64 : 4;
u64 SME : 4;
u64 RNDR_trap : 4;
u64 CSV2_frac : 4;
u64 NMI : 4;
u64 MTE_frac : 4;
u64 GCS : 4;
u64 THE : 4;
u64 MTEX : 4;
u64 DF2 : 4;
u64 PFAR : 4;
static inline ID_AA64PFR1_EL1 read()
{
ID_AA64PFR1_EL1 feature_register;
asm volatile("mrs %[value], ID_AA64PFR1_EL1"
: [value] "=r"(feature_register));
return feature_register;
}
};
static_assert(sizeof(ID_AA64PFR1_EL1) == 8);
// https://developer.arm.com/documentation/ddi0601/2022-12/AArch64-Registers/ID-AA64PFR2-EL1--AArch64-Processor-Feature-Register-2
// ID_AA64PFR2_EL1, AArch64 Processor Feature Register 2
struct alignas(u64) ID_AA64PFR2_EL1 {
u64 MTEPERM : 4;
u64 MTESTOREONLY : 4;
u64 MTEFAR : 4;
u64 : 20;
u64 : 32;
static inline ID_AA64PFR2_EL1 read()
{
ID_AA64PFR2_EL1 feature_register;
asm volatile("mrs %[value], s3_0_c0_c4_2" // encoded ID_AA64PFR2_EL1 register
: [value] "=r"(feature_register));
return feature_register;
}
};
static_assert(sizeof(ID_AA64PFR2_EL1) == 8);
// https://developer.arm.com/documentation/ddi0595/2021-12/AArch64-Registers/MPIDR-EL1--Multiprocessor-Affinity-Register?lang=en
// MPIDR_EL1, Multiprocessor Affinity Register
struct alignas(u64) MPIDR_EL1 {
u64 Aff0 : 8;
u64 Aff1 : 8;
u64 Aff2 : 8;
u64 MT : 1;
u64 : 5;
u64 U : 1;
u64 : 1;
u64 Aff3 : 8;
u64 : 24;
static inline MPIDR_EL1 read()
{
MPIDR_EL1 affinity_register;
asm volatile("mrs %[value], MPIDR_EL1"
: [value] "=r"(affinity_register));
return affinity_register;
}
};
static_assert(sizeof(MPIDR_EL1) == 8);
// https://developer.arm.com/documentation/ddi0601/2022-12/AArch64-Registers/ID-AA64MMFR0-EL1--AArch64-Memory-Model-Feature-Register-0
// ID_AA64MMFR0_EL1, AArch64 Memory Model Feature Register 0
struct alignas(u64) ID_AA64MMFR0_EL1 {
u64 PARange : 4;
u64 ASIDBits : 4;
u64 BigEnd : 4;
u64 SNSMem : 4;
u64 BigEndEL0 : 4;
u64 TGran16 : 4;
u64 TGran64 : 4;
u64 TGran4 : 4;
u64 TGran16_2 : 4;
u64 TGran64_2 : 4;
u64 TGran4_2 : 4;
u64 ExS : 4;
u64 : 8;
u64 FGT : 4;
u64 ECV : 4;
static inline ID_AA64MMFR0_EL1 read()
{
ID_AA64MMFR0_EL1 feature_register;
asm volatile("mrs %[value], ID_AA64MMFR0_EL1"
: [value] "=r"(feature_register));
return feature_register;
}
};
static_assert(sizeof(ID_AA64MMFR0_EL1) == 8);
// https://developer.arm.com/documentation/ddi0601/2022-12/AArch64-Registers/ID-AA64MMFR1-EL1--AArch64-Memory-Model-Feature-Register-1
// ID_AA64MMFR1_EL1, AArch64 Memory Model Feature Register 1
struct alignas(u64) ID_AA64MMFR1_EL1 {
u64 HAFDBS : 4;
u64 VMIDBits : 4;
u64 VH : 4;
u64 HPDS : 4;
u64 LO : 4;
u64 PAN : 4;
u64 SpecSEI : 4;
u64 XNX : 4;
u64 TWED : 4;
u64 ETS : 4;
u64 HCX : 4;
u64 AFP : 4;
u64 nTLBPA : 4;
u64 TIDCP1 : 4;
u64 CMOW : 4;
u64 ECBHB : 4;
static inline ID_AA64MMFR1_EL1 read()
{
ID_AA64MMFR1_EL1 feature_register;
asm volatile("mrs %[value], ID_AA64MMFR1_EL1"
: [value] "=r"(feature_register));
return feature_register;
}
};
static_assert(sizeof(ID_AA64MMFR1_EL1) == 8);
// https://developer.arm.com/documentation/ddi0601/2022-12/AArch64-Registers/ID-AA64MMFR2-EL1--AArch64-Memory-Model-Feature-Register-2
// ID_AA64MMFR2_EL1, AArch64 Memory Model Feature Register 2
struct alignas(u64) ID_AA64MMFR2_EL1 {
u64 CnP : 4;
u64 UAO : 4;
u64 LSM : 4;
u64 IESB : 4;
u64 VARange : 4;
u64 CCIDX : 4;
u64 NV : 4;
u64 ST : 4;
u64 AT : 4;
u64 IDS : 4;
u64 FWB : 4;
u64 : 4;
u64 TTL : 4;
u64 BBM : 4;
u64 EVT : 4;
u64 E0PD : 4;
static inline ID_AA64MMFR2_EL1 read()
{
ID_AA64MMFR2_EL1 feature_register;
asm volatile("mrs %[value], ID_AA64MMFR2_EL1"
: [value] "=r"(feature_register));
return feature_register;
}
};
static_assert(sizeof(ID_AA64MMFR2_EL1) == 8);
// https://developer.arm.com/documentation/ddi0601/2022-12/AArch64-Registers/ID-AA64MMFR3-EL1--AArch64-Memory-Model-Feature-Register-3
// ID_AA64MMFR3_EL1, AArch64 Memory Model Feature Register 3
struct alignas(u64) ID_AA64MMFR3_EL1 {
u64 TCRX : 4;
u64 SCTLRX : 4;
u64 S1PIE : 4;
u64 S2PIE : 4;
u64 S1POE : 4;
u64 S2POE : 4;
u64 AIE : 4;
u64 MEC : 4;
u64 D128 : 4;
u64 D128_2 : 4;
u64 SNERR : 4;
u64 ANERR : 4;
u64 : 4;
u64 SDERR : 4;
u64 ADERR : 4;
u64 Spec_FPACC : 4;
static inline ID_AA64MMFR3_EL1 read()
{
ID_AA64MMFR3_EL1 feature_register;
asm volatile("mrs %[value], s3_0_c0_c7_3" // encoded ID_AA64MMFR3_EL1 register
: [value] "=r"(feature_register));
return feature_register;
}
};
static_assert(sizeof(ID_AA64MMFR3_EL1) == 8);
// https://developer.arm.com/documentation/ddi0601/2022-12/AArch64-Registers/ID-AA64MMFR4-EL1--AArch64-Memory-Model-Feature-Register-4
// ID_AA64MMFR4_EL1, AArch64 Memory Model Feature Register 4
struct alignas(u64) ID_AA64MMFR4_EL1 {
u64 : 4;
u64 EIESB : 4;
u64 : 24;
u64 : 32;
static inline ID_AA64MMFR4_EL1 read()
{
ID_AA64MMFR4_EL1 feature_register;
asm volatile("mrs %[value], s3_0_c0_c7_4" // encoded ID_AA64MMFR4_EL1 register
: [value] "=r"(feature_register));
return feature_register;
}
};
static_assert(sizeof(ID_AA64MMFR4_EL1) == 8);
// https://developer.arm.com/documentation/ddi0601/2022-12/AArch64-Registers/ID-AA64SMFR0-EL1--SME-Feature-ID-register-0
// ID_AA64SMFR0_EL1, AArch64 SME Feature ID register 0
struct alignas(u64) ID_AA64SMFR0_EL1 {
u64 : 32;
u64 F32F32 : 1;
u64 BI32I32 : 1;
u64 B16F32 : 1;
u64 F16F32 : 1;
u64 I8I32 : 4;
u64 : 2;
u64 F16F16 : 1;
u64 B16B16 : 1;
u64 I16I32 : 4;
u64 F64F64 : 1;
u64 : 3;
u64 I16I64 : 4;
u64 SMEver : 4;
u64 : 3;
u64 FA64 : 1;
static inline ID_AA64SMFR0_EL1 read()
{
ID_AA64SMFR0_EL1 feature_register;
asm volatile("mrs %[value], s3_0_c0_c4_5" // encoded ID_AA64SMFR0_EL1 register
: [value] "=r"(feature_register));
return feature_register;
}
};
static_assert(sizeof(ID_AA64SMFR0_EL1) == 8);
// https://developer.arm.com/documentation/ddi0601/2022-12/AArch64-Registers/ID-AA64ZFR0-EL1--SVE-Feature-ID-register-0
// ID_AA64ZFR0_EL1, AArch64 SVE Feature ID register 0
struct alignas(u64) ID_AA64ZFR0_EL1 {
u64 SVEver : 4;
u64 AES : 4;
u64 : 8;
u64 BitPerm : 4;
u64 BF16 : 4;
u64 B16B16 : 4;
u64 : 4;
u64 SHA3 : 4;
u64 : 4;
u64 SM4 : 4;
u64 I8MM : 4;
u64 : 4;
u64 F32MM : 4;
u64 F64MM : 4;
u64 : 4;
static inline ID_AA64ZFR0_EL1 read()
{
ID_AA64ZFR0_EL1 feature_register;
asm volatile("mrs %[value], s3_0_c0_c4_4" // encoded ID_AA64ZFR0_EL1 register
: [value] "=r"(feature_register));
return feature_register;
}
};
static_assert(sizeof(ID_AA64ZFR0_EL1) == 8);
// https://developer.arm.com/documentation/ddi0601/2022-12/AArch64-Registers/ID-AA64DFR0-EL1--AArch64-Debug-Feature-Register-0
// ID_AA64DFR0_EL1, AArch64 Debug Feature Register 0
struct alignas(u64) ID_AA64DFR0_EL1 {
u64 DebugVer : 4;
u64 TraceVer : 4;
u64 PMUVer : 4;
u64 BRPs : 4;
u64 PMSS : 4;
u64 WRPs : 4;
u64 SEBEP : 4;
u64 CTX_CMPs : 4;
u64 PMSVer : 4;
u64 DoubleLock : 4;
u64 TraceFilt : 4;
u64 TraceBuffer : 4;
u64 MTPMU : 4;
u64 BRBE : 4;
u64 ExtTrcBuff : 4;
u64 HPMN0 : 4;
static inline ID_AA64DFR0_EL1 read()
{
ID_AA64DFR0_EL1 feature_register;
asm volatile("mrs %[value], ID_AA64DFR0_EL1"
: [value] "=r"(feature_register));
return feature_register;
}
};
static_assert(sizeof(ID_AA64DFR0_EL1) == 8);
// https://developer.arm.com/documentation/ddi0601/2022-12/AArch64-Registers/ID-AA64DFR1-EL1--AArch64-Debug-Feature-Register-1
// ID_AA64DFR1_EL1, AArch64 Debug Feature Register 1
struct alignas(u64) ID_AA64DFR1_EL1 {
u64 SYSPMUID : 8;
u64 BRPs : 8;
u64 WRPs : 8;
u64 CTX_CMPs : 8;
u64 SPMU : 4;
u64 PMICNTR : 4;
u64 ABLE : 4;
u64 ITE : 4;
u64 EBEP : 4;
u64 : 4;
u64 ABL_CMPs : 8;
static inline ID_AA64DFR1_EL1 read()
{
ID_AA64DFR1_EL1 feature_register;
asm volatile("mrs %[value], ID_AA64DFR1_EL1"
: [value] "=r"(feature_register));
return feature_register;
}
};
static_assert(sizeof(ID_AA64DFR1_EL1) == 8);
// https://developer.arm.com/documentation/ddi0595/2020-12/AArch64-Registers/CNTFRQ-EL0--Counter-timer-Frequency-register
// CNTFRQ_EL0, Counter-timer Frequency register
struct alignas(u64) CNTFRQ_EL0 {
u64 : 32;
u64 ClockFrequency : 32;
static inline CNTFRQ_EL0 read()
{
CNTFRQ_EL0 frequency;
asm volatile("mrs %[value], CNTFRQ_EL0"
: [value] "=r"(frequency));
return frequency;
}
};
static_assert(sizeof(CNTFRQ_EL0) == 8);
// https://developer.arm.com/documentation/ddi0595/2021-06/AArch64-Registers/TCR-EL1--Translation-Control-Register--EL1-
// Translation Control Register
struct alignas(u64) TCR_EL1 {
enum Shareability {
NonSharable = 0b00,
OuterShareable = 0b10,
InnerShareable = 0b11,
};
enum OuterCacheability {
NormalMemory_Outer_NonCacheable = 0b00,
NormalMemory_Outer_WriteBack_ReadAllocate_WriteAllocateCacheable = 0b01,
NormalMemory_Outer_WriteThrough_ReadAllocate_NoWriteAllocateCacheable = 0b10,
NormalMemory_Outer_WriteBack_ReadAllocate_NoWriteAllocateCacheable = 0b11,
};
enum InnerCacheability {
NormalMemory_Inner_NonCacheable = 0b00,
NormalMemory_Inner_WriteBack_ReadAllocate_WriteAllocateCacheable = 0b01,
NormalMemory_Inner_WriteThrough_ReadAllocate_NoWriteAllocateCacheable = 0b10,
NormalMemory_Inner_WriteBack_ReadAllocate_NoWriteAllocateCacheable = 0b11,
};
// In AArch64, you have 3 possible translation granules to choose from,
// each of which results in a different set of page sizes:
// - 4KB granule: 4KB, 2MB, and 1GB pages.
// - 16KB granule: 16KB and 32MB pages.
// - 64KB granule: 64KB and 512MB pages.
//
// (https://stackoverflow.com/a/34269498)
enum class TG1GranuleSize : u8 {
Size_16KB = 0b01,
Size_4KB = 0b10,
Size_64KB = 0b11,
};
enum class TG0GranuleSize : u8 {
Size_4KB = 0b00,
Size_64KB = 0b01,
Size_16KB = 0b10,
};
u64 T0SZ : 6;
u64 RES0_0 : 1;
u64 EPD0 : 1;
InnerCacheability IRGN0 : 2;
OuterCacheability ORGN0 : 2;
Shareability SH0 : 2;
TG0GranuleSize TG0 : 2;
u64 T1SZ : 6;
u64 A1 : 1;
u64 EPD1 : 1;
InnerCacheability IRGN1 : 2;
OuterCacheability ORGN1 : 2;
Shareability SH1 : 2;
TG1GranuleSize TG1 : 2;
u64 IPS : 3;
u64 RES0_1 : 1;
u64 AS : 1;
u64 TBI0 : 1;
u64 TBI1 : 1;
u64 HA : 1;
u64 HD : 1;
u64 HPD0 : 1;
u64 HPD1 : 1;
u64 HWU059 : 1;
u64 HWU060 : 1;
u64 HWU061 : 1;
u64 HWU062 : 1;
u64 HWU159 : 1;
u64 HWU160 : 1;
u64 HWU161 : 1;
u64 HWU162 : 1;
u64 TBID0 : 1;
u64 TBID1 : 1;
u64 NFD0 : 1;
u64 NFD1 : 1;
u64 E0PD0 : 1;
u64 E0PD1 : 1;
u64 TCMA0 : 1;
u64 TCMA1 : 1;
u64 DS : 1;
u64 RES0_2 : 4;
static inline void write(TCR_EL1 tcr_el1)
{
asm volatile("msr tcr_el1, %[value]" ::[value] "r"(tcr_el1));
}
static inline TCR_EL1 read()
{
TCR_EL1 tcr_el1;
asm volatile("mrs %[value], tcr_el1"
: [value] "=r"(tcr_el1));
return tcr_el1;
}
static constexpr TCR_EL1 reset_value()
{
return {};
}
};
static_assert(sizeof(TCR_EL1) == 8);
// https://developer.arm.com/documentation/ddi0595/2021-03/AArch64-Registers/SCTLR-EL1--System-Control-Register--EL1-
// System Control Register
struct alignas(u64) SCTLR_EL1 {
u64 M : 1;
u64 A : 1;
u64 C : 1;
u64 SA : 1;
u64 SA0 : 1;
u64 CP15BEN : 1;
u64 nAA : 1;
u64 ITD : 1;
u64 SED : 1;
u64 UMA : 1;
u64 EnRCTX : 1;
u64 EOS : 1;
u64 I : 1;
u64 EnDB : 1;
u64 DZE : 1;
u64 UCT : 1;
u64 nTWI : 1;
u64 _reserved17 : 1 = 0;
u64 nTWE : 1;
u64 WXN : 1;
u64 TSCXT : 1;
u64 IESB : 1;
u64 EIS : 1;
u64 SPAN : 1;
u64 E0E : 1;
u64 EE : 1;
u64 UCI : 1;
u64 EnDA : 1;
u64 nTLSMD : 1;
u64 LSMAOE : 1;
u64 EnIB : 1;
u64 EnIA : 1;
u64 _reserved32 : 3 = 0;
u64 BT0 : 1;
u64 BT1 : 1;
u64 ITFSB : 1;
u64 TCF0 : 2;
u64 TCF : 2;
u64 ATA0 : 1;
u64 ATA : 1;
u64 DSSBS : 1;
u64 TWEDEn : 1;
u64 TWEDEL : 4;
u64 _reserved50 : 4 = 0;
u64 EnASR : 1;
u64 EnAS0 : 1;
u64 EnALS : 1;
u64 EPAN : 1;
u64 _reserved58 : 6 = 0;
static inline void write(SCTLR_EL1 sctlr_el1)
{
asm volatile("msr sctlr_el1, %[value]" ::[value] "r"(sctlr_el1));
}
static inline SCTLR_EL1 read()
{
SCTLR_EL1 sctlr;
asm volatile("mrs %[value], sctlr_el1"
: [value] "=r"(sctlr));
return sctlr;
}
static constexpr SCTLR_EL1 reset_value()
{
SCTLR_EL1 system_control_register_el1 = {};
system_control_register_el1.SA = 1;
system_control_register_el1.SA0 = 1;
system_control_register_el1.ITD = 1;
system_control_register_el1.SED = 1;
system_control_register_el1.EOS = 1;
system_control_register_el1.TSCXT = 1;
system_control_register_el1.IESB = 1;
system_control_register_el1.EIS = 1;
system_control_register_el1.SPAN = 1;
system_control_register_el1.LSMAOE = 1;
system_control_register_el1.nTLSMD = 1;
return system_control_register_el1;
}
};
static_assert(sizeof(SCTLR_EL1) == 8);
// https://developer.arm.com/documentation/ddi0601/2022-09/AArch64-Registers/MIDR-EL1--Main-ID-Register?lang=en
// MIDR_EL1, Main ID Register
struct alignas(u64) MIDR_EL1 {
u8 Revision : 4;
u16 PartNum : 12;
u8 Architecture : 4;
u8 Variant : 4;
u8 Implementer : 8;
u64 : 32;
static inline MIDR_EL1 read()
{
MIDR_EL1 main_id_register;
asm volatile("mrs %[value], MIDR_EL1"
: [value] "=r"(main_id_register));
return main_id_register;
}
};
static_assert(sizeof(MIDR_EL1) == 8);
// https://developer.arm.com/documentation/ddi0601/2022-09/AArch64-Registers/AIDR-EL1--Auxiliary-ID-Register?lang=en
// AIDR_EL1, Auxiliary ID Register
struct alignas(u64) AIDR_EL1 {
u64 AIDR : 64;
static inline AIDR_EL1 read()
{
AIDR_EL1 auxiliary_id_register;
asm volatile("mrs %[value], AIDR_EL1"
: [value] "=r"(auxiliary_id_register));
return auxiliary_id_register;
}
};
static_assert(sizeof(AIDR_EL1) == 8);
// https://developer.arm.com/documentation/ddi0595/2021-06/AArch64-Registers/HCR-EL2--Hypervisor-Configuration-Register
// Hypervisor Configuration Register
struct alignas(u64) HCR_EL2 {
u64 VM : 1;
u64 SWIO : 1;
u64 PTW : 1;
u64 FMO : 1;
u64 IMO : 1;
u64 AMO : 1;
u64 VF : 1;
u64 VI : 1;
u64 VSE : 1;
u64 FB : 1;
u64 BSU : 2;
u64 DC : 1;
u64 TWI : 1;
u64 TWE : 1;
u64 TID0 : 1;
u64 TID1 : 1;
u64 TID2 : 1;
u64 TID3 : 1;
u64 TSC : 1;
u64 TIPDCP : 1;
u64 TACR : 1;
u64 TSW : 1;
u64 TPCF : 1;
u64 TPU : 1;
u64 TTLB : 1;
u64 TVM : 1;
u64 TGE : 1;
u64 TDZ : 1;
u64 HCD : 1;
u64 TRVM : 1;
u64 RW : 1;
u64 CD : 1;
u64 ID : 1;
u64 E2H : 1;
u64 TLOR : 1;
u64 TERR : 1;
u64 MIOCNCE : 1;
u64 _reserved39 : 1 = 0;
u64 APK : 1 = 0;
u64 API : 1 = 0;
u64 NV : 1 = 0;
u64 NV1 : 1 = 0;
u64 AT : 1 = 0;
u64 _reserved45 : 18 = 0;
static inline void write(HCR_EL2 hcr_el2)
{
asm volatile("msr hcr_el2, %[value]" ::[value] "r"(hcr_el2));
}
static inline HCR_EL2 read()
{
HCR_EL2 spsr;
asm volatile("mrs %[value], hcr_el2"
: [value] "=r"(spsr));
return spsr;
}
};
static_assert(sizeof(HCR_EL2) == 8);
// https://developer.arm.com/documentation/ddi0595/2021-06/AArch64-Registers/SCR-EL3--Secure-Configuration-Register
// Secure Configuration Register
struct alignas(u64) SCR_EL3 {
u64 NS : 1;
u64 IRQ : 1;
u64 FIQ : 1;
u64 EA : 1;
u64 _reserved4 : 1 = 1;
u64 _reserved5 : 1 = 1;
u64 _reserved6 : 1 = 0;
u64 SMD : 1;
u64 HCE : 1;
u64 SIF : 1;
u64 RW : 1;
u64 ST : 1;
u64 TWI : 1;
u64 TWE : 1;
u64 TLOR : 1;
u64 TERR : 1;
u64 APK : 1;
u64 API : 1;
u64 EEL2 : 1;
u64 EASE : 1;
u64 NMEA : 1;
u64 FIEN : 1;
u64 _reserved22 : 3 = 0;
u64 EnSCXT : 1;
u64 ATA : 1;
u64 FGTEn : 1;
u64 ECVEn : 1;
u64 TWEDEn : 1;
u64 TWEDEL : 4;
u64 _reserved34 : 1 = 0;
u64 AMVOFFEN : 1;
u64 EnAS0 : 1;
u64 ADEn : 1;
u64 HXEn : 1;
u64 _reserved39 : 14 = 0;
static inline void write(SCR_EL3 scr_el3)
{
asm volatile("msr scr_el3, %[value]" ::[value] "r"(scr_el3));
}
static inline SCR_EL3 read()
{
SCR_EL3 scr;
asm volatile("mrs %[value], scr_el3"
: [value] "=r"(scr));
return scr;
}
};
static_assert(sizeof(SCR_EL3) == 8);
// C5.2.18 SPSR_EL1, Saved Program Status Register (EL1)
struct alignas(u64) SPSR_EL1 {
enum Mode : u8 {
EL0t = 0b0000,
EL1t = 0b0100,
EL1h = 0b0101
};
Mode M : 4;
u64 M_4 : 1 = 0;
u64 _reserved5 : 1 = 0;
u64 F : 1;
u64 I : 1;
u64 A : 1;
u64 D : 1;
u64 BTYPE : 2;
u64 SSBS : 1;
u64 _reserved13 : 7 = 0;
u64 IL : 1;
u64 SS : 1;
u64 PAN : 1;
u64 UA0 : 1;
u64 DIT : 1;
u64 TCO : 1;
u64 _reserved26 : 2 = 0;
u64 V : 1;
u64 C : 1;
u64 Z : 1;
u64 N : 1;
u64 _reserved32 : 32 = 0;
static inline void write(SPSR_EL1 spsr_el1)
{
asm volatile("msr spsr_el1, %[value]" ::[value] "r"(spsr_el1));
}
static inline SPSR_EL1 read()
{
SPSR_EL1 spsr;
asm volatile("mrs %[value], spsr_el1"
: [value] "=r"(spsr));
return spsr;
}
};
static_assert(sizeof(SPSR_EL1) == 8);
struct alignas(u64) SPSR_EL2 {
enum Mode : u16 {
EL0t = 0b0000,
EL1t = 0b0100,
EL1h = 0b0101,
EL2t = 0b1000,
EL2h = 0b1001
};
Mode M : 4;
u64 M_4 : 1 = 0;
u64 _reserved5 : 1 = 0;
u64 F : 1;
u64 I : 1;
u64 A : 1;
u64 D : 1;
u64 BTYPE : 2;
u64 SSBS : 1;
u64 _reserved13 : 7 = 0;
u64 IL : 1;
u64 SS : 1;
u64 PAN : 1;
u64 UA0 : 1;
u64 DIT : 1;
u64 TCO : 1;
u64 _reserved26 : 2 = 0;
u64 V : 1;
u64 C : 1;
u64 Z : 1;
u64 N : 1;
u64 _reserved32 : 32 = 0;
static inline void write(SPSR_EL2 spsr_el2)
{
asm volatile("msr spsr_el2, %[value]" ::[value] "r"(spsr_el2));
}
static inline SPSR_EL2 read()
{
SPSR_EL2 spsr;
asm volatile("mrs %[value], spsr_el2"
: [value] "=r"(spsr));
return spsr;
}
};
static_assert(sizeof(SPSR_EL2) == 8);
// https://developer.arm.com/documentation/ddi0595/2021-06/AArch64-Registers/SPSR-EL3--Saved-Program-Status-Register--EL3-
// Saved Program Status Register
struct alignas(u64) SPSR_EL3 {
enum Mode : uint16_t {
EL0t = 0b0000,
EL1t = 0b0100,
EL1h = 0b0101,
EL2t = 0b1000,
EL2h = 0b1001,
EL3t = 0b1100,
EL3h = 0b1101
};
Mode M : 4;
u64 M_4 : 1 = 0;
u64 _reserved5 : 1 = 0;
u64 F : 1;
u64 I : 1;
u64 A : 1;
u64 D : 1;
u64 _reserved10 : 10 = 0;
u64 IL : 1;
u64 SS : 1;
u64 PAN : 1;
u64 UA0 : 1;
u64 _reserved24 : 4 = 0;
u64 V : 1;
u64 C : 1;
u64 Z : 1;
u64 N : 1;
u64 _reserved32 : 32 = 0;
static inline void write(SPSR_EL3 spsr_el3)
{
asm volatile("msr spsr_el3, %[value]" ::[value] "r"(spsr_el3));
}
static inline SPSR_EL3 read()
{
SPSR_EL3 spsr;
asm volatile("mrs %[value], spsr_el3"
: [value] "=r"(spsr));
return spsr;
}
};
static_assert(sizeof(SPSR_EL3) == 8);
// https://developer.arm.com/documentation/ddi0595/2020-12/AArch64-Registers/MAIR-EL1--Memory-Attribute-Indirection-Register--EL1-?lang=en#fieldset_0-63_0
// Memory Attribute Indirection Register
struct alignas(u64) MAIR_EL1 {
using AttributeEncoding = uint8_t;
AttributeEncoding Attr[8];
static inline void write(MAIR_EL1 mair_el1)
{
asm volatile("msr mair_el1, %[value]" ::[value] "r"(mair_el1));
}
};
static_assert(sizeof(MAIR_EL1) == 8);
// https://developer.arm.com/documentation/ddi0595/2021-06/AArch64-Registers/ESR-EL1--Exception-Syndrome-Register--EL1-
// Exception Syndrome Register (EL1)
struct ESR_EL1 {
u64 ISS : 25;
u64 IL : 1;
u64 EC : 6;
u64 ISS2 : 5;
u64 : 27;
static inline ESR_EL1 read()
{
ESR_EL1 esr_el1;
asm volatile("mrs %[value], esr_el1"
: [value] "=r"(esr_el1));
return esr_el1;
}
};
static_assert(sizeof(ESR_EL1) == 8);
// D17.2.40 FAR_EL1, Fault Address Register (EL1)
struct FAR_EL1 {
u64 virtual_address;
static inline FAR_EL1 read()
{
FAR_EL1 far_el1;
asm volatile("mrs %[value], far_el1"
: [value] "=r"(far_el1));
return far_el1;
}
};
static_assert(sizeof(FAR_EL1) == 8);
// D17.2.37 ESR_EL1, Exception Syndrome Register (EL1)
static inline StringView exception_class_to_string(u8 exception_class)
{
switch (exception_class) {
case 0b000000:
return "Unknown reason"sv;
case 0b000001:
return "Trapped WF* instruction execution"sv;
case 0b000011:
return "Trapped MCR or MRC access with (coproc==0b1111) that is not reported using EC 0b000000"sv;
case 0b000100:
return "Trapped MCRR or MRRC access with (coproc==0b1111) that is not reported using EC 0b000000"sv;
case 0b000101:
return "Trapped MCR or MRC access with (coproc==0b1110)"sv;
case 0b000110:
return "Trapped LDC or STC access"sv;
case 0b000111:
return "Access to SME, SVE, Advanced SIMD or floating-point functionality trapped by CPACR_EL1.FPEN, CPTR_EL2.FPEN, CPTR_EL2.TFP, or CPTR_EL3.TFP control"sv;
case 0b001010:
return "Trapped execution of an LD64B or ST64B* instruction"sv;
case 0b001100:
return "Trapped MRRC access with (coproc==0b1110)"sv;
case 0b001101:
return "Branch Target Exception"sv;
case 0b001110:
return "Illegal Execution state"sv;
case 0b010001:
return "SVC instruction execution in AArch32 state"sv;
case 0b010101:
return "SVC instruction execution in AArch64 state"sv;
case 0b011000:
return "Trapped MSR, MRS or System instruction execution in AArch64 state, that is not reported using EC 0b000000, 0b000001, or 0b000111"sv;
case 0b011001:
return "Access to SVE functionality trapped as a result of CPACR_EL1.ZEN, CPTR_EL2.ZEN, CPTR_EL2.TZ, or CPTR_EL3.EZ, that is not reported using EC 0b000000"sv;
case 0b011011:
return "Exception from an access to a TSTART instruction at EL0 when SCTLR_EL1.TME0 == 0, EL0 when SCTLR_EL2.TME0 == 0, at EL1 when SCTLR_EL1.TME == 0, at EL2 when SCTLR_EL2.TME == 0 or at EL3 when SCTLR_EL3.TME == 0"sv;
case 0b011100:
return "Exception from a Pointer Authentication instruction authentication failure"sv;
case 0b011101:
return "Access to SME functionality trapped as a result of CPACR_EL1.SMEN, CPTR_EL2.SMEN, CPTR_EL2.TSM, CPTR_EL3.ESM, or an attempted execution of an instruction that is illegal because of the value of PSTATE.SM or PSTATE.ZA, that is not reported using EC 0b000000"sv;
case 0b011110:
return "Exception from a Granule Protection Check"sv;
case 0b100000:
return "Instruction Abort from a lower Exception level"sv;
case 0b100001:
return "Instruction Abort taken without a change in Exception level"sv;
case 0b100010:
return "PC alignment fault exception"sv;
case 0b100100:
return "Data Abort exception from a lower Exception level"sv;
case 0b100101:
return "Data Abort exception taken without a change in Exception level"sv;
case 0b100110:
return "SP alignment fault exception"sv;
case 0b100111:
return "Memory Operation Exception"sv;
case 0b101000:
return "Trapped floating-point exception taken from AArch32 state"sv;
case 0b101100:
return "Trapped floating-point exception taken from AArch64 state"sv;
case 0b101111:
return "SError interrupt"sv;
case 0b110000:
return "Breakpoint exception from a lower Exception level"sv;
case 0b110001:
return "Breakpoint exception taken without a change in Exception level"sv;
case 0b110010:
return "Software Step exception from a lower Exception level"sv;
case 0b110011:
return "Software Step exception taken without a change in Exception level"sv;
case 0b110100:
return "Watchpoint exception from a lower Exception level"sv;
case 0b110101:
return "Watchpoint exception taken without a change in Exception level"sv;
case 0b111000:
return "BKPT instruction execution in AArch32 state"sv;
case 0b111100:
return "BRK instruction execution in AArch64 state"sv;
default:
VERIFY_NOT_REACHED();
}
}
// D17.2.40 FAR_EL1, Fault Address Register (EL1)
static inline bool exception_class_has_set_far(u8 exception_class)
{
// Faulting Virtual Address for synchronous exceptions taken to EL1. Exceptions that set the
// FAR_EL1 are Instruction Aborts (EC 0x20 or 0x21), Data Aborts (EC 0x24 or 0x25), PC alignment
// faults (EC 0x22), and Watchpoints (EC 0x34 or 0x35). ESR_EL1.EC holds the EC value for the
// exception.
switch (exception_class) {
case 0x20:
case 0x21:
case 0x22:
case 0x24:
case 0x25:
case 0x34:
case 0x35:
return true;
default:
return false;
}
}
static inline bool exception_class_is_data_abort(u8 exception_class)
{
return exception_class == 0x24 || exception_class == 0x25;
}
static inline bool exception_class_is_instruction_abort(u8 exception_class)
{
return exception_class == 0x20 || exception_class == 0x21;
}
static inline bool exception_class_is_data_or_instruction_abort_from_lower_exception_level(u8 exception_class)
{
return exception_class == 0x20 || exception_class == 0x24;
}
static inline bool exception_class_is_svc_instruction_execution(u8 exception_class)
{
return exception_class == 0x11 || exception_class == 0x15;
}
// D17.2.37 ESR_EL1, Exception Syndrome Register (EL1)
// ISS encoding for an exception from a Data Abort
// DFSC, bits [5:0]
static inline StringView data_fault_status_code_to_string(u32 instruction_specific_syndrome)
{
u8 data_fault_status_code = instruction_specific_syndrome & 0x3f;
switch (data_fault_status_code) {
case 0b000000:
return "Address size fault, level 0 of translation or translation table base register"sv;
case 0b000001:
return "Address size fault, level 1"sv;
case 0b000010:
return "Address size fault, level 2"sv;
case 0b000011:
return "Address size fault, level 3"sv;
case 0b000100:
return "Translation fault, level 0"sv;
case 0b000101:
return "Translation fault, level 1"sv;
case 0b000110:
return "Translation fault, level 2"sv;
case 0b000111:
return "Translation fault, level 3"sv;
case 0b001001:
return "Access flag fault, level 1"sv;
case 0b001010:
return "Access flag fault, level 2"sv;
case 0b001011:
return "Access flag fault, level 3"sv;
case 0b001000:
return "Access flag fault, level 0"sv;
case 0b001100:
return "Permission fault, level 0"sv;
case 0b001101:
return "Permission fault, level 1"sv;
case 0b001110:
return "Permission fault, level 2"sv;
case 0b001111:
return "Permission fault, level 3"sv;
case 0b010000:
return "Synchronous External abort, not on translation table walk or hardware update of translation table"sv;
case 0b010001:
return "Synchronous Tag Check Fault"sv;
case 0b010011:
return "Synchronous External abort on translation table walk or hardware update of translation table, level -1"sv;
case 0b010100:
return "Synchronous External abort on translation table walk or hardware update of translation table, level 0"sv;
case 0b010101:
return "Synchronous External abort on translation table walk or hardware update of translation table, level 1"sv;
case 0b010110:
return "Synchronous External abort on translation table walk or hardware update of translation table, level 2"sv;
case 0b010111:
return "Synchronous External abort on translation table walk or hardware update of translation table, level 3"sv;
case 0b011000:
return "Synchronous parity or ECC error on memory access, not on translation table walk"sv;
case 0b011011:
return "Synchronous parity or ECC error on memory access on translation table walk or hardware update of translation table, level -1"sv;
case 0b011100:
return "Synchronous parity or ECC error on memory access on translation table walk or hardware update of translation table, level 0"sv;
case 0b011101:
return "Synchronous parity or ECC error on memory access on translation table walk or hardware update of translation table, level 1"sv;
case 0b011110:
return "Synchronous parity or ECC error on memory access on translation table walk or hardware update of translation table, level 2"sv;
case 0b011111:
return "Synchronous parity or ECC error on memory access on translation table walk or hardware update of translation table, level 3"sv;
case 0b100001:
return "Alignment fault"sv;
case 0b100011:
return "Granule Protection Fault on translation table walk or hardware update of translation table, level -1"sv;
case 0b100100:
return "Granule Protection Fault on translation table walk or hardware update of translation table, level 0"sv;
case 0b100101:
return "Granule Protection Fault on translation table walk or hardware update of translation table, level 1"sv;
case 0b100110:
return "Granule Protection Fault on translation table walk or hardware update of translation table, level 2"sv;
case 0b100111:
return "Granule Protection Fault on translation table walk or hardware update of translation table, level 3"sv;
case 0b101000:
return "Granule Protection Fault, not on translation table walk or hardware update of translation table"sv;
case 0b101001:
return "Address size fault, level -1"sv;
case 0b101011:
return "Translation fault, level -1"sv;
case 0b110000:
return "TLB conflict abort"sv;
case 0b110001:
return "Unsupported atomic hardware update fault"sv;
case 0b110100:
return "IMPLEMENTATION DEFINED fault (Lockdown)"sv;
case 0b110101:
return "IMPLEMENTATION DEFINED fault (Unsupported Exclusive or Atomic access)"sv;
default:
VERIFY_NOT_REACHED();
}
}
// https://developer.arm.com/documentation/ddi0601/2020-12/AArch64-Registers/DAIF--Interrupt-Mask-Bits?lang=en
// DAIF, Interrupt Mask Bits
struct DAIF {
u64 : 6;
u64 F : 1;
u64 I : 1;
u64 A : 1;
u64 D : 1;
u64 : 54;
static inline DAIF read()
{
DAIF daif;
asm volatile("mrs %[value], daif"
: [value] "=r"(daif));
return daif;
}
// Clearing the I bit, causes interrupts to be enabled.
static inline void clear_I()
{
asm volatile("msr daifclr, #2" ::
:);
}
// Setting the I bit, causes interrupts to be disabled.
static inline void set_I()
{
asm volatile("msr daifset, #2" ::
:);
}
};
static_assert(sizeof(DAIF) == 8);
// https://developer.arm.com/documentation/ddi0595/2021-03/AArch64-Registers/NZCV--Condition-Flags
// NZCV, Condition Flags
struct alignas(u64) NZCV {
u64 : 28;
u64 V : 1;
u64 C : 1;
u64 Z : 1;
u64 N : 1;
u64 : 32;
static inline NZCV read()
{
NZCV nzcv;
asm volatile("mrs %[value], nzcv"
: [value] "=r"(nzcv));
return nzcv;
}
};
static_assert(sizeof(NZCV) == 8);
// https://developer.arm.com/documentation/ddi0595/2021-03/AArch64-Registers/PMCCNTR-EL0--Performance-Monitors-Cycle-Count-Register
// PMCCNTR_EL0, Performance Monitors Cycle Count Register
struct alignas(u64) PMCCNTR_EL0 {
u64 CCNT : 64;
static inline PMCCNTR_EL0 read()
{
PMCCNTR_EL0 pmccntr_el0;
asm volatile("mrs %[value], pmccntr_el0"
: [value] "=r"(pmccntr_el0));
return pmccntr_el0;
}
};
static_assert(sizeof(PMCCNTR_EL0) == 8);
// D17.2.30 CPACR_EL1, Architectural Feature Access Control Register
struct alignas(u64) CPACR_EL1 {
u64 _reserved0 : 16 = 0;
u64 ZEN : 2;
u64 _reserved18 : 2 = 0;
u64 FPEN : 2;
u64 _reserved22 : 2 = 0;
u64 SMEN : 2;
u64 _reserved26 : 2 = 0;
u64 TTA : 1;
u64 _reserved29 : 3 = 0;
u64 _reserved32 : 32 = 0;
static inline void write(CPACR_EL1 cpacr_el1)
{
asm volatile("msr cpacr_el1, %[value]" ::[value] "r"(cpacr_el1));
}
};
static_assert(sizeof(CPACR_EL1) == 8);
}