The plan is two base kernel compilation around a specific 'board support package' (BSP), located in
/bsp
. The BSP will provide a specific architecture implementation, in conjunction with required
devices, memory maps, and linker scripts to generate an appropriate binary to run on the target.
Currently this is hard-coded in .cargo/config.toml
:
build.target
: The target triple to compile for (egaarch64-unknown-none-softfloat
)build.rustflags
: Additional flags to control the linker for this targetlink-arg=--library-path
: An additional path for the linker to search, which should point to the BSP directory (eg./bsp/rpi3
)link-arg=--script
: Name of the linker script, which will likely remain the same across multiple targets (egkernel.ld
)
- Generate tables (maybe const with Rust?)
- Identity map kernel (VA == PA, temporary until execution switches over to MMU)
- Map high addresses to kernel
- Map peripherals
- Begin execution with PIC
- Seperate Rust crate with
-pie
enabled - Assembly
- TODO: How to configure linker script to place this code at the top of the binary? Redox Linker Script
-
PIC configures tables
-
PIC 'trampolines' into regular kernel setup, compiled for high execution
mmu_on_trampoline:
adr x0, mmu_on_marker // x0: paddr of mmu_on_marker
ldr x0, [x0] // x0: vaddr of mmu_on
br x0 // MMU now On. Jump to mmu_on using it's vaddr
Copied from Redox
-
Note: This code is executing whilst the MMU is on, but the link return register will contain the 'old' address
-
adr x0, mmu_on_marker
: Store an offset from the current location to the labelmmu_on_marker
(which contains the virtual memory address of themmu_on
label, inserted by the linker). -
ldr x0, [x0]
: Load from the offset stored inx0
a value, and place it inx0
. This fetches the virtual address ofmmu_on
stored by the linker. -
br x0
: Branch tommu_on
using the virtual address.
-
Identity mapped kernel is removed from tables (optional)
-
MMU is now enabled!
Memory attributes are defined in the MAIR_ELx
register (Memory Attribute Indirection Register).
The register consists 8x 1-byte 'attributes', each of which can be used to specify a different set
of memory attributes. A specific attribute can then be referred to by index in the table or page
descriptors when writing them to memory.
(reference values Redox kernel MAIR) (full specification in ARM ARM D19.2.100)
-
0b00
:0b0000_0000
-
Rule
0b0000dd00
wheredd
=00
-
Device memory (device-nGnRnE memory)
-
-
0b01
:0b0100_0100
-
Rule
0boooo_iiii
whereoooo
=0100
andiiii
=0100
-
Normal memory (Outer Non-cacheable, Inner None-cacheable)
-
-
0b10
:0b1111_1111
-
Rule
0b0000_iiii
whereoooo
=11RW
andiiii
=11RW
-
Normal memory (Outer Write-Back Non-transient, Inner Write-Back Non-transient)
-
-
Kernel text:
0b01
(normal non-cacheable)- It's standard to not cache kernel text in order to ensure the 'latest' code version is always being read (eg incase it's updated). It also apparently assists with preventing side-channel attacks?
-
Kernel stack:
0b10
(normal, cacheable)- Kernel stack is fine to be cached as it will receive frequent reads and writes. Caching it reduces activity on the memory busses.
-
Device memory map:
0b00
(device memory)- Since this is just the device's entire RAM re-mapped at a higher address, it's best to limit additional caching since it will contain memory mapped devices.