This project is a bare-metal experimental framework based on the Arm Fixed Virtual Platform (FVP) AEM (Architecture Envelope Model). It is designed to explore and understand the Armv9 Realm Management Extension (RME), focusing on the four distinct Physical Address Spaces (PAS) and the Granule Protection Check (GPC) mechanism.
The core objective is to set up a 2-stage EL1&0 Realm translation regime. This environment simulates how a Realm Management Monitor (RMM) or a Root-world controller manages memory isolation between the Realm and Non-secure worlds.
The project demonstrates three specific memory access scenarios:
- Realm EL0 accessing Non-secure address space.
- Realm EL1 accessing Realm address space.
- Realm EL1 accessing Root address space (triggering Faults).
The project implements four Physical Address Spaces (PAS):
- Root (0xC0000000-0xCFFFFFFF): For firmware and GPT management
- Realm (0xA0000000-0xAFFFFFFF, 0x80000000-0x8FFFFFFF): For protected Virtual Machines (Realms)
- Secure (0x90000000-0x9FFFFFFF): For traditional Secure-world TEEs
- Non-secure (0xB0000000-0xBFFFFFFF): For Host OS and standard application
The project implements the following translation chains (VA -> IPA -> PA):
| Virtual Address (VA) | Intermediate Phys Addr (IPA) | Physical Address (PA) | Target PAS |
|---|---|---|---|
0x80000000 - 0x8FFFFFFF |
0x80000000 - 0x8FFFFFFF |
0x80000000 - 0x8FFFFFFF |
Realm |
0xD0000000 - 0xDFFFFFFF |
0x50000000 - 0x5FFFFFFF |
0xB0000000 - 0xBFFFFFFF |
Non-secure |
0xFFFFFFFF00000000 - ... |
0x60000000 - 0x6FFFFFFF |
0xA0000000 - 0xAFFFFFFF |
Realm |
To build and run this project, ensure the following tools are installed and accessible in your PATH:
- Toolchain:
aarch64-none-elf-gcc(GNU Bare Metal Toolchain). - Simulator: Arm Fixed Virtual Platform (FVP) supporting RME (e.g.,
FVP_Base_RevC-2xAEMvA). - Build Tool:
make
The build system compiles the source code and generates the ELF image.
To compile the project, run:
Bash
● make
aarch64-none-elf-gcc -march=armv9-a -c -g -x assembler-with-cpp -c -o gpc_relam_el10.o gpc_relam_el10.S
aarch64-none-elf-gcc -march=armv9-a -c -g -x assembler-with-cpp -c -o invalidate_dcache.o invalidate_dcache.S
aarch64-none-elf-gcc -march=armv9-a -c -g -x assembler-with-cpp -c -o setup_realm_el10_stage1_translation.o setup_realm_el10_stage1_translation.S
aarch64-none-elf-gcc -march=armv9-a -c -g -x assembler-with-cpp -c -o setup_realm_el10_stage2_translation.o setup_realm_el10_stage2_translation.S
aarch64-none-elf-gcc -march=armv9-a -c -g -x assembler-with-cpp -c -o setup_gpt.o setup_gpt.S
aarch64-none-elf-gcc -march=armv9-a -static -nostartfiles -Wl,--entry=start -Wl,-Ttext=0x80000000 -o gpc_relam_el10.elf gpc_relam_el10.o invalidate_dcache.o setup_realm_el10_stage1_translation.o setup_realm_el10_stage2_translation.o setup_gpt.o
The project is configured to run on the AEM model with RME features enabled. The simulation will generate a Tarmac Trace file (rme_trace.log) for execution analysis.
To start the simulation, execute:
Bash
● ./run_AEM.sh gpc_relam_el10.elf
application: gpc_relam_el10.elf
Info: FVP_Base_RevC_2xAEMvA: terminal_0: Listening for serial connection on port 5000
Info: FVP_Base_RevC_2xAEMvA: terminal_1: Listening for serial connection on port 5001
Info: FVP_Base_RevC_2xAEMvA: terminal_2: Listening for serial connection on port 5002
Info: FVP_Base_RevC_2xAEMvA: terminal_3: Listening for serial connection on port 5003
'ToggleMTIInterfaceTRACE.TarmacTrace' registered in component registry.
Attaching the Tarmac trace to component FVP_Base_RevC_2xAEMvA.cluster0.cpu0.
RELAM GPC CHECK PASS
Info: /OSCI/SystemC: Simulation stopped by user.
--- FVP_Base_RevC_2xAEMvA statistics: -----------------------------------------
Simulated time : 0.000437s
User time at initialisation : 0.468364s
User time : 0.715826s
System time at initialisation : 0.238168s
System time : 0.009453s
Wall time at initialisation : 0.891460s
Wall time : 0.749652s
Performance index : 0.00
cluster0.cpu0 : 0.06 MIPS ( 43735 Inst)
Memory highwater mark at initialisation : 0x286fe000 bytes ( 0.632 GiB )
Memory highwater mark : 0x298c6000 bytes ( 0.649 GiB )
-------------------------------------------------------------------------------
Explore the isolation between the four Physical Address Spaces introduced by RME:
- Root: For firmware and GPC table management.
- Realm: For protected Virtual Machines (Realms).
- Secure: For traditional Secure-world TEEs.
- Non-secure: For the Host OS and standard applications.
Utilize Tarmac logs generated by the AEM model to trace instruction execution, register state changes, and memory transactions.
The Tarmac trace (rme_trace.log) is essential for debugging and verification. Key events to look for:
MW(Memory Write): Successful memory accessesTTW(Table Walk): Translation table walksGPTW(GPT Walk): Granule Protection Table walksES(Exception): Exception events with FSR indicating GPF
By analyzing these logs, we verify the integrity of the Stage 2 Translation and the Granule Protection Check (GPC) across the following three scenarios:
- Mechanism: A Realm-world application (EL0) accesses a VA mapped to a Non-secure PAS (e.g., for shared data with the Host).
- Verification: The Tarmac log should show a successful translation, and the final Physical Address matches the Non-secure range (
0xB0000000-0xBFFFFFFF). - Log Signature: Look for
MW(Memory Write) events pointing to the Non-secure PA range without triggering an exception.
43714 clk IT (43714) 80000920 d2800401 O EL1h_rl : MOV x1,#0x20
43715 clk IT (43715) 80000924 f2ba0001 O EL1h_rl : MOVK x1,#0xd000,LSL #16
43715 clk R X1 00000000D0000020
43716 clk IT (43716) 80000928 d2822220 O EL1h_rl : MOV x0,#0x1111
43717 clk IT (43717) 8000092c f2a22220 O EL1h_rl : MOVK x0,#0x1111,LSL #16
43717 clk R X0 0000000011111111
43718 clk IT (43718) 80000930 f9000020 O EL1h_rl : STR x0,[x1,#0]
VA(hex): 0xD0000020
VA(bin):0b11010000000000000000000000100000
- L1 index[46:36] = 0x0
- L2 index[35:25] = 0x68
- L3 index[24:14] = 0x0
- Offset[13:0] = 0x20
- Descriptor Entry: 8 Bytes
- 0x68 * 8 = 0x340
43718 clk TTW DTLB LPAE 1:2 000080018340(el1_stage1_table_lo_base + 0x340) 0060000050000641 : BLOCK ATTRIDX=0 NS=0 AP=1 SH=2 AF=1 nT=0 nG=0 16E=0 PXN=1 XN=1 ADDR=0x0000000050000000
IPA(hex): 0x50000020
IPA(bin): 0b1010000000000000000000000100000
- L1 index[46:36] = 0x0
- L2 index[35:25] = 0x28
- L3 index[24:14] = 0x0
- Offset[13:0] = 0x20
- Descriptor Entry: 8 Bytes
- 0x28 * 8 = 0x140
43718 clk TTW DTLB LPAE 2:2 000080020140(el1_stage2_table_base + 0x140) 00c00000b00006fd : BLOCK MEMATTR=15 HAP=3 SH=2 AF=1 nT=0 16E=0 XN=2 AMEC=0 ADDR=0x00000000b0000000
PA(hex): 0xB0000020
PA(bin): 0b10110000000000000000000000100000
- L0 index[31:30] = 0x2
- L1 index[29:18] = 0xC00
- GPI index[17:14] = 0x0
- Offset[13:0] = 0x20
- Descriptor Entry: 8 Bytes
- L0 index => 0x2 * 8 = 0x10
- L1 index => 0xC00 * 8 = 0x6000
- GPI index = > 0x0 * 8 = 0
43718 clk GPTW DSIDE L0 0000b0000020 0000000080028010(gpt_table_base + 0x10) : 0000000080030003 TABLE TYPE=0x03 ADDR=0x0000000080030000
43718 clk GPTW DSIDE L1 0000b0000020 0000000080036000(L0 Entry + 0x6000) : 999999999999999[9] GRANULE TYPE=0x09 GPI=0x09 PGS=16KB
Write: 0xB0000020_NS = 0x11111111
43718 clk MW8 0000b0000020_NS Normal OuterShareable Inner=WriteBackWriteAllocate Outer=WriteBackWriteAllocate
00000000_11111111
-
Mechanism: The Realm Kernel (EL1) accesses its own protected memory space.
-
Verification: Tarmac should reflect that mapped to a Physical Address within the Realm PAS (
0x80000000or0xA0000000ranges). -
GPC Check: Hardware validates the PA against the Granule Protection Table (GPT). The log confirms execution continues normally as the GPT entry for this granule is marked as
REALM. -
Log Signature: Look for
MW(Memory Write) events pointing to the realm PA range without triggering an exception.
43721 clk IT (43721) 8000093c d2802001 O EL1h_rl : MOV x1,#0x100
43722 clk IT (43722) 80000940 f2a00001 O EL1h_rl : MOVK x1,#0,LSL #16
43723 clk IT (43723) 80000944 f2dfffe1 O EL1h_rl : MOVK x1,#0xffff,LSL #32
43724 clk IT (43724) 80000948 f2ffffe1 O EL1h_rl : MOVK x1,#0xffff,LSL #48
43724 clk R X1 FFFFFFFF00000100
43725 clk IT (43725) 8000094c d2844440 O EL1h_rl : MOV x0,#0x2222
43726 clk IT (43726) 80000950 f2a44440 O EL1h_rl : MOVK x0,#0x2222,LSL #16
43726 clk R X0 0000000022222222
43727 clk IT (43727) 80000954 f9000020 O EL1h_rl : STR x0,[x1,#0]
VA(hex): 0xFFFFFFFF00000100
VA(bin):0b1111111111111111111111111111111100000000000000000000000100000000
- L2 index[35:25] = 0x0
- Offset[13:0] = 0x100
- Descriptor Entry: 8 Bytes
- 0x0 * 8 = 0x0
43727 clk TTW DTLB LPAE 1:2 00008001c000(el1_stage1_table_hi_base + 0x0) 0060000060000601 : BLOCK ATTRIDX=0 NS=0 AP=0 SH=2 AF=1 nT=0 nG=0 16E=0 PXN=1 XN=1 ADDR=0x0000000060000000
IPA(hex): 0x60000100
IPA(bin): 0b1100000000000000000000100000000
- L2 index[35:25] = 0x30
- Offset[13:0] = 0x100
- Descriptor Entry: 8 Bytes
- 0x30 * 8 = 0x180
43727 clk TTW DTLB LPAE 2:2 000080020180(el1_stage2_table_base + 0x180) 00400000a00006fd : BLOCK MEMATTR=15 HAP=3 SH=2 AF=1 nT=0 16E=0 XN=2 AMEC=0 ADDR=0x00000000a0000000
PA(hex): 0xA0000100
PA(bin): 0b10100000000000000000000000000000
- L0 index[31:30] = 0x2
- L1 index[29:18] = 0x800
- GPI index[17:14] = 0x0
- Offset[13:0] = 0x100
- Descriptor Entry: 8 Bytes
- L0 index => 0x2 * 8 = 0x10
- L1 index => 0x800 * 8 = 0x4000
- GPI index = > 0x0 * 8 = 0
43727 clk GPTW DSIDE L0 0000a0000100 0000000080028010(gpt_table_base + 0x10) : 0000000080030003 TABLE TYPE=0x03 ADDR=0x0000000080030000
43727 clk GPTW DSIDE L1 0000a0000100 0000000080034000(L0 Entry + 0x4000): [b]bbbbbbbbbbbbbbb GRANULE TYPE=0x0b GPI=0x0b PGS=16KB
43727 clk MW8 ffffffff00000100:0000a0000100_RL Normal OuterShareable Inner=WriteBackWriteAllocate Outer=WriteBackWriteAllocate 00000000_22222222
43727 clk MW8 00000100 00000000_22222222
- Mechanism: An intentional or accidental access by a Realm to a Root PAS address.
- Verification: This constitutes a security violation. The GPC mechanism must intercept the transaction.
- Result: The Tarmac log will capture a Granule Protection Fault (GPF).
- Log Signature: Search for
ESevents with a Fault Status Register (FSR) indicating a GPF.
43721 clk IT (43721) 8000093c d2802001 O EL1h_rl : MOV x1,#0x100
43722 clk IT (43722) 80000940 f2a00001 O EL1h_rl : MOVK x1,#0,LSL #16
43723 clk IT (43723) 80000944 f2dfffe1 O EL1h_rl : MOVK x1,#0xffff,LSL #32
43724 clk IT (43724) 80000948 f2ffffe1 O EL1h_rl : MOVK x1,#0xffff,LSL #48
43724 clk R X1 FFFFFFFF00000100
43725 clk IT (43725) 8000094c d2844440 O EL1h_rl : MOV x0,#0x2222
43726 clk IT (43726) 80000950 f2a44440 O EL1h_rl : MOVK x0,#0x2222,LSL #16
43726 clk R X0 0000000022222222
43727 clk IT (43727) 80000954 f9000020 O EL1h_rl : STR x0,[x1,#0]
VA(hex): 0xFFFFFFFF00000100
VA(bin):0b1111111111111111111111111111111100000000000000000000000100000000
- L2 index[35:25] = 0x0
- Offset[13:0] = 0x100
- Descriptor Entry: 8 Bytes
- 0x0 * 8 = 0x0
43727 clk TTW DTLB LPAE 1:2 00008001c000(el1_stage1_table_hi_base + 0x0) 0060000060000601 : BLOCK ATTRIDX=0 NS=0 AP=0 SH=2 AF=1 nT=0 nG=0 16E=0 PXN=1 XN=1 ADDR=0x0000000060000000
IPA(hex): 0x60000100
IPA(bin): 0b1100000000000000000000100000000
- L2 index[35:25] = 0x30
- Offset[13:0] = 0x100
- Descriptor Entry: 8 Bytes
- 0x30 * 8 = 0x180
43727 clk TTW DTLB LPAE 2:2 000080020180(el1_stage2_table_base + 0x180) 00400000a00006fd : BLOCK MEMATTR=15 HAP=3 SH=2 AF=1 nT=0 16E=0 XN=2 AMEC=0 ADDR=0x00000000a0000000
PA(hex): 0xA0000100
PA(bin): 0b10100000000000000000000000000000
- L0 index[31:30] = 0x2
- L1 index[29:18] = 0x800
- GPI index[17:14] = 0x0
- Offset[13:0] = 0x100
- Descriptor Entry: 8 Bytes
- L0 index => 0x2 * 8 = 0x10
- L1 index => 0x800 * 8 = 0x4000
- GPI index = > 0x0 * 8 = 0
43727 clk GPTW DSIDE L0 0000a0000000 0000000080028010(gpt_table_base + 0x10) : 0000000080030003 TABLE TYPE=0x03 ADDR=0x0000000080030000
43727 clk GPTW DSIDE L1 0000a0000000 0000000080034000(L0 Entry + 0x4000) : [a]aaaaaaaaaaaaaaa GRANULE TYPE=0x0a GPI=0x0a PGS=16KB
43727 clk MW8 ffffffff00000100 00000000_22222222 (ABORTED)
43727 clk MW8 00000100 00000000_00000000 (ABORTED)
43727 clk R cpsr 004003c5
43727 clk R FAR_EL1 ffffffff00000100
43727 clk R ELR_EL1 0000000080000954
43727 clk R SPSR_EL1 0000000000000005
43727 clk R ESR_EL1 0000000096000068
- Scenario Analysis: We demonstrate how the OS/Monitor identifies the cause of the fault (e.g., misconfiguration or unauthorized access) using the fault status registers.
- GPF Localization: Using the GPC mechanism to pinpoint the exact physical granule that caused the violation.
43727 clk R cpsr 004003c5
43727 clk R FAR_EL1 ffffffff00000100
43727 clk R ELR_EL1 0000000080000954
43727 clk R SPSR_EL1 0000000000000005
43727 clk R ESR_EL1 0000000096000068
Current Program Status Register (CPSR)
- The Current Program Status Register (CPSR) holds processor status and control information.
- 0x4003c5
- A[8] = 0x1
- I[7] = 0x1
- F[6] = 0x1
- M[3:0] = 0x5(EL1h)
- 0x4003c5
FAR_EL1, Fault Address Register (EL1)
- Holds the faulting Virtual Address for all synchronous exceptions that are taken to EL1.
- 0xffffffff00000100
ELR_EL1, Exception Link Register (EL1)
- When taking an exception to EL1, holds the address to return to.
- 0x80000954
80000954: f9000020 str x0, [x1]
- 0x80000954
ESR_EL1, Exception Syndrome Register (EL1)
- Holds syndrome information for an exception taken to EL1.
- 0x96000068
- EC (bits 31:26) = 0x25(Data Abort)
- WnR (bit 6) = 1, Write
- DFSC (bits 5:0) = 0x28(Granule Protection Fault)
- 0x96000068
SPSR_EL1, Saved Program Status Register (EL1)
- Holds the saved PE state when an exception is taken to EL1.
- 0x5
- M[3:0] = 0x5(EL1h)
- 0x5