https://github.com/lupyuen/nuttx-arm64-emulator
Emulate Apache NuttX RTOS for Arm64 with Unicorn Emulator (Avaota-A1 SBC)
https://github.com/lupyuen/nuttx-arm64-emulator
allwinner-t527 arm64 assembly avaota-a1 emulator nuttx pinephone qemu rust unicorn-emulator
Last synced: about 1 year ago
JSON representation
Emulate Apache NuttX RTOS for Arm64 with Unicorn Emulator (Avaota-A1 SBC)
- Host: GitHub
- URL: https://github.com/lupyuen/nuttx-arm64-emulator
- Owner: lupyuen
- License: apache-2.0
- Created: 2023-02-18T13:49:03.000Z (over 3 years ago)
- Default Branch: main
- Last Pushed: 2025-03-31T02:20:29.000Z (about 1 year ago)
- Last Synced: 2025-03-31T02:26:01.344Z (about 1 year ago)
- Topics: allwinner-t527, arm64, assembly, avaota-a1, emulator, nuttx, pinephone, qemu, rust, unicorn-emulator
- Language: Assembly
- Homepage: https://lupyuen.org/articles/unicorn3.html
- Size: 141 MB
- Stars: 40
- Watchers: 4
- Forks: 4
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- License: LICENSE
Awesome Lists containing this project
README
# Unicorn Emulator for Apache NuttX RTOS on Avaota-A1 Arm64 SBC
See https://github.com/lupyuen/nuttx-arm64-emulator/tree/avaota
# Unicorn Emulator for Apache NuttX RTOS on QEMU Arm64
See https://github.com/lupyuen/nuttx-arm64-emulator/tree/qemu
# Emulate PinePhone with Unicorn Emulator
Read the articles...
- ["Inside Arm64 MMU: Unicorn Emulator vs Apache NuttX RTOS"](https://lupyuen.org/articles/unicorn3.html)
- ["(Possibly) Emulate PinePhone with Unicorn Emulator"](https://lupyuen.org/articles/unicorn.html)
- ["(Clickable) Call Graph for Apache NuttX Real-Time Operating System"](https://lupyuen.org/articles/unicorn2.html)
We're porting a new operating system ([Apache NuttX RTOS](https://lupyuen.github.io/articles/what)) to [Pine64 PinePhone](https://wiki.pine64.org/index.php/PinePhone). And I wondered...
_To make PinePhone testing easier..._
_Can we emulate Arm64 PinePhone with [Unicorn Emulator](https://www.unicorn-engine.org/)?_
Let's find out! We'll call the [Unicorn Emulator](https://www.unicorn-engine.org/) in Rust (instead of C).
(Because I'm too old to write meticulous C... But I'm OK to get nagged by Rust Compiler if I miss something!)
We begin by emulating simple Arm64 Machine Code...
# Emulate Arm64 Machine Code

Suppose we wish to emulate some Arm64 Machine Code...
https://github.com/lupyuen/nuttx-arm64-emulator/blob/bc5643dea66c70f57a150955a12884f695acf1a4/src/main.rs#L7-L8
Here's our Rust Program that calls Unicorn Emulator to emulate the Arm64 Machine Code...
https://github.com/lupyuen/nuttx-arm64-emulator/blob/bc5643dea66c70f57a150955a12884f695acf1a4/src/main.rs#L1-L55
We add `unicorn-engine` to [Cargo.toml](Cargo.toml)...
https://github.com/lupyuen/nuttx-arm64-emulator/blob/bc5643dea66c70f57a150955a12884f695acf1a4/Cargo.toml#L8-L9
And we run our Rust Program...
```text
→ cargo run --verbose
Fresh cc v1.0.79
Fresh cmake v0.1.49
Fresh pkg-config v0.3.26
Fresh bitflags v1.3.2
Fresh libc v0.2.139
Fresh unicorn-engine v2.0.1
Fresh nuttx-arm64-emulator v0.1.0
Finished dev [unoptimized + debuginfo] target(s) in 0.08s
Running `target/debug/nuttx-arm64-emulator`
```
Our Rust Program works OK for emulating Arm64 Memory and Arm64 Registers.
Let's talk about Arm64 Memory-Mapped Input / Output...
# Memory Access Hook for Arm64 Emulation

_How will we emulate Arm64 Memory-Mapped Input / Output?_
Unicorn Emulator lets us attach hooks to Emulate Memory Access.
Here's a Hook Function for Memory Access...
https://github.com/lupyuen/nuttx-arm64-emulator/blob/3655ac2875664376f42ad3a3ced5cbf067790782/src/main.rs#L83-L95
Our Hook Function prints all Read / Write Access to Emulated Arm64 Memory.
[(Return value is unused)](https://github.com/unicorn-engine/unicorn/blob/dev/docs/FAQ.md#i-cant-recover-from-unmapped-readwrite-even-i-return-true-in-the-hook-why)
This is how we attach the Hook Function to the Unicorn Emulator...
https://github.com/lupyuen/nuttx-arm64-emulator/blob/3655ac2875664376f42ad3a3ced5cbf067790782/src/main.rs#L59-L74
When we run our Rust Program, we see the Read and Write Memory Accesses made by our [Emulated Arm64 Code](https://github.com/lupyuen/nuttx-arm64-emulator/blob/bc5643dea66c70f57a150955a12884f695acf1a4/src/main.rs#L7-L8)...
```text
hook_memory:
mem_type=WRITE,
address=0x10008,
size=4,
value=0x12345678
hook_memory:
mem_type=READ,
address=0x10008,
size=1,
value=0x0
```
This Memory Access Hook Function will be helpful when we emulate Memory-Mapped Input/Output on PinePhone.
(Like for the Allwinner A64 UART Controller)
Unicorn Emulator allows Code Execution Hooks too...
# Code Execution Hook for Arm64 Emulation

_Can we intercept every Arm64 Instruction that will be emulated?_
Yep we can call Unicorn Emulator to add a Code Execution Hook.
Here's a sample Hook Function that will be called for every Arm64 Instruction...
https://github.com/lupyuen/nuttx-arm64-emulator/blob/3655ac2875664376f42ad3a3ced5cbf067790782/src/main.rs#L108-L117
And this is how we call Unicorn Emulator to add the above Hook Function...
https://github.com/lupyuen/nuttx-arm64-emulator/blob/3655ac2875664376f42ad3a3ced5cbf067790782/src/main.rs#L52-L57
When we run our Rust Program, we see the Address of every Arm64 Instruction emulated (and its size)...
```text
hook_code:
address=0x10000,
size=4
hook_code:
address=0x10004,
size=4
```
We might use this to emulate special Arm64 Instructions.
If we don't need to intercept every single instruction, try the Block Execution Hook...
# Block Execution Hook for Arm64 Emulation
_Is there something that works like a Code Execution Hook..._
_But doesn't stop at every single Arm64 Instruction?_
Yep Unicorn Emulator supports Block Execution Hooks.
This Hook Function will be called once when executing a Block of Arm64 Instructions...
https://github.com/lupyuen/nuttx-arm64-emulator/blob/3655ac2875664376f42ad3a3ced5cbf067790782/src/main.rs#L97-L106
This is how we add the Block Execution Hook...
https://github.com/lupyuen/nuttx-arm64-emulator/blob/3655ac2875664376f42ad3a3ced5cbf067790782/src/main.rs#L48-L50
When we run the Rust Program, we see that that the Block Size is 8...
```text
hook_block:
address=0x10000,
size=8
```
Which means that Unicorn Emulator calls our Hook Function only once for the entire Block of 2 Arm64 Instructions.
This Block Execution Hook will be super helpful for monitoring the Execution Flow of our emulated code.
Let's talk about the Block...
# What is a Block of Arm64 Instructions?
_What exactly is a Block of Arm64 Instructions?_
When we run this code from Apache NuttX RTOS (that handles UART Output)...
```text
SECTION_FUNC(text, up_lowputc)
ldr x15, =UART0_BASE_ADDRESS
400801f0: 580000cf ldr x15, 40080208
nuttx/arch/arm64/src/chip/a64_lowputc.S:89
early_uart_ready x15, w2
400801f4: 794029e2 ldrh w2, [x15, #20]
400801f8: 721b005f tst w2, #0x20
400801fc: 54ffffc0 b.eq 400801f4 // b.none
nuttx/arch/arm64/src/chip/a64_lowputc.S:90
early_uart_transmit x15, w0
40080200: 390001e0 strb w0, [x15]
nuttx/arch/arm64/src/chip/a64_lowputc.S:91
ret
40080204: d65f03c0 ret
```
[(Arm64 Disassembly)](https://github.com/lupyuen/nuttx-arm64-emulator/blob/a1fb82d829856d86d6845c477709c2be24373aca/nuttx/nuttx.S#L3398-L3411)
[(Source Code)](https://github.com/apache/nuttx/blob/master/arch/arm64/src/a64/a64_lowputc.S#L61-L71)
We observe that Unicorm Emulator treats `400801f0` to `400801fc` as a Block of Arm64 Instructins...
```text
hook_block: address=0x400801f0, size=16
hook_code: address=0x400801f0, size=4
hook_code: address=0x400801f4, size=4
hook_code: address=0x400801f4, size=4
hook_code: address=0x400801f8, size=4
hook_code: address=0x400801fc, size=4
hook_block: address=0x400801f4, size=12
hook_code: address=0x400801f4, size=4
hook_code: address=0x400801f8, size=4
hook_code: address=0x400801fc, size=4
hook_block: address=0x400801f4, size=12
hook_code: address=0x400801f4, size=4
hook_code: address=0x400801f8, size=4
hook_code: address=0x400801fc, size=4
```
[(Source)](https://github.com/lupyuen/nuttx-arm64-emulator/blob/cd030954c2ace4cf0207872f275abc3ffb7343c6/README.md#block-execution-hooks-for-arm64-emulation)
The Block ends at `400801fc` because there's an Arm64 Branch Instruction `b.eq`.
From this we deduce that Unicorn Emulator treats a sequence of Arm64 Instructions as a Block, until it sees a Branch Instruction. (Including function calls)
# Unmapped Memory in Unicorn Emulator
_What happens when Unicorn Emulator tries to access memory that isn't mapped?_
Unicorn Emulator will call our Memory Access Hook with `mem_type` set to `READ_UNMAPPED`...
```text
hook_memory:
address=0x01c28014,
size=2,
mem_type=READ_UNMAPPED,
value=0x0
```
[(Source)](https://github.com/lupyuen/nuttx-arm64-emulator/blob/b842358ba457b67ffa9f4c1a362b0386cfd97c4a/README.md#block-execution-hooks-for-arm64-emulation)
The log above says that address `0x01c2` `8014` is unmapped.
This is how we map the memory...
https://github.com/lupyuen/nuttx-arm64-emulator/blob/cd030954c2ace4cf0207872f275abc3ffb7343c6/src/main.rs#L26-L32
[(See the NuttX Memory Map)](https://github.com/apache/nuttx/blob/master/arch/arm64/include/a64/chip.h#L44-L52)
_Can we map Memory Regions during emulation?_
Yep we may use a Memory Access Hook to map memory regions on the fly. [(See this)](https://github.com/unicorn-engine/unicorn/blob/dev/docs/FAQ.md#i-cant-recover-from-unmapped-readwrite-even-i-return-true-in-the-hook-why)
# Run Apache NuttX RTOS in Unicorn Emulator

Let's run Apache NuttX RTOS in Unicorn Emulator!
We have compiled [Apache NuttX RTOS for PinePhone](nuttx) into an Arm64 Binary Image `nuttx.bin`.
This is how we load the NuttX Binary Image into Unicorn...
https://github.com/lupyuen/nuttx-arm64-emulator/blob/aa24d1c61256f38f92cf627d52c3e9a0c189bfc6/src/main.rs#L6-L40
In our Rust Program above, we mapped 2 Memory Regions for NuttX...
- Map 128 MB Executable Memory at `0x4000` `0000` for Arm64 Machine Code
- Map 512 MB Read/Write Memory at `0x0000` `0000` for Memory-Mapped I/O by Allwinner A64 Peripherals
This is based on the [NuttX Memory Map](https://github.com/apache/nuttx/blob/master/arch/arm64/include/a64/chip.h#L44-L52) for PinePhone.
When we run this, Unicorn Emulator loops forever. Let's find out why...
# Unicorn Emulator Waits Forever for UART Controller Ready

Here's the output when we run NuttX RTOS in Unicorn Emulator...
```text
hook_memory: address=0x01c28014, size=2, mem_type=READ, value=0x0
hook_code: address=0x400801f8, size=4
hook_code: address=0x400801fc, size=4
hook_block: address=0x400801f4, size=12
hook_code: address=0x400801f4, size=4
hook_memory: address=0x01c28014, size=2, mem_type=READ, value=0x0
hook_code: address=0x400801f8, size=4
hook_code: address=0x400801fc, size=4
hook_block: address=0x400801f4, size=12
hook_code: address=0x400801f4, size=4
hook_memory: address=0x01c28014, size=2, mem_type=READ, value=0x0
hook_code: address=0x400801f8, size=4
hook_code: address=0x400801fc, size=4
hook_block: address=0x400801f4, size=12
hook_code: address=0x400801f4, size=4
...
```
[(Source)](https://github.com/lupyuen/nuttx-arm64-emulator/blob/045fa5da84d9e07ead5a820a075c1445661328b6/README.md#unicorn-emulator-waits-forever-for-uart-controller-ready)
The above log shows that Unicorn Emulator loops forever at address `0x4008` `01f4`, while reading the data from address `0x01c2` `8014`.
Let's check the NuttX Arm64 Code at address `0x4008` `01f4`...
```text
SECTION_FUNC(text, up_lowputc)
ldr x15, =UART0_BASE_ADDRESS
400801f0: 580000cf ldr x15, 40080208
nuttx/arch/arm64/src/chip/a64_lowputc.S:89
early_uart_ready x15, w2
400801f4: 794029e2 ldrh w2, [x15, #20]
400801f8: 721b005f tst w2, #0x20
400801fc: 54ffffc0 b.eq 400801f4 // b.none
nuttx/arch/arm64/src/chip/a64_lowputc.S:90
early_uart_transmit x15, w0
40080200: 390001e0 strb w0, [x15]
nuttx/arch/arm64/src/chip/a64_lowputc.S:91
ret
40080204: d65f03c0 ret
```
[(Arm64 Disassembly)](https://github.com/lupyuen/nuttx-arm64-emulator/blob/a1fb82d829856d86d6845c477709c2be24373aca/nuttx/nuttx.S#L3398-L3411)
Which comes from this NuttX Source Code...
```text
/* Wait for A64 UART to be ready to transmit
* xb: Register that contains the UART Base Address
* wt: Scratch register number
*/
.macro early_uart_ready xb, wt
1:
ldrh \wt, [\xb, #0x14] /* UART_LSR (Line Status Register) */
tst \wt, #0x20 /* Check THRE (TX Holding Register Empty) */
b.eq 1b /* Wait for the UART to be ready (THRE=1) */
.endm
```
[(Source Code)](https://github.com/apache/nuttx/blob/master/arch/arm64/src/a64/a64_lowputc.S#L61-L71)
This code waits for the UART Controller to be ready (before printing UART Output), by checking the value at `0x01c2` `8014`. The code is explained here...
- ["Wait for UART Ready"](https://lupyuen.github.io/articles/uboot#wait-for-uart-ready)
_What is `0x01c2` `8014`?_
According to the Allwinner A64 Doc...
- ["Wait To Transmit"](https://lupyuen.github.io/articles/serial#wait-to-transmit)
`0x01c2` `8014` is the UART Line Status Register (UART_LSR) at Offset 0x14.
Bit 5 needs to be set to 1 to indicate that the UART Transmit FIFO is ready.
We emulate the UART Ready Bit like so...
https://github.com/lupyuen/nuttx-arm64-emulator/blob/4d78876ad6f40126bf68cb2da4a43f56d9ef6e76/src/main.rs#L42-L49
And Unicorn Emulator stops looping! It continues execution to `memset()` (to init the BSS Section to 0)...
```text
hook_block: address=0x40089328, size=8
hook_memory: address=0x400b6a52, size=1, mem_type=WRITE, value=0x0
hook_block: address=0x40089328, size=8
hook_memory: address=0x400b6a53, size=1, mem_type=WRITE, value=0x0
hook_block: address=0x40089328, size=8
hook_memory: address=0x400b6a54, size=1, mem_type=WRITE, value=0x0
...
```
[(Source)](https://github.com/lupyuen/nuttx-arm64-emulator/blob/045fa5da84d9e07ead5a820a075c1445661328b6/README.md#unicorn-emulator-waits-forever-for-uart-controller-ready)
But we don't see any UART Output. Let's print the UART Output...
# Emulate UART Output in Unicorn Emulator

_How do we print the UART Output?_
According to the Allwinner A64 Doc...
- ["Transmit UART"](https://lupyuen.github.io/articles/serial#transmit-uart)
NuttX RTOS will write the UART Output to the UART Transmit Holding Register (THR) at `0x01c2` `8000`.
In our Memory Access Hook, let's intercept all writes to `0x01c2` `8000` and dump the characters written to UART Output...
https://github.com/lupyuen/nuttx-arm64-emulator/blob/aa6dd986857231a935617e8346978d7750aa51e7/src/main.rs#L89-L111
When we run this, we see a long chain of UART Output...
```text
→ cargo run | grep uart
uart output: '-'
uart output: ' '
uart output: 'R'
uart output: 'e'
uart output: 'a'
uart output: 'd'
uart output: 'y'
...
```
[(Source)](https://gist.github.com/lupyuen/587dbeb9329d9755e4d007dd8e1246cd)
Which reads as...
```text
- Ready to Boot CPU
- Boot from EL2
- Boot from EL1
- Boot to C runtime for OS Initialize
```
[(Similar to this)](https://lupyuen.github.io/articles/uboot#pinephone-boots-nuttx)
Yep NuttX RTOS is booting on Unicorn Emulator! But Unicorn Emulator halts while booting NuttX...
# Unicorn Emulator Halts in NuttX MMU
Unicorn Emulator halts with an __Arm64 Exception__ at address __`4008` `0EF8`__...
```text
hook_block: address=0x40080cec, size=16
hook_code: address=0x40080cec, size=4
hook_memory: address=0x400c3f90, size=8, mem_type=READ, value=0x0
hook_memory: address=0x400c3f98, size=8, mem_type=READ, value=0x0
hook_code: address=0x40080cf0, size=4
hook_memory: address=0x400c3fa0, size=8, mem_type=READ, value=0x0
hook_code: address=0x40080cf4, size=4
hook_memory: address=0x400c3f80, size=8, mem_type=READ, value=0x0
hook_memory: address=0x400c3f88, size=8, mem_type=READ, value=0x0
hook_code: address=0x40080cf8, size=4
hook_block: address=0x40080eb0, size=12
hook_code: address=0x40080eb0, size=4
hook_code: address=0x40080eb4, size=4
hook_code: address=0x40080eb8, size=4
hook_block: address=0x40080ebc, size=16
hook_code: address=0x40080ebc, size=4
hook_code: address=0x40080ec0, size=4
hook_code: address=0x40080ec4, size=4
hook_code: address=0x40080ec8, size=4
hook_block: address=0x40080ecc, size=16
hook_code: address=0x40080ecc, size=4
hook_code: address=0x40080ed0, size=4
hook_code: address=0x40080ed4, size=4
hook_code: address=0x40080ed8, size=4
hook_block: address=0x40080edc, size=12
hook_code: address=0x40080edc, size=4
hook_code: address=0x40080ee0, size=4
hook_code: address=0x40080ee4, size=4
hook_block: address=0x40080ee8, size=4
hook_code: address=0x40080ee8, size=4
hook_block: address=0x40080eec, size=16
hook_code: address=0x40080eec, size=4
hook_code: address=0x40080ef0, size=4
hook_code: address=0x40080ef4, size=4
hook_code: address=0x40080ef8, size=4
err=Err(EXCEPTION)
```
[(See the Complete Log)](https://gist.github.com/lupyuen/778f15875edf632ccb5a093a656084cb)
Unicorn Emulator halts at the NuttX MMU (EL1) code at `0x4008` `0ef8`...
```text
nuttx/arch/arm64/src/common/arm64_mmu.c:544
write_sysreg((value | SCTLR_M_BIT | SCTLR_C_BIT), sctlr_el1);
40080ef0: d28000a1 mov x1, #0x5 // #5
40080ef4: aa010000 orr x0, x0, x1
40080ef8: d5181000 msr sctlr_el1, x0
```
_Why did MSR fail with an Exception?_
Here's the context...
```text
enable_mmu_el1():
nuttx/arch/arm64/src/common/arm64_mmu.c:533
write_sysreg(MEMORY_ATTRIBUTES, mair_el1);
40080ebc: d2808000 mov x0, #0x400 // #1024
40080ec0: f2a88180 movk x0, #0x440c, lsl #16
40080ec4: f2c01fe0 movk x0, #0xff, lsl #32
40080ec8: d518a200 msr mair_el1, x0
nuttx/arch/arm64/src/common/arm64_mmu.c:534
write_sysreg(get_tcr(1), tcr_el1);
40080ecc: d286a380 mov x0, #0x351c // #13596
40080ed0: f2a01000 movk x0, #0x80, lsl #16
40080ed4: f2c00020 movk x0, #0x1, lsl #32
40080ed8: d5182040 msr tcr_el1, x0
nuttx/arch/arm64/src/common/arm64_mmu.c:535
write_sysreg(((uint64_t)base_xlat_table), ttbr0_el1);
40080edc: d00001a0 adrp x0, 400b6000
40080ee0: 91200000 add x0, x0, #0x800
40080ee4: d5182000 msr ttbr0_el1, x0
arm64_isb():
nuttx/arch/arm64/src/common/barriers.h:58
__asm__ volatile ("isb" : : : "memory");
40080ee8: d5033fdf isb
enable_mmu_el1():
nuttx/arch/arm64/src/common/arm64_mmu.c:543
value = read_sysreg(sctlr_el1);
40080eec: d5381000 mrs x0, sctlr_el1
nuttx/arch/arm64/src/common/arm64_mmu.c:544
write_sysreg((value | SCTLR_M_BIT | SCTLR_C_BIT), sctlr_el1);
40080ef0: d28000a1 mov x1, #0x5 // #5
40080ef4: aa010000 orr x0, x0, x1
40080ef8: d5181000 msr sctlr_el1, x0
arm64_isb():
nuttx/arch/arm64/src/common/barriers.h:58
40080efc: d5033fdf isb
```
Which comes from this __NuttX Source Code__: [arm64_mmu.c](https://github.com/apache/nuttx/blob/master/arch/arm64/src/common/arm64_mmu.c#L541-L544)
```c
// Enable the MMU and data cache:
// Read from System Control Register EL1
value = read_sysreg(sctlr_el1);
// Write to System Control Register EL1
write_sysreg( // Write to System Register...
value | SCTLR_M_BIT | SCTLR_C_BIT, // Enable Address Translation and Caching
sctlr_el1 // System Control Register EL1
);
```
Let's dump the Arm64 Exception...
# Dump the Arm64 Exception
To find out the cause of the Arm64 Exception, let's dump the Exception Syndrome Register (ESR).
But this won't work...
https://github.com/lupyuen/nuttx-arm64-emulator/blob/1cbfa48de10ef4735ebaf91ab85631cb48e37591/src/main.rs#L86-L91
Because `ESR_EL` is [no longer supported](https://github.com/unicorn-engine/unicorn/blob/master/bindings/rust/src/arm64.rs#L288-L307) and `CP_REG` can't be read in Rust...
```text
err=Err(EXCEPTION)
CP_REG=Err(ARG)
ESR_EL0=Ok(0)
ESR_EL1=Ok(0)
ESR_EL2=Ok(0)
ESR_EL3=Ok(0)
```
[(See the Complete Log)](https://gist.github.com/lupyuen/778f15875edf632ccb5a093a656084cb)
`CP_REG` can't be read in Rust because Unicorn needs a pointer to `uc_arm64_cp_reg`...
```c
static uc_err reg_read(CPUARMState *env, unsigned int regid, void *value) {
...
case UC_ARM64_REG_CP_REG:
ret = read_cp_reg(env, (uc_arm64_cp_reg *)value);
break;
```
[(Source)](https://github.com/unicorn-engine/unicorn/blob/master/qemu/target/arm/unicorn_aarch64.c#L225-L227)
Which isn't supported by the [Rust Bindings](https://github.com/unicorn-engine/unicorn/blob/master/bindings/rust/src/lib.rs#L528-L543).
[(Works in Python though)](https://github.com/unicorn-engine/unicorn/blob/master/bindings/python/sample_arm64.py#L76-L82)
So instead we set a breakpoint at `arm64_reg_read()` (pic below) in...
```text
.cargo/registry/src/github.com-1ecc6299db9ec823/unicorn-engine-2.0.1/qemu/target/arm/unicorn_aarch64.c
```
(`arm64_reg_read()` calls `reg_read()` in unicorn_aarch64.c)
Which shows the Exception as...
```text
env.exception = {
syndrome: 0x8600 003f,
fsr: 5,
vaddress: 0x400c 3fff,
target_el: 1
}
```
Let's study the Arm64 Exception...

# Arm64 MMU Exception
Earlier we saw this Arm64 Exception in Unicorn Emulator...
```text
env.exception = {
syndrome: 0x8600 003f,
fsr: 5,
vaddress: 0x400c 3fff,
target_el: 1
}
```
TODO: What is address `0x400c` `3fff`?
_What is Syndrome 0x8600 003f?_
Bits 26-31 of Syndrome = 0b100001, which means...
> 0b100001: Instruction Abort taken without a change in Exception level.
> Used for MMU faults generated by instruction accesses and synchronous External aborts, including synchronous parity or ECC errors. Not used for debug-related exceptions.
[(Source)](https://developer.arm.com/documentation/ddi0601/2022-03/AArch64-Registers/ESR-EL1--Exception-Syndrome-Register--EL1-)
_What is FSR 5?_
FSR 5 means...
> 0b00101: Translation Fault (in) Section
[(Source)](https://developer.arm.com/documentation/ddi0500/d/system-control/aarch64-register-descriptions/instruction-fault-status-register--el2)
_Why the MMU Fault?_
Unicorn Emulator triggers the exception when NuttX writes to SCTLR_EL1...
```c
/* Enable the MMU and data cache */
value = read_sysreg(sctlr_el1);
write_sysreg((value | SCTLR_M_BIT | SCTLR_C_BIT), sctlr_el1);
```
[(Source)](https://github.com/apache/nuttx/blob/master/arch/arm64/src/common/arm64_mmu.c#L541-L544)
The above code sets these flags in SCTLR_EL1 (System Control Register EL1)...
- SCTLR_M_BIT (Bit 0): Enable Address Translation for EL0 and EL1 Stage 1
- SCTLR_C_BIT (Bit 2): Enable Caching for EL0 and EL1 Stage 1
[(More about SCTLR_EL1)](https://developer.arm.com/documentation/ddi0595/2021-06/AArch64-Registers/SCTLR-EL1--System-Control-Register--EL1-)
TODO: Why did the Address Translation (or Caching) fail?
TODO: Should we skip the MMU Update to SCTLR_EL1? Since we don't use MMU?
# Debug the Unicorn Emulator
_To troubleshoot the Arm64 MMU Exception..._
_Can we use a debugger to step through Unicorn Emulator?_
Yes but it gets messy.
To trace the exception in the debugger. Look for...
```text
$HOME/.cargo/registry/src/github.com-1ecc6299db9ec823/unicorn-engine-2.0.1/qemu/target/arm/translate-a64.c
```
Set a breakpoint in `aarch64_tr_translate_insn()`
- Which calls `disas_b_exc_sys()`
- Which calls `disas_system()`
- Which calls `handle_sys()` to handle system instructions
To inspect the Emulator Settings, set a breakpoint at `cpu_aarch64_init()` in...
```text
$HOME/.cargo/registry/src/github.com-1ecc6299db9ec823/unicorn-engine-2.0.1/qemu/target/arm/cpu64.c
```
TODO: Check that the CPU Setting is correct for PinePhone. (CPU Model should be Cortex-A53)
# Map Address to Function with ELF File
Read the article...
- ["(Clickable) Call Graph for Apache NuttX Real-Time Operating System"](https://lupyuen.github.io/articles/unicorn2)
Our __Block Execution Hook__ now prints the __Function Name__ and the __Filename__...
```text
hook_block:
address=0x40080eb0,
size=12,
setup_page_tables,
arch/arm64/src/common/arm64_mmu.c:516:25
hook_block:
address=0x40080eec,
size=16,
enable_mmu_el1,
arch/arm64/src/common/arm64_mmu.c:543:11
err=Err(EXCEPTION)
```
[(Source)](https://gist.github.com/lupyuen/f2e883b2b8054d75fbac7de661f0ee5a)
Our Hook Function looks up the Address in the [__DWARF Debug Symbols__](https://crates.io/crates/gimli) of the [__NuttX ELF File__](https://github.com/lupyuen/nuttx-arm64-emulator/blob/main/nuttx/nuttx).
This is explained here...
- ["Map Address to Function with ELF File"](https://lupyuen.github.io/articles/unicorn#appendix-map-address-to-function-with-elf-file)
# Call Graph for Apache NuttX RTOS
To troubleshoot the Apache NuttX MMU Fault on Unicorn Emulator, we auto-generated this Call Graph...
(To see the NuttX Source Code: Right-click the Node and select "Open Link")
```mermaid
flowchart TD
START --> arm64_head
arm64_head --> a64_lowputc
click arm64_head href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_head.S#L104" "arch/arm64/src/common/arm64_head.S " _blank
a64_lowputc --> arm64_head
click a64_lowputc href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/a64/a64_lowputc.S#L58" "arch/arm64/src/a64/a64_lowputc.S " _blank
arm64_head --> a64_lowputc
click arm64_head href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_head.S#L177" "arch/arm64/src/common/arm64_head.S " _blank
a64_lowputc --> arm64_head
click a64_lowputc href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/a64/a64_lowputc.S#L87" "arch/arm64/src/a64/a64_lowputc.S " _blank
arm64_head --> a64_lowputc
click arm64_head href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_head.S#L298" "arch/arm64/src/common/arm64_head.S " _blank
a64_lowputc --> arm64_head
click a64_lowputc href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/a64/a64_lowputc.S#L87" "arch/arm64/src/a64/a64_lowputc.S " _blank
arm64_head --> a64_lowputc
click arm64_head href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_head.S#L298" "arch/arm64/src/common/arm64_head.S " _blank
a64_lowputc --> arm64_head
click a64_lowputc href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/a64/a64_lowputc.S#L87" "arch/arm64/src/a64/a64_lowputc.S " _blank
arm64_head --> a64_lowputc
click arm64_head href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_head.S#L298" "arch/arm64/src/common/arm64_head.S " _blank
a64_lowputc --> arm64_head
click a64_lowputc href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/a64/a64_lowputc.S#L87" "arch/arm64/src/a64/a64_lowputc.S " _blank
arm64_head --> a64_lowputc
click arm64_head href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_head.S#L298" "arch/arm64/src/common/arm64_head.S " _blank
a64_lowputc --> arm64_head
click a64_lowputc href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/a64/a64_lowputc.S#L87" "arch/arm64/src/a64/a64_lowputc.S " _blank
arm64_head --> a64_lowputc
click arm64_head href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_head.S#L298" "arch/arm64/src/common/arm64_head.S " _blank
a64_lowputc --> arm64_head
click a64_lowputc href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/a64/a64_lowputc.S#L87" "arch/arm64/src/a64/a64_lowputc.S " _blank
arm64_head --> a64_lowputc
click arm64_head href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_head.S#L298" "arch/arm64/src/common/arm64_head.S " _blank
arm64_head --> arm64_boot_el1_init
click arm64_head href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_head.S#L298" "arch/arm64/src/common/arm64_head.S " _blank
arm64_boot_el1_init --> arm64_isb
click arm64_boot_el1_init href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_boot.c#L137" "arch/arm64/src/common/arm64_boot.c " _blank
arm64_isb --> arm64_boot_el1_init
click arm64_isb href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/barriers.h#L57" "arch/arm64/src/common/barriers.h " _blank
arm64_boot_el1_init --> arm64_isb
click arm64_boot_el1_init href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_boot.c#L145" "arch/arm64/src/common/arm64_boot.c " _blank
arm64_isb --> arm64_boot_el1_init
click arm64_isb href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/barriers.h#L57" "arch/arm64/src/common/barriers.h " _blank
arm64_head --> arm64_boot_primary_c_routine
click arm64_head href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_head.S#L298" "arch/arm64/src/common/arm64_head.S " _blank
arm64_boot_primary_c_routine --> memset
click arm64_boot_primary_c_routine href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_boot.c#L180" "arch/arm64/src/common/arm64_boot.c " _blank
memset --> arm64_boot_primary_c_routine
click memset href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/libs/libc/string/lib_memset.c#L168" "libs/libc/string/lib_memset.c " _blank
arm64_boot_primary_c_routine --> arm64_chip_boot
click arm64_boot_primary_c_routine href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_boot.c#L181" "arch/arm64/src/common/arm64_boot.c " _blank
arm64_chip_boot --> arm64_mmu_init
click arm64_chip_boot href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/a64/a64_boot.c#L81" "arch/arm64/src/a64/a64_boot.c " _blank
arm64_mmu_init --> setup_page_tables
click arm64_mmu_init href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L583" "arch/arm64/src/common/arm64_mmu.c " _blank
setup_page_tables --> init_xlat_tables
click setup_page_tables href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L490" "arch/arm64/src/common/arm64_mmu.c " _blank
init_xlat_tables --> calculate_pte_index
click init_xlat_tables href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L417" "arch/arm64/src/common/arm64_mmu.c " _blank
calculate_pte_index --> init_xlat_tables
click calculate_pte_index href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L246" "arch/arm64/src/common/arm64_mmu.c " _blank
init_xlat_tables --> pte_desc_type
click init_xlat_tables href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L447" "arch/arm64/src/common/arm64_mmu.c " _blank
pte_desc_type --> new_prealloc_table
click pte_desc_type href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L234" "arch/arm64/src/common/arm64_mmu.c " _blank
new_prealloc_table --> init_xlat_tables
click new_prealloc_table href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L378" "arch/arm64/src/common/arm64_mmu.c " _blank
init_xlat_tables --> calculate_pte_index
click init_xlat_tables href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L437" "arch/arm64/src/common/arm64_mmu.c " _blank
calculate_pte_index --> pte_desc_type
click calculate_pte_index href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L246" "arch/arm64/src/common/arm64_mmu.c " _blank
pte_desc_type --> calculate_pte_index
click pte_desc_type href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L234" "arch/arm64/src/common/arm64_mmu.c " _blank
calculate_pte_index --> init_xlat_tables
click calculate_pte_index href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L247" "arch/arm64/src/common/arm64_mmu.c " _blank
init_xlat_tables --> set_pte_block_desc
click init_xlat_tables href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L447" "arch/arm64/src/common/arm64_mmu.c " _blank
set_pte_block_desc --> init_xlat_tables
click set_pte_block_desc href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L293" "arch/arm64/src/common/arm64_mmu.c " _blank
init_xlat_tables --> calculate_pte_index
click init_xlat_tables href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L456" "arch/arm64/src/common/arm64_mmu.c " _blank
calculate_pte_index --> init_xlat_tables
click calculate_pte_index href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L246" "arch/arm64/src/common/arm64_mmu.c " _blank
init_xlat_tables --> pte_desc_type
click init_xlat_tables href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L447" "arch/arm64/src/common/arm64_mmu.c " _blank
pte_desc_type --> init_xlat_tables
click pte_desc_type href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L234" "arch/arm64/src/common/arm64_mmu.c " _blank
init_xlat_tables --> calculate_pte_index
click init_xlat_tables href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L472" "arch/arm64/src/common/arm64_mmu.c " _blank
calculate_pte_index --> pte_desc_type
click calculate_pte_index href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L246" "arch/arm64/src/common/arm64_mmu.c " _blank
pte_desc_type --> calculate_pte_index
click pte_desc_type href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L234" "arch/arm64/src/common/arm64_mmu.c " _blank
calculate_pte_index --> init_xlat_tables
click calculate_pte_index href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L247" "arch/arm64/src/common/arm64_mmu.c " _blank
init_xlat_tables --> set_pte_block_desc
click init_xlat_tables href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L447" "arch/arm64/src/common/arm64_mmu.c " _blank
init_xlat_tables --> calculate_pte_index
click init_xlat_tables href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L456" "arch/arm64/src/common/arm64_mmu.c " _blank
init_xlat_tables --> pte_desc_type
click init_xlat_tables href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L447" "arch/arm64/src/common/arm64_mmu.c " _blank
init_xlat_tables --> calculate_pte_index
click init_xlat_tables href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L472" "arch/arm64/src/common/arm64_mmu.c " _blank
calculate_pte_index --> pte_desc_type
click calculate_pte_index href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L246" "arch/arm64/src/common/arm64_mmu.c " _blank
init_xlat_tables --> set_pte_block_desc
click init_xlat_tables href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L447" "arch/arm64/src/common/arm64_mmu.c " _blank
init_xlat_tables --> pte_desc_type
click init_xlat_tables href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L447" "arch/arm64/src/common/arm64_mmu.c " _blank
calculate_pte_index --> pte_desc_type
click calculate_pte_index href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L246" "arch/arm64/src/common/arm64_mmu.c " _blank
init_xlat_tables --> set_pte_block_desc
click init_xlat_tables href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L447" "arch/arm64/src/common/arm64_mmu.c " _blank
init_xlat_tables --> set_pte_block_desc
click init_xlat_tables href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L447" "arch/arm64/src/common/arm64_mmu.c " _blank
init_xlat_tables --> set_pte_block_desc
click init_xlat_tables href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L447" "arch/arm64/src/common/arm64_mmu.c " _blank
init_xlat_tables --> set_pte_block_desc
click init_xlat_tables href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L447" "arch/arm64/src/common/arm64_mmu.c " _blank
init_xlat_tables --> set_pte_block_desc
click init_xlat_tables href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L447" "arch/arm64/src/common/arm64_mmu.c " _blank
init_xlat_tables --> setup_page_tables
click init_xlat_tables href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L456" "arch/arm64/src/common/arm64_mmu.c " _blank
pte_desc_type --> new_prealloc_table
click pte_desc_type href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L234" "arch/arm64/src/common/arm64_mmu.c " _blank
init_xlat_tables --> setup_page_tables
click init_xlat_tables href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L456" "arch/arm64/src/common/arm64_mmu.c " _blank
init_xlat_tables --> new_prealloc_table
click init_xlat_tables href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L472" "arch/arm64/src/common/arm64_mmu.c " _blank
new_prealloc_table --> split_pte_block_desc
click new_prealloc_table href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L378" "arch/arm64/src/common/arm64_mmu.c " _blank
split_pte_block_desc --> set_pte_table_desc
click split_pte_block_desc href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L401" "arch/arm64/src/common/arm64_mmu.c " _blank
init_xlat_tables --> setup_page_tables
click init_xlat_tables href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L456" "arch/arm64/src/common/arm64_mmu.c " _blank
init_xlat_tables --> setup_page_tables
click init_xlat_tables href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L456" "arch/arm64/src/common/arm64_mmu.c " _blank
init_xlat_tables --> setup_page_tables
click init_xlat_tables href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L456" "arch/arm64/src/common/arm64_mmu.c " _blank
setup_page_tables --> enable_mmu_el1
click setup_page_tables href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L515" "arch/arm64/src/common/arm64_mmu.c " _blank
enable_mmu_el1 --> arm64_isb
click enable_mmu_el1 href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L532" "arch/arm64/src/common/arm64_mmu.c " _blank
arm64_isb --> enable_mmu_el1
click arm64_isb href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/barriers.h#L57" "arch/arm64/src/common/barriers.h " _blank
enable_mmu_el1 --> ***_HALT_***
click enable_mmu_el1 href "https://github.com/apache/nuttx/blob/0f20888a0ececc5dc7419d57a01ac508ac3ace5b/arch/arm64/src/common/arm64_mmu.c#L542" "arch/arm64/src/common/arm64_mmu.c " _blank
```
We generated the Call Graph with this command...
```bash
cargo run | grep call_graph | cut -c 12-
```
(`cut` command removes columns 1 to 11)
Which produces this [Mermaid Flowchart](https://mermaid.js.org/syntax/flowchart.html)...
```text
→ cargo run | grep call_graph | cut -c 12-
flowchart TD
arm64_boot_el1_init --> arm64_isb
click arm64_boot_el1_init href "https://github.com/apache/nuttx/blob/master/arch/arm64/src/common/arm64_boot.c#L137" "arch/arm64/src/common/arm64_boot.c "
arm64_isb --> arm64_boot_el1_init
click arm64_isb href "https://github.com/apache/nuttx/blob/master/arch/arm64/src/common/barriers.h#L57" "arch/arm64/src/common/barriers.h "
arm64_boot_el1_init --> arm64_isb
click arm64_boot_el1_init href "https://github.com/apache/nuttx/blob/master/arch/arm64/src/common/arm64_boot.c#L145" "arch/arm64/src/common/arm64_boot.c "
arm64_isb --> arm64_boot_el1_init
...
setup_page_tables --> enable_mmu_el1
click setup_page_tables href "https://github.com/apache/nuttx/blob/master/arch/arm64/src/common/arm64_mmu.c#L515" "arch/arm64/src/common/arm64_mmu.c "
enable_mmu_el1 --> arm64_isb
click enable_mmu_el1 href "https://github.com/apache/nuttx/blob/master/arch/arm64/src/common/arm64_mmu.c#L532" "arch/arm64/src/common/arm64_mmu.c "
arm64_isb --> enable_mmu_el1
click arm64_isb href "https://github.com/apache/nuttx/blob/master/arch/arm64/src/common/barriers.h#L57" "arch/arm64/src/common/barriers.h "
enable_mmu_el1 --> ***_HALT_***
click enable_mmu_el1 href "https://github.com/apache/nuttx/blob/master/arch/arm64/src/common/arm64_mmu.c#L542" "arch/arm64/src/common/arm64_mmu.c "
```
[(Source)](https://gist.github.com/lupyuen/b0e4019801aaf9860bcb234c8a9c8584)
The Call Graph is generated by our Block Execution Hook like so...
https://github.com/lupyuen/nuttx-arm64-emulator/blob/b23c1d251a7fb244f2e396419d12ab532deb3e6b/src/main.rs#L130-L159
`call_graph` prints the Call Graph by looking up the Block Address in the ELF Context...
https://github.com/lupyuen/nuttx-arm64-emulator/blob/b23c1d251a7fb244f2e396419d12ab532deb3e6b/src/main.rs#L224-L265
We map the Block Address to Function Name and Source File in `map_address_to_function` and `map_address_to_location`...
https://github.com/lupyuen/nuttx-arm64-emulator/blob/b23c1d251a7fb244f2e396419d12ab532deb3e6b/src/main.rs#L175-L222
`ELF_CONTEXT` is explained here...
- ["(Clickable) Call Graph for Apache NuttX Real-Time Operating System"](https://lupyuen.github.io/articles/unicorn2)
# Other Emulators
_What about emulating popular operating systems: Linux / macOS / Windows / Android?_
Check out the Qiling Binary Emulation Framework...
- [qilingframework/qiling](https://github.com/qilingframework/qiling)
_How about other hardware platforms: STM32 Blue Pill and ESP32?_
Check out QEMU...
- ["STM32 Blue Pill — Unit Testing with Qemu Blue Pill Emulator"](https://lupyuen.github.io/articles/stm32-blue-pill-unit-testing-with-qemu-blue-pill-emulator)
- ["NuttX on an emulated ESP32 using QEMU"](https://medium.com/@lucassvaz/nuttx-on-an-emulated-esp32-using-qemu-8d8d93d24c63)
# TODO
TODO: Emulate Input Interupts from UART Controller
TODO: Emulate Apache NuttX NSH Shell with UART Controller
TODO: Select Arm Cortex-A53 as CPU
TODO: Emulate Multiple CPUs
TODO: Emulate Arm64 Memory Protection
TODO: Emulate Arm64 Generic Interrupt Controller version 2
TODO: Read the Symbol Table in NuttX ELF File to match the addresses received by Block Execution Hook
TODO: Emulate PinePhone's Allwinner A64 Display Engine. How to render the emulated graphics: Use Web Browser + WebAssembly + Unicorn.js? Will framebuffer emulation be slow?