From 223989adb9cce379d650b9cd67581c0a26df2f6f Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Tue, 16 Mar 2021 22:36:06 +0100 Subject: [PATCH] Overhaul linker script --- 01_wait_forever/Makefile | 1 - 01_wait_forever/src/bsp/raspberrypi/link.ld | 23 +- 02_runtime_init/Makefile | 1 + 02_runtime_init/README.md | 62 ++- 02_runtime_init/src/bsp/raspberrypi/link.ld | 45 +- 03_hacky_hello_world/Makefile | 1 + .../src/bsp/raspberrypi/link.ld | 45 +- 04_zero_overhead_abstraction/Makefile | 1 + 04_zero_overhead_abstraction/README.md | 37 +- .../src/bsp/raspberrypi/link.ld | 46 ++- .../src/bsp/raspberrypi/memory.rs | 18 +- 05_safe_globals/Makefile | 1 + 05_safe_globals/src/bsp/raspberrypi/link.ld | 46 ++- 05_safe_globals/src/bsp/raspberrypi/memory.rs | 18 +- 06_drivers_gpio_uart/Makefile | 1 + 06_drivers_gpio_uart/README.md | 21 +- .../src/bsp/raspberrypi/link.ld | 46 ++- .../src/bsp/raspberrypi/memory.rs | 21 +- 07_uart_chainloader/README.md | 119 +++--- 07_uart_chainloader/demo_payload_rpi3.img | Bin 6808 -> 6824 bytes 07_uart_chainloader/demo_payload_rpi4.img | Bin 6656 -> 6672 bytes .../src/bsp/raspberrypi/link.ld | 49 +-- .../src/bsp/raspberrypi/memory.rs | 7 +- 07_uart_chainloader/src/relocate.rs | 16 +- 08_timestamps/Makefile | 1 + 08_timestamps/README.md | 117 +++--- 08_timestamps/src/bsp/raspberrypi/link.ld | 46 ++- 08_timestamps/src/bsp/raspberrypi/memory.rs | 21 +- 09_hw_debug_JTAG/Makefile | 1 + 09_hw_debug_JTAG/src/bsp/raspberrypi/link.ld | 46 ++- .../src/bsp/raspberrypi/memory.rs | 21 +- 10_privilege_level/Makefile | 1 + 10_privilege_level/README.md | 2 +- .../src/bsp/raspberrypi/link.ld | 46 ++- .../src/bsp/raspberrypi/memory.rs | 21 +- .../Makefile | 1 + .../README.md | 94 ++--- .../src/bsp/raspberrypi/link.ld | 52 ++- .../src/bsp/raspberrypi/memory.rs | 23 +- .../src/bsp/raspberrypi/memory/mmu.rs | 6 +- 12_exceptions_part1_groundwork/Makefile | 1 + 12_exceptions_part1_groundwork/README.md | 52 +-- .../src/_arch/aarch64/exception.S | 2 +- .../src/_arch/aarch64/exception.rs | 24 +- .../src/bsp/raspberrypi/link.ld | 55 +-- .../src/bsp/raspberrypi/memory.rs | 23 +- .../src/bsp/raspberrypi/memory/mmu.rs | 6 +- 13_integrated_testing/Makefile | 1 + .../src/_arch/aarch64/exception.S | 2 +- .../src/_arch/aarch64/exception.rs | 24 +- .../src/bsp/raspberrypi/link.ld | 55 +-- .../src/bsp/raspberrypi/memory.rs | 23 +- .../src/bsp/raspberrypi/memory/mmu.rs | 6 +- 14_exceptions_part2_peripheral_IRQs/Makefile | 1 + 14_exceptions_part2_peripheral_IRQs/README.md | 4 +- .../src/_arch/aarch64/exception.S | 2 +- .../src/_arch/aarch64/exception.rs | 24 +- .../src/bsp/raspberrypi/link.ld | 55 +-- .../src/bsp/raspberrypi/memory.rs | 23 +- .../src/bsp/raspberrypi/memory/mmu.rs | 6 +- 15_virtual_mem_part2_mmio_remap/Makefile | 1 + 15_virtual_mem_part2_mmio_remap/README.md | 384 +++++++++++------- .../src/_arch/aarch64/exception.S | 2 +- .../src/_arch/aarch64/exception.rs | 42 +- .../src/bsp/raspberrypi/link.ld | 74 ++-- .../src/bsp/raspberrypi/memory.rs | 94 +++-- .../src/bsp/raspberrypi/memory/mmu.rs | 89 ++-- X1_JTAG_boot/Makefile | 1 + X1_JTAG_boot/jtag_boot_rpi3.img | Bin 8144 -> 8152 bytes X1_JTAG_boot/jtag_boot_rpi4.img | Bin 6832 -> 6840 bytes X1_JTAG_boot/src/bsp/raspberrypi/link.ld | 46 ++- X1_JTAG_boot/src/bsp/raspberrypi/memory.rs | 21 +- 72 files changed, 1339 insertions(+), 928 deletions(-) diff --git a/01_wait_forever/Makefile b/01_wait_forever/Makefile index eb2cc732..2e44e7ac 100644 --- a/01_wait_forever/Makefile +++ b/01_wait_forever/Makefile @@ -102,7 +102,6 @@ objdump: $(KERNEL_ELF) $(call colorecho, "\nLaunching objdump") @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ - --section .rodata \ $(KERNEL_ELF) | rustfilt nm: $(KERNEL_ELF) diff --git a/01_wait_forever/src/bsp/raspberrypi/link.ld b/01_wait_forever/src/bsp/raspberrypi/link.ld index 81f01c11..7d649f88 100644 --- a/01_wait_forever/src/bsp/raspberrypi/link.ld +++ b/01_wait_forever/src/bsp/raspberrypi/link.ld @@ -3,15 +3,26 @@ * Copyright (c) 2018-2021 Andre Richter */ +/* The address at which the the kernel binary will be loaded by the Raspberry's firmware */ +__rpi_load_addr = 0x80000; + +ENTRY(__rpi_load_addr) + +PHDRS +{ + segment_rx PT_LOAD FLAGS(5); /* 5 == RX */ +} + SECTIONS { - /* Set current address to the value from which the RPi starts execution */ - . = 0x80000; + . = __rpi_load_addr; + /*********************************************************************************************** + * Code + ***********************************************************************************************/ .text : { - *(.text._start) *(.text*) - } - - /DISCARD/ : { *(.comment*) } + KEEP(*(.text._start)) + *(.text*) + } :segment_rx } diff --git a/02_runtime_init/Makefile b/02_runtime_init/Makefile index eb2cc732..a20b283b 100644 --- a/02_runtime_init/Makefile +++ b/02_runtime_init/Makefile @@ -103,6 +103,7 @@ objdump: $(KERNEL_ELF) @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ --section .rodata \ + --section .got \ $(KERNEL_ELF) | rustfilt nm: $(KERNEL_ELF) diff --git a/02_runtime_init/README.md b/02_runtime_init/README.md index 9241a195..5f5245d5 100644 --- a/02_runtime_init/README.md +++ b/02_runtime_init/README.md @@ -9,8 +9,7 @@ ## Notable additions - More sections in linker script: - - `.rodata`, `.data` - - `.bss` + - `.rodata`, `.got`, `.data`, `.bss` - `_start()`: - Halt core if core != `core0`. - `core0` jumps to the `runtime_init()` Rust function. @@ -37,6 +36,19 @@ diff -uNr 01_wait_forever/Cargo.toml 02_runtime_init/Cargo.toml default = [] bsp_rpi3 = [] +diff -uNr 01_wait_forever/Makefile 02_runtime_init/Makefile +--- 01_wait_forever/Makefile ++++ 02_runtime_init/Makefile +@@ -102,6 +102,8 @@ + $(call colorecho, "\nLaunching objdump") + @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ + --section .text \ ++ --section .rodata \ ++ --section .got \ + $(KERNEL_ELF) | rustfilt + + nm: $(KERNEL_ELF) + diff -uNr 01_wait_forever/src/_arch/aarch64/cpu/boot.S 02_runtime_init/src/_arch/aarch64/cpu/boot.S --- 01_wait_forever/src/_arch/aarch64/cpu/boot.S +++ 02_runtime_init/src/_arch/aarch64/cpu/boot.S @@ -97,33 +109,45 @@ diff -uNr 01_wait_forever/src/_arch/aarch64/cpu.rs 02_runtime_init/src/_arch/aar diff -uNr 01_wait_forever/src/bsp/raspberrypi/link.ld 02_runtime_init/src/bsp/raspberrypi/link.ld --- 01_wait_forever/src/bsp/raspberrypi/link.ld +++ 02_runtime_init/src/bsp/raspberrypi/link.ld -@@ -13,5 +13,27 @@ - *(.text._start) *(.text*) - } +@@ -11,6 +11,7 @@ + PHDRS + { + segment_rx PT_LOAD FLAGS(5); /* 5 == RX */ ++ segment_rw PT_LOAD FLAGS(6); /* 6 == RW */ + } -+ .rodata : -+ { -+ *(.rodata*) -+ } + SECTIONS +@@ -18,11 +19,30 @@ + . = __rpi_load_addr; + + /*********************************************************************************************** +- * Code ++ * Code + RO Data + Global Offset Table + ***********************************************************************************************/ + .text : + { + KEEP(*(.text._start)) + *(.text*) + } :segment_rx + -+ .data : -+ { -+ *(.data*) -+ } ++ .rodata : ALIGN(8) { *(.rodata*) } :segment_rx ++ .got : ALIGN(8) { *(.got) } :segment_rx ++ ++ /*********************************************************************************************** ++ * Data + BSS ++ ***********************************************************************************************/ ++ .data : { *(.data*) } :segment_rw + + /* Section is zeroed in u64 chunks, align start and end to 8 bytes */ -+ .bss ALIGN(8): ++ .bss : ALIGN(8) + { + __bss_start = .; + *(.bss*); + . = ALIGN(8); + -+ /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ -+ . += 8; ++ . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ + __bss_end_inclusive = . - 8; -+ } -+ - /DISCARD/ : { *(.comment*) } ++ } :NONE } diff -uNr 01_wait_forever/src/bsp/raspberrypi/memory.rs 02_runtime_init/src/bsp/raspberrypi/memory.rs diff --git a/02_runtime_init/src/bsp/raspberrypi/link.ld b/02_runtime_init/src/bsp/raspberrypi/link.ld index 573abc5f..acb7fe28 100644 --- a/02_runtime_init/src/bsp/raspberrypi/link.ld +++ b/02_runtime_init/src/bsp/raspberrypi/link.ld @@ -3,37 +3,46 @@ * Copyright (c) 2018-2021 Andre Richter */ +/* The address at which the the kernel binary will be loaded by the Raspberry's firmware */ +__rpi_load_addr = 0x80000; + +ENTRY(__rpi_load_addr) + +PHDRS +{ + segment_rx PT_LOAD FLAGS(5); /* 5 == RX */ + segment_rw PT_LOAD FLAGS(6); /* 6 == RW */ +} + SECTIONS { - /* Set current address to the value from which the RPi starts execution */ - . = 0x80000; + . = __rpi_load_addr; + /*********************************************************************************************** + * Code + RO Data + Global Offset Table + ***********************************************************************************************/ .text : { - *(.text._start) *(.text*) - } + KEEP(*(.text._start)) + *(.text*) + } :segment_rx - .rodata : - { - *(.rodata*) - } + .rodata : ALIGN(8) { *(.rodata*) } :segment_rx + .got : ALIGN(8) { *(.got) } :segment_rx - .data : - { - *(.data*) - } + /*********************************************************************************************** + * Data + BSS + ***********************************************************************************************/ + .data : { *(.data*) } :segment_rw /* Section is zeroed in u64 chunks, align start and end to 8 bytes */ - .bss ALIGN(8): + .bss : ALIGN(8) { __bss_start = .; *(.bss*); . = ALIGN(8); - /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ - . += 8; + . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ __bss_end_inclusive = . - 8; - } - - /DISCARD/ : { *(.comment*) } + } :NONE } diff --git a/03_hacky_hello_world/Makefile b/03_hacky_hello_world/Makefile index 75158b5b..2ed82a5f 100644 --- a/03_hacky_hello_world/Makefile +++ b/03_hacky_hello_world/Makefile @@ -103,6 +103,7 @@ objdump: $(KERNEL_ELF) @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ --section .rodata \ + --section .got \ $(KERNEL_ELF) | rustfilt nm: $(KERNEL_ELF) diff --git a/03_hacky_hello_world/src/bsp/raspberrypi/link.ld b/03_hacky_hello_world/src/bsp/raspberrypi/link.ld index 573abc5f..acb7fe28 100644 --- a/03_hacky_hello_world/src/bsp/raspberrypi/link.ld +++ b/03_hacky_hello_world/src/bsp/raspberrypi/link.ld @@ -3,37 +3,46 @@ * Copyright (c) 2018-2021 Andre Richter */ +/* The address at which the the kernel binary will be loaded by the Raspberry's firmware */ +__rpi_load_addr = 0x80000; + +ENTRY(__rpi_load_addr) + +PHDRS +{ + segment_rx PT_LOAD FLAGS(5); /* 5 == RX */ + segment_rw PT_LOAD FLAGS(6); /* 6 == RW */ +} + SECTIONS { - /* Set current address to the value from which the RPi starts execution */ - . = 0x80000; + . = __rpi_load_addr; + /*********************************************************************************************** + * Code + RO Data + Global Offset Table + ***********************************************************************************************/ .text : { - *(.text._start) *(.text*) - } + KEEP(*(.text._start)) + *(.text*) + } :segment_rx - .rodata : - { - *(.rodata*) - } + .rodata : ALIGN(8) { *(.rodata*) } :segment_rx + .got : ALIGN(8) { *(.got) } :segment_rx - .data : - { - *(.data*) - } + /*********************************************************************************************** + * Data + BSS + ***********************************************************************************************/ + .data : { *(.data*) } :segment_rw /* Section is zeroed in u64 chunks, align start and end to 8 bytes */ - .bss ALIGN(8): + .bss : ALIGN(8) { __bss_start = .; *(.bss*); . = ALIGN(8); - /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ - . += 8; + . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ __bss_end_inclusive = . - 8; - } - - /DISCARD/ : { *(.comment*) } + } :NONE } diff --git a/04_zero_overhead_abstraction/Makefile b/04_zero_overhead_abstraction/Makefile index 75158b5b..2ed82a5f 100644 --- a/04_zero_overhead_abstraction/Makefile +++ b/04_zero_overhead_abstraction/Makefile @@ -103,6 +103,7 @@ objdump: $(KERNEL_ELF) @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ --section .rodata \ + --section .got \ $(KERNEL_ELF) | rustfilt nm: $(KERNEL_ELF) diff --git a/04_zero_overhead_abstraction/README.md b/04_zero_overhead_abstraction/README.md index aeb3bfb8..358d01e7 100644 --- a/04_zero_overhead_abstraction/README.md +++ b/04_zero_overhead_abstraction/README.md @@ -167,20 +167,43 @@ diff -uNr 03_hacky_hello_world/src/bsp/raspberrypi/cpu.rs 04_zero_overhead_abstr +/// Used by `arch` code to find the early boot core. +pub const BOOT_CORE_ID: usize = 0; +diff -uNr 03_hacky_hello_world/src/bsp/raspberrypi/link.ld 04_zero_overhead_abstraction/src/bsp/raspberrypi/link.ld +--- 03_hacky_hello_world/src/bsp/raspberrypi/link.ld ++++ 04_zero_overhead_abstraction/src/bsp/raspberrypi/link.ld +@@ -21,6 +21,7 @@ + /*********************************************************************************************** + * Code + RO Data + Global Offset Table + ***********************************************************************************************/ ++ __rx_start = .; + .text : + { + KEEP(*(.text._start)) + diff -uNr 03_hacky_hello_world/src/bsp/raspberrypi/memory.rs 04_zero_overhead_abstraction/src/bsp/raspberrypi/memory.rs --- 03_hacky_hello_world/src/bsp/raspberrypi/memory.rs +++ 04_zero_overhead_abstraction/src/bsp/raspberrypi/memory.rs -@@ -17,9 +17,25 @@ +@@ -12,14 +12,36 @@ + + // Symbols from the linker script. + extern "Rust" { ++ static __rx_start: UnsafeCell<()>; ++ + static __bss_start: UnsafeCell; + static __bss_end_inclusive: UnsafeCell; } //-------------------------------------------------------------------------------------------------- -+// Public Definitions ++// Private Code +//-------------------------------------------------------------------------------------------------- + -+/// The board's memory map. -+#[rustfmt::skip] -+pub(super) mod map { -+ pub const BOOT_CORE_STACK_END: usize = 0x8_0000; ++/// Start address of the Read+Execute (RX) range. ++/// ++/// # Safety ++/// ++/// - Value is provided by the linker script and must be trusted as-is. ++#[inline(always)] ++fn rx_start() -> usize { ++ unsafe { __rx_start.get() as usize } +} + +//-------------------------------------------------------------------------------------------------- @@ -190,7 +213,7 @@ diff -uNr 03_hacky_hello_world/src/bsp/raspberrypi/memory.rs 04_zero_overhead_ab +/// Exclusive end address of the boot core's stack. +#[inline(always)] +pub fn boot_core_stack_end() -> usize { -+ map::BOOT_CORE_STACK_END ++ rx_start() +} + /// Return the inclusive range spanning the .bss section. diff --git a/04_zero_overhead_abstraction/src/bsp/raspberrypi/link.ld b/04_zero_overhead_abstraction/src/bsp/raspberrypi/link.ld index 573abc5f..87e6a976 100644 --- a/04_zero_overhead_abstraction/src/bsp/raspberrypi/link.ld +++ b/04_zero_overhead_abstraction/src/bsp/raspberrypi/link.ld @@ -3,37 +3,47 @@ * Copyright (c) 2018-2021 Andre Richter */ +/* The address at which the the kernel binary will be loaded by the Raspberry's firmware */ +__rpi_load_addr = 0x80000; + +ENTRY(__rpi_load_addr) + +PHDRS +{ + segment_rx PT_LOAD FLAGS(5); /* 5 == RX */ + segment_rw PT_LOAD FLAGS(6); /* 6 == RW */ +} + SECTIONS { - /* Set current address to the value from which the RPi starts execution */ - . = 0x80000; + . = __rpi_load_addr; + /*********************************************************************************************** + * Code + RO Data + Global Offset Table + ***********************************************************************************************/ + __rx_start = .; .text : { - *(.text._start) *(.text*) - } + KEEP(*(.text._start)) + *(.text*) + } :segment_rx - .rodata : - { - *(.rodata*) - } + .rodata : ALIGN(8) { *(.rodata*) } :segment_rx + .got : ALIGN(8) { *(.got) } :segment_rx - .data : - { - *(.data*) - } + /*********************************************************************************************** + * Data + BSS + ***********************************************************************************************/ + .data : { *(.data*) } :segment_rw /* Section is zeroed in u64 chunks, align start and end to 8 bytes */ - .bss ALIGN(8): + .bss : ALIGN(8) { __bss_start = .; *(.bss*); . = ALIGN(8); - /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ - . += 8; + . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ __bss_end_inclusive = . - 8; - } - - /DISCARD/ : { *(.comment*) } + } :NONE } diff --git a/04_zero_overhead_abstraction/src/bsp/raspberrypi/memory.rs b/04_zero_overhead_abstraction/src/bsp/raspberrypi/memory.rs index 77fdafd7..bffe8eab 100644 --- a/04_zero_overhead_abstraction/src/bsp/raspberrypi/memory.rs +++ b/04_zero_overhead_abstraction/src/bsp/raspberrypi/memory.rs @@ -12,18 +12,24 @@ use core::{cell::UnsafeCell, ops::RangeInclusive}; // Symbols from the linker script. extern "Rust" { + static __rx_start: UnsafeCell<()>; + static __bss_start: UnsafeCell; static __bss_end_inclusive: UnsafeCell; } //-------------------------------------------------------------------------------------------------- -// Public Definitions +// Private Code //-------------------------------------------------------------------------------------------------- -/// The board's memory map. -#[rustfmt::skip] -pub(super) mod map { - pub const BOOT_CORE_STACK_END: usize = 0x8_0000; +/// Start address of the Read+Execute (RX) range. +/// +/// # Safety +/// +/// - Value is provided by the linker script and must be trusted as-is. +#[inline(always)] +fn rx_start() -> usize { + unsafe { __rx_start.get() as usize } } //-------------------------------------------------------------------------------------------------- @@ -33,7 +39,7 @@ pub(super) mod map { /// Exclusive end address of the boot core's stack. #[inline(always)] pub fn boot_core_stack_end() -> usize { - map::BOOT_CORE_STACK_END + rx_start() } /// Return the inclusive range spanning the .bss section. diff --git a/05_safe_globals/Makefile b/05_safe_globals/Makefile index 75158b5b..2ed82a5f 100644 --- a/05_safe_globals/Makefile +++ b/05_safe_globals/Makefile @@ -103,6 +103,7 @@ objdump: $(KERNEL_ELF) @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ --section .rodata \ + --section .got \ $(KERNEL_ELF) | rustfilt nm: $(KERNEL_ELF) diff --git a/05_safe_globals/src/bsp/raspberrypi/link.ld b/05_safe_globals/src/bsp/raspberrypi/link.ld index 573abc5f..87e6a976 100644 --- a/05_safe_globals/src/bsp/raspberrypi/link.ld +++ b/05_safe_globals/src/bsp/raspberrypi/link.ld @@ -3,37 +3,47 @@ * Copyright (c) 2018-2021 Andre Richter */ +/* The address at which the the kernel binary will be loaded by the Raspberry's firmware */ +__rpi_load_addr = 0x80000; + +ENTRY(__rpi_load_addr) + +PHDRS +{ + segment_rx PT_LOAD FLAGS(5); /* 5 == RX */ + segment_rw PT_LOAD FLAGS(6); /* 6 == RW */ +} + SECTIONS { - /* Set current address to the value from which the RPi starts execution */ - . = 0x80000; + . = __rpi_load_addr; + /*********************************************************************************************** + * Code + RO Data + Global Offset Table + ***********************************************************************************************/ + __rx_start = .; .text : { - *(.text._start) *(.text*) - } + KEEP(*(.text._start)) + *(.text*) + } :segment_rx - .rodata : - { - *(.rodata*) - } + .rodata : ALIGN(8) { *(.rodata*) } :segment_rx + .got : ALIGN(8) { *(.got) } :segment_rx - .data : - { - *(.data*) - } + /*********************************************************************************************** + * Data + BSS + ***********************************************************************************************/ + .data : { *(.data*) } :segment_rw /* Section is zeroed in u64 chunks, align start and end to 8 bytes */ - .bss ALIGN(8): + .bss : ALIGN(8) { __bss_start = .; *(.bss*); . = ALIGN(8); - /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ - . += 8; + . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ __bss_end_inclusive = . - 8; - } - - /DISCARD/ : { *(.comment*) } + } :NONE } diff --git a/05_safe_globals/src/bsp/raspberrypi/memory.rs b/05_safe_globals/src/bsp/raspberrypi/memory.rs index 77fdafd7..bffe8eab 100644 --- a/05_safe_globals/src/bsp/raspberrypi/memory.rs +++ b/05_safe_globals/src/bsp/raspberrypi/memory.rs @@ -12,18 +12,24 @@ use core::{cell::UnsafeCell, ops::RangeInclusive}; // Symbols from the linker script. extern "Rust" { + static __rx_start: UnsafeCell<()>; + static __bss_start: UnsafeCell; static __bss_end_inclusive: UnsafeCell; } //-------------------------------------------------------------------------------------------------- -// Public Definitions +// Private Code //-------------------------------------------------------------------------------------------------- -/// The board's memory map. -#[rustfmt::skip] -pub(super) mod map { - pub const BOOT_CORE_STACK_END: usize = 0x8_0000; +/// Start address of the Read+Execute (RX) range. +/// +/// # Safety +/// +/// - Value is provided by the linker script and must be trusted as-is. +#[inline(always)] +fn rx_start() -> usize { + unsafe { __rx_start.get() as usize } } //-------------------------------------------------------------------------------------------------- @@ -33,7 +39,7 @@ pub(super) mod map { /// Exclusive end address of the boot core's stack. #[inline(always)] pub fn boot_core_stack_end() -> usize { - map::BOOT_CORE_STACK_END + rx_start() } /// Return the inclusive range spanning the .bss section. diff --git a/06_drivers_gpio_uart/Makefile b/06_drivers_gpio_uart/Makefile index 07eb97b2..1dd6cc2b 100644 --- a/06_drivers_gpio_uart/Makefile +++ b/06_drivers_gpio_uart/Makefile @@ -122,6 +122,7 @@ objdump: $(KERNEL_ELF) @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ --section .rodata \ + --section .got \ $(KERNEL_ELF) | rustfilt nm: $(KERNEL_ELF) diff --git a/06_drivers_gpio_uart/README.md b/06_drivers_gpio_uart/README.md index 8b8e076d..7dea308f 100644 --- a/06_drivers_gpio_uart/README.md +++ b/06_drivers_gpio_uart/README.md @@ -1110,10 +1110,16 @@ diff -uNr 05_safe_globals/src/bsp/raspberrypi/driver.rs 06_drivers_gpio_uart/src diff -uNr 05_safe_globals/src/bsp/raspberrypi/memory.rs 06_drivers_gpio_uart/src/bsp/raspberrypi/memory.rs --- 05_safe_globals/src/bsp/raspberrypi/memory.rs +++ 06_drivers_gpio_uart/src/bsp/raspberrypi/memory.rs -@@ -24,6 +24,29 @@ - #[rustfmt::skip] - pub(super) mod map { - pub const BOOT_CORE_STACK_END: usize = 0x8_0000; +@@ -19,6 +19,38 @@ + } + + //-------------------------------------------------------------------------------------------------- ++// Public Definitions ++//-------------------------------------------------------------------------------------------------- ++ ++/// The board's physical memory map. ++#[rustfmt::skip] ++pub(super) mod map { + + pub const GPIO_OFFSET: usize = 0x0020_0000; + pub const UART_OFFSET: usize = 0x0020_1000; @@ -1137,10 +1143,13 @@ diff -uNr 05_safe_globals/src/bsp/raspberrypi/memory.rs 06_drivers_gpio_uart/src + pub const GPIO_START: usize = START + GPIO_OFFSET; + pub const PL011_UART_START: usize = START + UART_OFFSET; + } - } - ++} ++ ++//-------------------------------------------------------------------------------------------------- + // Private Code //-------------------------------------------------------------------------------------------------- + diff -uNr 05_safe_globals/src/bsp/raspberrypi.rs 06_drivers_gpio_uart/src/bsp/raspberrypi.rs --- 05_safe_globals/src/bsp/raspberrypi.rs +++ 06_drivers_gpio_uart/src/bsp/raspberrypi.rs diff --git a/06_drivers_gpio_uart/src/bsp/raspberrypi/link.ld b/06_drivers_gpio_uart/src/bsp/raspberrypi/link.ld index 573abc5f..87e6a976 100644 --- a/06_drivers_gpio_uart/src/bsp/raspberrypi/link.ld +++ b/06_drivers_gpio_uart/src/bsp/raspberrypi/link.ld @@ -3,37 +3,47 @@ * Copyright (c) 2018-2021 Andre Richter */ +/* The address at which the the kernel binary will be loaded by the Raspberry's firmware */ +__rpi_load_addr = 0x80000; + +ENTRY(__rpi_load_addr) + +PHDRS +{ + segment_rx PT_LOAD FLAGS(5); /* 5 == RX */ + segment_rw PT_LOAD FLAGS(6); /* 6 == RW */ +} + SECTIONS { - /* Set current address to the value from which the RPi starts execution */ - . = 0x80000; + . = __rpi_load_addr; + /*********************************************************************************************** + * Code + RO Data + Global Offset Table + ***********************************************************************************************/ + __rx_start = .; .text : { - *(.text._start) *(.text*) - } + KEEP(*(.text._start)) + *(.text*) + } :segment_rx - .rodata : - { - *(.rodata*) - } + .rodata : ALIGN(8) { *(.rodata*) } :segment_rx + .got : ALIGN(8) { *(.got) } :segment_rx - .data : - { - *(.data*) - } + /*********************************************************************************************** + * Data + BSS + ***********************************************************************************************/ + .data : { *(.data*) } :segment_rw /* Section is zeroed in u64 chunks, align start and end to 8 bytes */ - .bss ALIGN(8): + .bss : ALIGN(8) { __bss_start = .; *(.bss*); . = ALIGN(8); - /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ - . += 8; + . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ __bss_end_inclusive = . - 8; - } - - /DISCARD/ : { *(.comment*) } + } :NONE } diff --git a/06_drivers_gpio_uart/src/bsp/raspberrypi/memory.rs b/06_drivers_gpio_uart/src/bsp/raspberrypi/memory.rs index fb47b141..56a3306e 100644 --- a/06_drivers_gpio_uart/src/bsp/raspberrypi/memory.rs +++ b/06_drivers_gpio_uart/src/bsp/raspberrypi/memory.rs @@ -12,6 +12,8 @@ use core::{cell::UnsafeCell, ops::RangeInclusive}; // Symbols from the linker script. extern "Rust" { + static __rx_start: UnsafeCell<()>; + static __bss_start: UnsafeCell; static __bss_end_inclusive: UnsafeCell; } @@ -20,10 +22,9 @@ extern "Rust" { // Public Definitions //-------------------------------------------------------------------------------------------------- -/// The board's memory map. +/// The board's physical memory map. #[rustfmt::skip] pub(super) mod map { - pub const BOOT_CORE_STACK_END: usize = 0x8_0000; pub const GPIO_OFFSET: usize = 0x0020_0000; pub const UART_OFFSET: usize = 0x0020_1000; @@ -49,6 +50,20 @@ pub(super) mod map { } } +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +/// Start address of the Read+Execute (RX) range. +/// +/// # Safety +/// +/// - Value is provided by the linker script and must be trusted as-is. +#[inline(always)] +fn rx_start() -> usize { + unsafe { __rx_start.get() as usize } +} + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- @@ -56,7 +71,7 @@ pub(super) mod map { /// Exclusive end address of the boot core's stack. #[inline(always)] pub fn boot_core_stack_end() -> usize { - map::BOOT_CORE_STACK_END + rx_start() } /// Return the inclusive range spanning the .bss section. diff --git a/07_uart_chainloader/README.md b/07_uart_chainloader/README.md index e67c7810..923615b5 100644 --- a/07_uart_chainloader/README.md +++ b/07_uart_chainloader/README.md @@ -165,14 +165,6 @@ diff -uNr 06_drivers_gpio_uart/Makefile 07_uart_chainloader/Makefile clippy: @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(CLIPPY_CMD) -@@ -122,6 +129,7 @@ - @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ - --section .text \ - --section .rodata \ -+ --section .got \ - $(KERNEL_ELF) | rustfilt - - nm: $(KERNEL_ELF) diff -uNr 06_drivers_gpio_uart/src/_arch/aarch64/cpu/boot.rs 07_uart_chainloader/src/_arch/aarch64/cpu/boot.rs --- 06_drivers_gpio_uart/src/_arch/aarch64/cpu/boot.rs @@ -276,77 +268,82 @@ diff -uNr 06_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 0 diff -uNr 06_drivers_gpio_uart/src/bsp/raspberrypi/link.ld 07_uart_chainloader/src/bsp/raspberrypi/link.ld --- 06_drivers_gpio_uart/src/bsp/raspberrypi/link.ld +++ 07_uart_chainloader/src/bsp/raspberrypi/link.ld -@@ -5,12 +5,15 @@ +@@ -16,12 +16,13 @@ SECTIONS { -- /* Set current address to the value from which the RPi starts execution */ -- . = 0x80000; +- . = __rpi_load_addr; + /* Set the link address to 32 MiB */ + . = 0x2000000; + /*********************************************************************************************** + * Code + RO Data + Global Offset Table + ***********************************************************************************************/ +- __rx_start = .; + __binary_start = .; .text : { -- *(.text._start) *(.text*) -+ *(.text._start) -+ KEEP(*(.text.runtime_init)) -+ *(.text*); - } - - .rodata : -@@ -35,5 +38,16 @@ + KEEP(*(.text._start)) +@@ -46,4 +47,10 @@ + . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ __bss_end_inclusive = . - 8; - } - -+ .got : -+ { -+ *(.got*) -+ } + } :NONE + + /* Fill up to 8 byte, b/c relocating the binary is done in u64 chunks */ + . = ALIGN(8); + __binary_end_inclusive = . - 8; + + __runtime_init_reloc = runtime_init; -+ - /DISCARD/ : { *(.comment*) } } diff -uNr 06_drivers_gpio_uart/src/bsp/raspberrypi/memory.rs 07_uart_chainloader/src/bsp/raspberrypi/memory.rs --- 06_drivers_gpio_uart/src/bsp/raspberrypi/memory.rs +++ 07_uart_chainloader/src/bsp/raspberrypi/memory.rs -@@ -12,6 +12,9 @@ +@@ -12,10 +12,12 @@ // Symbols from the linker script. extern "Rust" { +- static __rx_start: UnsafeCell<()>; +- + static __binary_start: UnsafeCell; -+ static __binary_end_inclusive: UnsafeCell; -+ static __runtime_init_reloc: UnsafeCell; static __bss_start: UnsafeCell; static __bss_end_inclusive: UnsafeCell; ++ static __binary_end_inclusive: UnsafeCell; ++ ++ static __runtime_init_reloc: UnsafeCell; } -@@ -23,10 +26,12 @@ - /// The board's memory map. + + //-------------------------------------------------------------------------------------------------- +@@ -25,9 +27,12 @@ + /// The board's physical memory map. #[rustfmt::skip] pub(super) mod map { -- pub const BOOT_CORE_STACK_END: usize = 0x8_0000; + pub const BOOT_CORE_STACK_END: usize = 0x8_0000; ++ ++ pub const BOARD_DEFAULT_LOAD_ADDRESS: usize = 0x8_0000; - pub const GPIO_OFFSET: usize = 0x0020_0000; - pub const UART_OFFSET: usize = 0x0020_1000; -+ pub const BOARD_DEFAULT_LOAD_ADDRESS: usize = 0x8_0000; -+ + pub const GPIO_OFFSET: usize = 0x0020_0000; + pub const UART_OFFSET: usize = 0x0020_1000; /// Physical devices. #[cfg(feature = "bsp_rpi3")] -@@ -59,13 +64,35 @@ - map::BOOT_CORE_STACK_END +@@ -51,36 +56,44 @@ } --/// Return the inclusive range spanning the .bss section. + //-------------------------------------------------------------------------------------------------- +-// Private Code ++// Public Code + //-------------------------------------------------------------------------------------------------- + +-/// Start address of the Read+Execute (RX) range. ++/// Exclusive end address of the boot core's stack. ++#[inline(always)] ++pub fn boot_core_stack_end() -> usize { ++ map::BOOT_CORE_STACK_END ++} ++ +/// The address on which the Raspberry firmware loads every binary by default. +#[inline(always)] +pub fn board_default_load_addr() -> *const u64 { @@ -354,21 +351,33 @@ diff -uNr 06_drivers_gpio_uart/src/bsp/raspberrypi/memory.rs 07_uart_chainloader +} + +/// Return the inclusive range spanning the relocated kernel binary. -+/// -+/// # Safety -+/// + /// + /// # Safety + /// +-/// - Value is provided by the linker script and must be trusted as-is. +-#[inline(always)] +-fn rx_start() -> usize { +- unsafe { __rx_start.get() as usize } +/// - Values are provided by the linker script and must be trusted as-is. +/// - The linker-provided addresses must be u64 aligned. +pub fn relocated_binary_range_inclusive() -> RangeInclusive<*mut u64> { + unsafe { RangeInclusive::new(__binary_start.get(), __binary_end_inclusive.get()) } -+} -+ + } + +-//-------------------------------------------------------------------------------------------------- +-// Public Code +-//-------------------------------------------------------------------------------------------------- +- +-/// Exclusive end address of the boot core's stack. +/// The relocated address of function `runtime_init()`. -+#[inline(always)] + #[inline(always)] +-pub fn boot_core_stack_end() -> usize { +- rx_start() +pub fn relocated_runtime_init_addr() -> *const u64 { + unsafe { __runtime_init_reloc.get() as _ } -+} -+ + } + +-/// Return the inclusive range spanning the .bss section. +/// Return the inclusive range spanning the relocated .bss section. /// /// # Safety @@ -498,7 +507,7 @@ diff -uNr 06_drivers_gpio_uart/src/main.rs 07_uart_chainloader/src/main.rs diff -uNr 06_drivers_gpio_uart/src/relocate.rs 07_uart_chainloader/src/relocate.rs --- 06_drivers_gpio_uart/src/relocate.rs +++ 07_uart_chainloader/src/relocate.rs -@@ -0,0 +1,51 @@ +@@ -0,0 +1,49 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2021 Andre Richter @@ -537,16 +546,14 @@ diff -uNr 06_drivers_gpio_uart/src/relocate.rs 07_uart_chainloader/src/relocate. + current_binary_start_addr = current_binary_start_addr.offset(1); + } + -+ // The following function calls form a hack to achieve an "absolute jump" to -+ // `runtime_init::runtime_init()` by forcing an indirection through the global offset table -+ // (GOT), so that execution continues from the relocated binary. -+ // -+ // Without this, the address of `runtime_init()` would be calculated as a relative offset from -+ // the current program counter, since we are compiling as `position independent code`. This -+ // would cause us to keep executing from the address to which the firmware loaded us, instead of -+ // the relocated position. ++ // The following function calls realize an "absolute jump" to `runtime_init::runtime_init()` by ++ // forcing an indirection through the global offset table (GOT), so that execution continues ++ // from the relocated binary. + // -+ // There likely is a more elegant way to do this. ++ // Without the indirection through the assembly, the address of `runtime_init()` would be ++ // calculated as a relative offset from the current program counter, since we are compiling as ++ // `position independent code`. This would cause us to keep executing from the address to which ++ // the firmware loaded us, instead of the relocated position. + let relocated_runtime_init_addr = bsp::memory::relocated_runtime_init_addr() as usize; + cpu::branch_to_raw_addr(relocated_runtime_init_addr) +} diff --git a/07_uart_chainloader/demo_payload_rpi3.img b/07_uart_chainloader/demo_payload_rpi3.img index a46c0d4149a22954048d876138fda7825a398700..79eef6b4ca54773cbe15dd88f8b48e0ea9a8541a 100755 GIT binary patch delta 1022 zcmZ8fL1@!p6#oCTS=+hUrdyh(*tKjQeDD1)S?*r#E{Pt5 zo_l+Ab1j_UuuWTV_KO|;hSH=>(CGw zJi2y>v`~kc{tOAxO!bmgyPZO1AALTJjAB}ABOe}yNWy?yfxK_MjlAejT4*EC#U0GR z&p<}(43M3th&S0yvu45AD55wliS*z!6d++q7~`k`jU&j( z2LOj8`K!l4wnT4qwRU`mZ0M~pD*vl4fFMbU8OdSkSGHq;VY&i4CSXX)&t3^TRRP9s zF|WN21*W$${UpQmAF|{BdWGqGUE>Tlu=);$*%Tbw0$=!AVm{)GvCQNW!!H@Om(w#Z zvMQDpwxlpKcT|Kfxtyn)EGw`XmV6U_hm8Z4bJ&C)Igf26yQgfk!wbyM$|}7+GTzVl dEm)Ut2%~JqC}S^x7D>@poGzJKDk)Dr*z delta 1028 zcmZ8fUuaTM96smj-Mni$hV6WMgNEh&Ogp%esLFtV4Pn%3x{ zjqvOY+FQ9^vZq3VeA@_u=%EI&*Xf>?MG*DkirKl|GZ;H?@A3P7-|zeVxxNgn1`2`( zK2N>rl^K{WpJPr!DB&5+Lnz~)nsKIPDTlQa5X$Ap>?p&^F67OWx7x!j^p}lYzo8(X zLB{|nbOP|Y9s_8$IEa=Yw(76Qxn8seaw$z$w2=mmt!9kb+z*4spGjQ_5H(oG%lb)g z-h}EJfU50nB}iCVvY{&R*>!76VH{BFuaM+!=?9 z*3JZeVhn~P7rK$_M;SJkS^!S8qk%}*Y(ABM^i}a()aFv$P`u$|qm>z<$M0i7h1<)e zbVGRG7#j%08{Sa75rMkz90Zrhx(W<=faF0Lk~y;OLAHOYTWdKXob3+6P5i3+8J{*I zk4W5zURj`b15fvS@*ZM63R`ocYCk~rcF<_fYfInyH6^7los1_0hfC?c>QcK;pFlhB z0lL1g)>C?cFqZ-VFAGWN#5KX}onlBbIUbeBe4IWm9EqGlVYYMZ)~kJ~y48t&JBw+z_EyycdB&#Jajpy3?F?p?6*Ft@5F57r-~AO%S(mb5Cglu{$w_3i9?E!&n= zs}Xu?|It+$^I-vN`Ff!f<03sN-o_<5BlhB4K4$B~xRk#k?G>a_kVFIdiRzsaZp}N_ zE@CwhBWn=K)_}}hCn6Vf?PTZ$t#uv433|a5!Z+x!tFz_3o0P*gy(}W)1ZGdF9Y~zB(NycJTHR z9gsu2G?f&;ATkX)*f2&iGTOcy`CbqwPvB{BJ2?oTE=zWI|~;6lh}VW{3Z)LPgNA zS<%B4V`S8Zwwu*B{&cabn*E8w9Ma+)I8ks)-IX2*rXxu-UfXWMA%Haiuhniz7lTBE zlcy5_VgrA3Jit^_QYN_udexBjkttWYD$P=&aMzYeUQj))%@QiuA?84jla8;bFfN{& zG(R?z1v8Ga(WS0R2eyB6U~~ilM#T+80KX@*k)%Lp({E$MX(q79H0Ex_3O(yiy6M|8^LS*R=jN+HkW+mf|jfSkoH2T@I z6_3+(YD@wGiqPGvH@ZUrQLxR(@`&R-od>o41KV0!w4=L|P<@$RSH1W?A@9bry!+m~{^hULJ(i6pzE}Vz!$1j*iuJq~Cb0(=uoE`7I31F)Q$W566!!(54Tlwu%}Q6%Sek6$M2+c}l8ciwfrV z7raTW2iab12_ABhL{ao4Sn=Yeh(Z!k6e*fwU1xXy3OcYm`+YMz-^~1fzAe|5_sckv znP@}_p|DKqMlA7T@(`AJP436RLc47@V!3ct>6MgnjJ06l^}H<##tVxUen-E$j?D+i zF8~;?bpt!YHnSV|c))c4BmAr@j>q^dS9h}PWtD_YtH{6_D6_9~F=0j94!KM%j+&m8 zw5p7(8kaSsc(lar?o>-M#$IABQ%QjNXMl9xKA}qQB+X0T7e*7zLEcg3C){xae$Blk z+S$ljsH&g%M^9p=s-9J}>8#zToR0#3?oK2xCD@eg8?z(ao*I(0AG-eahsVukE(4o6 z0$Tk(u=-)thGW2d^w;e!zD!+C3ft6vLq|<)9c*NMq*HkyYc<`b>641qY~U2sEge6b zqAKrcs)xVzJ83(lzROTI`$hgm4YmVi&_0ZeQOX#x!3HDhobEBRTEppL4I-%yOcxtw zd+L1(?QYh_w|F)i@CLyJ1hbyiYAMEK`tx`s%53DXjPS>v;J~+@daIHyUbp2kr~SV5 ztqK$!#5rLsT?@t7S|4Ic6>pL^;Z==kJB*aw86w1P?GyN<4815{_#Fa1sg zB5$l*-tJwG$WME-IKXROV?PbPn>z;Sju@Lr$eMLJF{Wqf?CBK#ZYEB1KLs{DOLNcY zZI+gpA{V!&0RG;$21mHZzYd!?hJu}K5)~wC2Fw3K%Xf9}itO3BHkpj<@61r+ALd!S znM^N|HLb$$`CqByp?{-QJ{Sl_Cj%Bsm&~-Pz%;&TFL*J~k$o1lvfP604O@6lVM4^| z(wKHvV7jiR{hvQ9;&ZAwf$bvys=%TP33~a(;K}Heko_sb6@epSG;>{>9Db|0knl}n zZ6Q(IiUJ&zt*=wUH}Sopp!2B9Vsrd_D20c(7V4m5ph$8qvR$aEqMqT?^lTKoOYprs Y89t|u3wEhsckqdDvtzMnf>* */ +/* The address at which the the kernel binary will be loaded by the Raspberry's firmware */ +__rpi_load_addr = 0x80000; + +ENTRY(__rpi_load_addr) + +PHDRS +{ + segment_rx PT_LOAD FLAGS(5); /* 5 == RX */ + segment_rw PT_LOAD FLAGS(6); /* 6 == RW */ +} + SECTIONS { /* Set the link address to 32 MiB */ . = 0x2000000; + /*********************************************************************************************** + * Code + RO Data + Global Offset Table + ***********************************************************************************************/ __binary_start = .; .text : { - *(.text._start) - KEEP(*(.text.runtime_init)) - *(.text*); - } + KEEP(*(.text._start)) + *(.text*) + } :segment_rx - .rodata : - { - *(.rodata*) - } + .rodata : ALIGN(8) { *(.rodata*) } :segment_rx + .got : ALIGN(8) { *(.got) } :segment_rx - .data : - { - *(.data*) - } + /*********************************************************************************************** + * Data + BSS + ***********************************************************************************************/ + .data : { *(.data*) } :segment_rw /* Section is zeroed in u64 chunks, align start and end to 8 bytes */ - .bss ALIGN(8): + .bss : ALIGN(8) { __bss_start = .; *(.bss*); . = ALIGN(8); - /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ - . += 8; + . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ __bss_end_inclusive = . - 8; - } - - .got : - { - *(.got*) - } + } :NONE /* Fill up to 8 byte, b/c relocating the binary is done in u64 chunks */ . = ALIGN(8); __binary_end_inclusive = . - 8; __runtime_init_reloc = runtime_init; - - /DISCARD/ : { *(.comment*) } } diff --git a/07_uart_chainloader/src/bsp/raspberrypi/memory.rs b/07_uart_chainloader/src/bsp/raspberrypi/memory.rs index 4b2642e3..5abfb9ef 100644 --- a/07_uart_chainloader/src/bsp/raspberrypi/memory.rs +++ b/07_uart_chainloader/src/bsp/raspberrypi/memory.rs @@ -13,17 +13,18 @@ use core::{cell::UnsafeCell, ops::RangeInclusive}; // Symbols from the linker script. extern "Rust" { static __binary_start: UnsafeCell; - static __binary_end_inclusive: UnsafeCell; - static __runtime_init_reloc: UnsafeCell; static __bss_start: UnsafeCell; static __bss_end_inclusive: UnsafeCell; + static __binary_end_inclusive: UnsafeCell; + + static __runtime_init_reloc: UnsafeCell; } //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- -/// The board's memory map. +/// The board's physical memory map. #[rustfmt::skip] pub(super) mod map { pub const BOOT_CORE_STACK_END: usize = 0x8_0000; diff --git a/07_uart_chainloader/src/relocate.rs b/07_uart_chainloader/src/relocate.rs index 85ddab67..6ac6bcce 100644 --- a/07_uart_chainloader/src/relocate.rs +++ b/07_uart_chainloader/src/relocate.rs @@ -36,16 +36,14 @@ pub unsafe fn relocate_self() -> ! { current_binary_start_addr = current_binary_start_addr.offset(1); } - // The following function calls form a hack to achieve an "absolute jump" to - // `runtime_init::runtime_init()` by forcing an indirection through the global offset table - // (GOT), so that execution continues from the relocated binary. + // The following function calls realize an "absolute jump" to `runtime_init::runtime_init()` by + // forcing an indirection through the global offset table (GOT), so that execution continues + // from the relocated binary. // - // Without this, the address of `runtime_init()` would be calculated as a relative offset from - // the current program counter, since we are compiling as `position independent code`. This - // would cause us to keep executing from the address to which the firmware loaded us, instead of - // the relocated position. - // - // There likely is a more elegant way to do this. + // Without the indirection through the assembly, the address of `runtime_init()` would be + // calculated as a relative offset from the current program counter, since we are compiling as + // `position independent code`. This would cause us to keep executing from the address to which + // the firmware loaded us, instead of the relocated position. let relocated_runtime_init_addr = bsp::memory::relocated_runtime_init_addr() as usize; cpu::branch_to_raw_addr(relocated_runtime_init_addr) } diff --git a/08_timestamps/Makefile b/08_timestamps/Makefile index 4206c528..b5a56d07 100644 --- a/08_timestamps/Makefile +++ b/08_timestamps/Makefile @@ -122,6 +122,7 @@ objdump: $(KERNEL_ELF) @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ --section .rodata \ + --section .got \ $(KERNEL_ELF) | rustfilt nm: $(KERNEL_ELF) diff --git a/08_timestamps/README.md b/08_timestamps/README.md index 55c12a7f..eebdd20c 100644 --- a/08_timestamps/README.md +++ b/08_timestamps/README.md @@ -96,14 +96,6 @@ diff -uNr 07_uart_chainloader/Makefile 08_timestamps/Makefile clippy: @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(CLIPPY_CMD) -@@ -129,7 +122,6 @@ - @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ - --section .text \ - --section .rodata \ -- --section .got \ - $(KERNEL_ELF) | rustfilt - - nm: $(KERNEL_ELF) diff -uNr 07_uart_chainloader/src/_arch/aarch64/cpu/boot.rs 08_timestamps/src/_arch/aarch64/cpu/boot.rs --- 07_uart_chainloader/src/_arch/aarch64/cpu/boot.rs @@ -369,65 +361,60 @@ diff -uNr 07_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 08 diff -uNr 07_uart_chainloader/src/bsp/raspberrypi/link.ld 08_timestamps/src/bsp/raspberrypi/link.ld --- 07_uart_chainloader/src/bsp/raspberrypi/link.ld +++ 08_timestamps/src/bsp/raspberrypi/link.ld -@@ -5,15 +5,12 @@ +@@ -16,13 +16,12 @@ SECTIONS { - /* Set the link address to 32 MiB */ - . = 0x2000000; -+ /* Set current address to the value from which the RPi starts execution */ -+ . = 0x80000; ++ . = __rpi_load_addr; + /*********************************************************************************************** + * Code + RO Data + Global Offset Table + ***********************************************************************************************/ - __binary_start = .; ++ __rx_start = .; .text : { -- *(.text._start) -- KEEP(*(.text.runtime_init)) -- *(.text*); -+ *(.text._start) *(.text*) - } - - .rodata : -@@ -38,16 +35,5 @@ + KEEP(*(.text._start)) +@@ -47,10 +46,4 @@ + . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ __bss_end_inclusive = . - 8; - } - -- .got : -- { -- *(.got*) -- } + } :NONE - - /* Fill up to 8 byte, b/c relocating the binary is done in u64 chunks */ - . = ALIGN(8); - __binary_end_inclusive = . - 8; - - __runtime_init_reloc = runtime_init; -- - /DISCARD/ : { *(.comment*) } } diff -uNr 07_uart_chainloader/src/bsp/raspberrypi/memory.rs 08_timestamps/src/bsp/raspberrypi/memory.rs --- 07_uart_chainloader/src/bsp/raspberrypi/memory.rs +++ 08_timestamps/src/bsp/raspberrypi/memory.rs -@@ -12,9 +12,6 @@ +@@ -12,12 +12,10 @@ // Symbols from the linker script. extern "Rust" { - static __binary_start: UnsafeCell; -- static __binary_end_inclusive: UnsafeCell; -- static __runtime_init_reloc: UnsafeCell; ++ static __rx_start: UnsafeCell<()>; ++ static __bss_start: UnsafeCell; static __bss_end_inclusive: UnsafeCell; +- static __binary_end_inclusive: UnsafeCell; +- +- static __runtime_init_reloc: UnsafeCell; } -@@ -26,12 +23,10 @@ - /// The board's memory map. + + //-------------------------------------------------------------------------------------------------- +@@ -27,12 +25,9 @@ + /// The board's physical memory map. #[rustfmt::skip] pub(super) mod map { - pub const BOOT_CORE_STACK_END: usize = 0x8_0000; -+ pub const BOOT_CORE_STACK_END: usize = 0x8_0000; - -- pub const BOARD_DEFAULT_LOAD_ADDRESS: usize = 0x8_0000; - +- pub const BOARD_DEFAULT_LOAD_ADDRESS: usize = 0x8_0000; + - pub const GPIO_OFFSET: usize = 0x0020_0000; - pub const UART_OFFSET: usize = 0x0020_1000; + pub const GPIO_OFFSET: usize = 0x0020_0000; @@ -435,10 +422,20 @@ diff -uNr 07_uart_chainloader/src/bsp/raspberrypi/memory.rs 08_timestamps/src/bs /// Physical devices. #[cfg(feature = "bsp_rpi3")] -@@ -64,35 +59,13 @@ - map::BOOT_CORE_STACK_END +@@ -56,44 +51,36 @@ } + //-------------------------------------------------------------------------------------------------- +-// Public Code ++// Private Code + //-------------------------------------------------------------------------------------------------- + +-/// Exclusive end address of the boot core's stack. +-#[inline(always)] +-pub fn boot_core_stack_end() -> usize { +- map::BOOT_CORE_STACK_END +-} +- -/// The address on which the Raspberry firmware loads every binary by default. -#[inline(always)] -pub fn board_default_load_addr() -> *const u64 { @@ -446,21 +443,33 @@ diff -uNr 07_uart_chainloader/src/bsp/raspberrypi/memory.rs 08_timestamps/src/bs -} - -/// Return the inclusive range spanning the relocated kernel binary. --/// --/// # Safety --/// ++/// Start address of the Read+Execute (RX) range. + /// + /// # Safety + /// -/// - Values are provided by the linker script and must be trusted as-is. -/// - The linker-provided addresses must be u64 aligned. -pub fn relocated_binary_range_inclusive() -> RangeInclusive<*mut u64> { - unsafe { RangeInclusive::new(__binary_start.get(), __binary_end_inclusive.get()) } --} -- ++/// - Value is provided by the linker script and must be trusted as-is. ++#[inline(always)] ++fn rx_start() -> usize { ++ unsafe { __rx_start.get() as usize } + } + -/// The relocated address of function `runtime_init()`. --#[inline(always)] ++//-------------------------------------------------------------------------------------------------- ++// Public Code ++//-------------------------------------------------------------------------------------------------- ++ ++/// Exclusive end address of the boot core's stack. + #[inline(always)] -pub fn relocated_runtime_init_addr() -> *const u64 { - unsafe { __runtime_init_reloc.get() as _ } --} -- ++pub fn boot_core_stack_end() -> usize { ++ rx_start() + } + -/// Return the inclusive range spanning the relocated .bss section. +/// Return the inclusive range spanning the .bss section. /// @@ -674,7 +683,7 @@ diff -uNr 07_uart_chainloader/src/print.rs 08_timestamps/src/print.rs diff -uNr 07_uart_chainloader/src/relocate.rs 08_timestamps/src/relocate.rs --- 07_uart_chainloader/src/relocate.rs +++ 08_timestamps/src/relocate.rs -@@ -1,51 +0,0 @@ +@@ -1,49 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2018-2021 Andre Richter @@ -713,16 +722,14 @@ diff -uNr 07_uart_chainloader/src/relocate.rs 08_timestamps/src/relocate.rs - current_binary_start_addr = current_binary_start_addr.offset(1); - } - -- // The following function calls form a hack to achieve an "absolute jump" to -- // `runtime_init::runtime_init()` by forcing an indirection through the global offset table -- // (GOT), so that execution continues from the relocated binary. -- // -- // Without this, the address of `runtime_init()` would be calculated as a relative offset from -- // the current program counter, since we are compiling as `position independent code`. This -- // would cause us to keep executing from the address to which the firmware loaded us, instead of -- // the relocated position. +- // The following function calls realize an "absolute jump" to `runtime_init::runtime_init()` by +- // forcing an indirection through the global offset table (GOT), so that execution continues +- // from the relocated binary. - // -- // There likely is a more elegant way to do this. +- // Without the indirection through the assembly, the address of `runtime_init()` would be +- // calculated as a relative offset from the current program counter, since we are compiling as +- // `position independent code`. This would cause us to keep executing from the address to which +- // the firmware loaded us, instead of the relocated position. - let relocated_runtime_init_addr = bsp::memory::relocated_runtime_init_addr() as usize; - cpu::branch_to_raw_addr(relocated_runtime_init_addr) -} diff --git a/08_timestamps/src/bsp/raspberrypi/link.ld b/08_timestamps/src/bsp/raspberrypi/link.ld index 573abc5f..87e6a976 100644 --- a/08_timestamps/src/bsp/raspberrypi/link.ld +++ b/08_timestamps/src/bsp/raspberrypi/link.ld @@ -3,37 +3,47 @@ * Copyright (c) 2018-2021 Andre Richter */ +/* The address at which the the kernel binary will be loaded by the Raspberry's firmware */ +__rpi_load_addr = 0x80000; + +ENTRY(__rpi_load_addr) + +PHDRS +{ + segment_rx PT_LOAD FLAGS(5); /* 5 == RX */ + segment_rw PT_LOAD FLAGS(6); /* 6 == RW */ +} + SECTIONS { - /* Set current address to the value from which the RPi starts execution */ - . = 0x80000; + . = __rpi_load_addr; + /*********************************************************************************************** + * Code + RO Data + Global Offset Table + ***********************************************************************************************/ + __rx_start = .; .text : { - *(.text._start) *(.text*) - } + KEEP(*(.text._start)) + *(.text*) + } :segment_rx - .rodata : - { - *(.rodata*) - } + .rodata : ALIGN(8) { *(.rodata*) } :segment_rx + .got : ALIGN(8) { *(.got) } :segment_rx - .data : - { - *(.data*) - } + /*********************************************************************************************** + * Data + BSS + ***********************************************************************************************/ + .data : { *(.data*) } :segment_rw /* Section is zeroed in u64 chunks, align start and end to 8 bytes */ - .bss ALIGN(8): + .bss : ALIGN(8) { __bss_start = .; *(.bss*); . = ALIGN(8); - /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ - . += 8; + . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ __bss_end_inclusive = . - 8; - } - - /DISCARD/ : { *(.comment*) } + } :NONE } diff --git a/08_timestamps/src/bsp/raspberrypi/memory.rs b/08_timestamps/src/bsp/raspberrypi/memory.rs index fb47b141..56a3306e 100644 --- a/08_timestamps/src/bsp/raspberrypi/memory.rs +++ b/08_timestamps/src/bsp/raspberrypi/memory.rs @@ -12,6 +12,8 @@ use core::{cell::UnsafeCell, ops::RangeInclusive}; // Symbols from the linker script. extern "Rust" { + static __rx_start: UnsafeCell<()>; + static __bss_start: UnsafeCell; static __bss_end_inclusive: UnsafeCell; } @@ -20,10 +22,9 @@ extern "Rust" { // Public Definitions //-------------------------------------------------------------------------------------------------- -/// The board's memory map. +/// The board's physical memory map. #[rustfmt::skip] pub(super) mod map { - pub const BOOT_CORE_STACK_END: usize = 0x8_0000; pub const GPIO_OFFSET: usize = 0x0020_0000; pub const UART_OFFSET: usize = 0x0020_1000; @@ -49,6 +50,20 @@ pub(super) mod map { } } +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +/// Start address of the Read+Execute (RX) range. +/// +/// # Safety +/// +/// - Value is provided by the linker script and must be trusted as-is. +#[inline(always)] +fn rx_start() -> usize { + unsafe { __rx_start.get() as usize } +} + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- @@ -56,7 +71,7 @@ pub(super) mod map { /// Exclusive end address of the boot core's stack. #[inline(always)] pub fn boot_core_stack_end() -> usize { - map::BOOT_CORE_STACK_END + rx_start() } /// Return the inclusive range spanning the .bss section. diff --git a/09_hw_debug_JTAG/Makefile b/09_hw_debug_JTAG/Makefile index 038244e7..e3dcaae8 100644 --- a/09_hw_debug_JTAG/Makefile +++ b/09_hw_debug_JTAG/Makefile @@ -147,6 +147,7 @@ objdump: $(KERNEL_ELF) @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ --section .rodata \ + --section .got \ $(KERNEL_ELF) | rustfilt nm: $(KERNEL_ELF) diff --git a/09_hw_debug_JTAG/src/bsp/raspberrypi/link.ld b/09_hw_debug_JTAG/src/bsp/raspberrypi/link.ld index 573abc5f..87e6a976 100644 --- a/09_hw_debug_JTAG/src/bsp/raspberrypi/link.ld +++ b/09_hw_debug_JTAG/src/bsp/raspberrypi/link.ld @@ -3,37 +3,47 @@ * Copyright (c) 2018-2021 Andre Richter */ +/* The address at which the the kernel binary will be loaded by the Raspberry's firmware */ +__rpi_load_addr = 0x80000; + +ENTRY(__rpi_load_addr) + +PHDRS +{ + segment_rx PT_LOAD FLAGS(5); /* 5 == RX */ + segment_rw PT_LOAD FLAGS(6); /* 6 == RW */ +} + SECTIONS { - /* Set current address to the value from which the RPi starts execution */ - . = 0x80000; + . = __rpi_load_addr; + /*********************************************************************************************** + * Code + RO Data + Global Offset Table + ***********************************************************************************************/ + __rx_start = .; .text : { - *(.text._start) *(.text*) - } + KEEP(*(.text._start)) + *(.text*) + } :segment_rx - .rodata : - { - *(.rodata*) - } + .rodata : ALIGN(8) { *(.rodata*) } :segment_rx + .got : ALIGN(8) { *(.got) } :segment_rx - .data : - { - *(.data*) - } + /*********************************************************************************************** + * Data + BSS + ***********************************************************************************************/ + .data : { *(.data*) } :segment_rw /* Section is zeroed in u64 chunks, align start and end to 8 bytes */ - .bss ALIGN(8): + .bss : ALIGN(8) { __bss_start = .; *(.bss*); . = ALIGN(8); - /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ - . += 8; + . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ __bss_end_inclusive = . - 8; - } - - /DISCARD/ : { *(.comment*) } + } :NONE } diff --git a/09_hw_debug_JTAG/src/bsp/raspberrypi/memory.rs b/09_hw_debug_JTAG/src/bsp/raspberrypi/memory.rs index fb47b141..56a3306e 100644 --- a/09_hw_debug_JTAG/src/bsp/raspberrypi/memory.rs +++ b/09_hw_debug_JTAG/src/bsp/raspberrypi/memory.rs @@ -12,6 +12,8 @@ use core::{cell::UnsafeCell, ops::RangeInclusive}; // Symbols from the linker script. extern "Rust" { + static __rx_start: UnsafeCell<()>; + static __bss_start: UnsafeCell; static __bss_end_inclusive: UnsafeCell; } @@ -20,10 +22,9 @@ extern "Rust" { // Public Definitions //-------------------------------------------------------------------------------------------------- -/// The board's memory map. +/// The board's physical memory map. #[rustfmt::skip] pub(super) mod map { - pub const BOOT_CORE_STACK_END: usize = 0x8_0000; pub const GPIO_OFFSET: usize = 0x0020_0000; pub const UART_OFFSET: usize = 0x0020_1000; @@ -49,6 +50,20 @@ pub(super) mod map { } } +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +/// Start address of the Read+Execute (RX) range. +/// +/// # Safety +/// +/// - Value is provided by the linker script and must be trusted as-is. +#[inline(always)] +fn rx_start() -> usize { + unsafe { __rx_start.get() as usize } +} + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- @@ -56,7 +71,7 @@ pub(super) mod map { /// Exclusive end address of the boot core's stack. #[inline(always)] pub fn boot_core_stack_end() -> usize { - map::BOOT_CORE_STACK_END + rx_start() } /// Return the inclusive range spanning the .bss section. diff --git a/10_privilege_level/Makefile b/10_privilege_level/Makefile index 038244e7..e3dcaae8 100644 --- a/10_privilege_level/Makefile +++ b/10_privilege_level/Makefile @@ -147,6 +147,7 @@ objdump: $(KERNEL_ELF) @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ --section .rodata \ + --section .got \ $(KERNEL_ELF) | rustfilt nm: $(KERNEL_ELF) diff --git a/10_privilege_level/README.md b/10_privilege_level/README.md index 0d58e281..2c435548 100644 --- a/10_privilege_level/README.md +++ b/10_privilege_level/README.md @@ -136,7 +136,7 @@ Finally, we set the stack pointer for `SP_EL1` and call `ERET`: ```rust // Set up SP_EL1 (stack pointer), which will be used by EL1 once we "return" to it. -SP_EL1.set(bsp::cpu::BOOT_CORE_STACK_START); +SP_EL1.set(bsp::memory::boot_core_stack_end() as u64); // Use `eret` to "return" to EL1. This results in execution of runtime_init() in EL1. asm::eret() diff --git a/10_privilege_level/src/bsp/raspberrypi/link.ld b/10_privilege_level/src/bsp/raspberrypi/link.ld index 573abc5f..87e6a976 100644 --- a/10_privilege_level/src/bsp/raspberrypi/link.ld +++ b/10_privilege_level/src/bsp/raspberrypi/link.ld @@ -3,37 +3,47 @@ * Copyright (c) 2018-2021 Andre Richter */ +/* The address at which the the kernel binary will be loaded by the Raspberry's firmware */ +__rpi_load_addr = 0x80000; + +ENTRY(__rpi_load_addr) + +PHDRS +{ + segment_rx PT_LOAD FLAGS(5); /* 5 == RX */ + segment_rw PT_LOAD FLAGS(6); /* 6 == RW */ +} + SECTIONS { - /* Set current address to the value from which the RPi starts execution */ - . = 0x80000; + . = __rpi_load_addr; + /*********************************************************************************************** + * Code + RO Data + Global Offset Table + ***********************************************************************************************/ + __rx_start = .; .text : { - *(.text._start) *(.text*) - } + KEEP(*(.text._start)) + *(.text*) + } :segment_rx - .rodata : - { - *(.rodata*) - } + .rodata : ALIGN(8) { *(.rodata*) } :segment_rx + .got : ALIGN(8) { *(.got) } :segment_rx - .data : - { - *(.data*) - } + /*********************************************************************************************** + * Data + BSS + ***********************************************************************************************/ + .data : { *(.data*) } :segment_rw /* Section is zeroed in u64 chunks, align start and end to 8 bytes */ - .bss ALIGN(8): + .bss : ALIGN(8) { __bss_start = .; *(.bss*); . = ALIGN(8); - /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ - . += 8; + . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ __bss_end_inclusive = . - 8; - } - - /DISCARD/ : { *(.comment*) } + } :NONE } diff --git a/10_privilege_level/src/bsp/raspberrypi/memory.rs b/10_privilege_level/src/bsp/raspberrypi/memory.rs index fb47b141..56a3306e 100644 --- a/10_privilege_level/src/bsp/raspberrypi/memory.rs +++ b/10_privilege_level/src/bsp/raspberrypi/memory.rs @@ -12,6 +12,8 @@ use core::{cell::UnsafeCell, ops::RangeInclusive}; // Symbols from the linker script. extern "Rust" { + static __rx_start: UnsafeCell<()>; + static __bss_start: UnsafeCell; static __bss_end_inclusive: UnsafeCell; } @@ -20,10 +22,9 @@ extern "Rust" { // Public Definitions //-------------------------------------------------------------------------------------------------- -/// The board's memory map. +/// The board's physical memory map. #[rustfmt::skip] pub(super) mod map { - pub const BOOT_CORE_STACK_END: usize = 0x8_0000; pub const GPIO_OFFSET: usize = 0x0020_0000; pub const UART_OFFSET: usize = 0x0020_1000; @@ -49,6 +50,20 @@ pub(super) mod map { } } +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +/// Start address of the Read+Execute (RX) range. +/// +/// # Safety +/// +/// - Value is provided by the linker script and must be trusted as-is. +#[inline(always)] +fn rx_start() -> usize { + unsafe { __rx_start.get() as usize } +} + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- @@ -56,7 +71,7 @@ pub(super) mod map { /// Exclusive end address of the boot core's stack. #[inline(always)] pub fn boot_core_stack_end() -> usize { - map::BOOT_CORE_STACK_END + rx_start() } /// Return the inclusive range spanning the .bss section. diff --git a/11_virtual_mem_part1_identity_mapping/Makefile b/11_virtual_mem_part1_identity_mapping/Makefile index 038244e7..e3dcaae8 100644 --- a/11_virtual_mem_part1_identity_mapping/Makefile +++ b/11_virtual_mem_part1_identity_mapping/Makefile @@ -147,6 +147,7 @@ objdump: $(KERNEL_ELF) @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ --section .rodata \ + --section .got \ $(KERNEL_ELF) | rustfilt nm: $(KERNEL_ELF) diff --git a/11_virtual_mem_part1_identity_mapping/README.md b/11_virtual_mem_part1_identity_mapping/README.md index 270c8422..bebf518e 100644 --- a/11_virtual_mem_part1_identity_mapping/README.md +++ b/11_virtual_mem_part1_identity_mapping/README.md @@ -224,10 +224,16 @@ enables caching for data and instructions. ### `link.ld` -We need to align the `ro` section to `64 KiB` so that it doesn't overlap with the next section that -needs read/write attributes. This blows up the binary in size, but is a small price to pay -considering that it reduces the amount of static paging entries significantly, when compared to the -classical `4 KiB` granule. +We need to align the `rx` segment to `64 KiB` so that it doesn't overlap with the next section that +needs read/write attributes instead of read/execute attributes: + +```ld.s +. = ALIGN(64K); /* Align to page boundary */ +__rx_end_exclusive = .; +``` + +This blows up the binary in size, but is a small price to pay considering that it reduces the amount +of static paging entries significantly, when compared to the classical `4 KiB` granule. ## Address translation examples @@ -807,23 +813,16 @@ diff -uNr 10_privilege_level/src/_arch/aarch64/memory/mmu.rs 11_virtual_mem_part diff -uNr 10_privilege_level/src/bsp/raspberrypi/link.ld 11_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/link.ld --- 10_privilege_level/src/bsp/raspberrypi/link.ld +++ 11_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/link.ld -@@ -8,6 +8,7 @@ - /* Set current address to the value from which the RPi starts execution */ - . = 0x80000; - -+ __ro_start = .; - .text : - { - *(.text._start) *(.text*) -@@ -17,6 +18,8 @@ - { - *(.rodata*) - } -+ . = ALIGN(65536); /* Fill up to 64 KiB */ -+ __ro_end = .; +@@ -31,6 +31,9 @@ + .rodata : ALIGN(8) { *(.rodata*) } :segment_rx + .got : ALIGN(8) { *(.got) } :segment_rx - .data : - { ++ . = ALIGN(64K); /* Align to page boundary */ ++ __rx_end_exclusive = .; ++ + /*********************************************************************************************** + * Data + BSS + ***********************************************************************************************/ diff -uNr 10_privilege_level/src/bsp/raspberrypi/memory/mmu.rs 11_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/memory/mmu.rs --- 10_privilege_level/src/bsp/raspberrypi/memory/mmu.rs @@ -857,7 +856,7 @@ diff -uNr 10_privilege_level/src/bsp/raspberrypi/memory/mmu.rs 11_virtual_mem_pa + [ + TranslationDescriptor { + name: "Kernel code and RO data", -+ virtual_range: ro_range_inclusive, ++ virtual_range: rx_range_inclusive, + physical_range_translation: Translation::Identity, + attribute_fields: AttributeFields { + mem_attributes: MemAttributes::CacheableDRAM, @@ -892,10 +891,10 @@ diff -uNr 10_privilege_level/src/bsp/raspberrypi/memory/mmu.rs 11_virtual_mem_pa +// Private Code +//-------------------------------------------------------------------------------------------------- + -+fn ro_range_inclusive() -> RangeInclusive { ++fn rx_range_inclusive() -> RangeInclusive { + // Notice the subtraction to turn the exclusive end into an inclusive end. + #[allow(clippy::range_minus_one)] -+ RangeInclusive::new(super::ro_start(), super::ro_end() - 1) ++ RangeInclusive::new(super::rx_start(), super::rx_end_exclusive() - 1) +} + +fn remapped_mmio_range_inclusive() -> RangeInclusive { @@ -928,17 +927,16 @@ diff -uNr 10_privilege_level/src/bsp/raspberrypi/memory.rs 11_virtual_mem_part1_ use core::{cell::UnsafeCell, ops::RangeInclusive}; //-------------------------------------------------------------------------------------------------- -@@ -14,6 +16,8 @@ +@@ -13,6 +15,7 @@ + // Symbols from the linker script. extern "Rust" { + static __rx_start: UnsafeCell<()>; ++ static __rx_end_exclusive: UnsafeCell<()>; + static __bss_start: UnsafeCell; static __bss_end_inclusive: UnsafeCell; -+ static __ro_start: UnsafeCell<()>; -+ static __ro_end: UnsafeCell<()>; - } - - //-------------------------------------------------------------------------------------------------- -@@ -23,6 +27,21 @@ - /// The board's memory map. +@@ -25,6 +28,20 @@ + /// The board's physical memory map. #[rustfmt::skip] pub(super) mod map { + /// The inclusive end address of the memory map. @@ -955,11 +953,10 @@ diff -uNr 10_privilege_level/src/bsp/raspberrypi/memory.rs 11_virtual_mem_part1_ + /// physical address that is not backed by any DRAM (e.g. accessing an address close to 4 GiB on + /// an RPi3 that comes with 1 GiB of RAM). This would result in a crash or other kind of error. + pub const END_INCLUSIVE: usize = 0xFFFF_FFFF; -+ - pub const BOOT_CORE_STACK_END: usize = 0x8_0000; pub const GPIO_OFFSET: usize = 0x0020_0000; -@@ -36,6 +55,7 @@ + pub const UART_OFFSET: usize = 0x0020_1000; +@@ -37,6 +54,7 @@ pub const START: usize = 0x3F00_0000; pub const GPIO_START: usize = START + GPIO_OFFSET; pub const PL011_UART_START: usize = START + UART_OFFSET; @@ -967,7 +964,7 @@ diff -uNr 10_privilege_level/src/bsp/raspberrypi/memory.rs 11_virtual_mem_part1_ } /// Physical devices. -@@ -46,10 +66,35 @@ +@@ -47,6 +65,7 @@ pub const START: usize = 0xFE00_0000; pub const GPIO_START: usize = START + GPIO_OFFSET; pub const PL011_UART_START: usize = START + UART_OFFSET; @@ -975,35 +972,24 @@ diff -uNr 10_privilege_level/src/bsp/raspberrypi/memory.rs 11_virtual_mem_part1_ } } - //-------------------------------------------------------------------------------------------------- -+// Private Code -+//-------------------------------------------------------------------------------------------------- -+ -+/// Start address of the Read-Only (RO) range. -+/// -+/// # Safety -+/// -+/// - Value is provided by the linker script and must be trusted as-is. -+#[inline(always)] -+fn ro_start() -> usize { -+ unsafe { __ro_start.get() as usize } -+} -+ -+/// Size of the Read-Only (RO) range of the kernel binary. +@@ -64,6 +83,16 @@ + unsafe { __rx_start.get() as usize } + } + ++/// Exclusive end address of the Read+Execute (RX) range. +/// +/// # Safety +/// +/// - Value is provided by the linker script and must be trusted as-is. +#[inline(always)] -+fn ro_end() -> usize { -+ unsafe { __ro_end.get() as usize } ++fn rx_end_exclusive() -> usize { ++ unsafe { __rx_end_exclusive.get() as usize } +} + -+//-------------------------------------------------------------------------------------------------- + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- - diff -uNr 10_privilege_level/src/bsp.rs 11_virtual_mem_part1_identity_mapping/src/bsp.rs --- 10_privilege_level/src/bsp.rs +++ 11_virtual_mem_part1_identity_mapping/src/bsp.rs diff --git a/11_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/link.ld b/11_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/link.ld index aec8e79b..6c63ba10 100644 --- a/11_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/link.ld +++ b/11_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/link.ld @@ -3,40 +3,50 @@ * Copyright (c) 2018-2021 Andre Richter */ +/* The address at which the the kernel binary will be loaded by the Raspberry's firmware */ +__rpi_load_addr = 0x80000; + +ENTRY(__rpi_load_addr) + +PHDRS +{ + segment_rx PT_LOAD FLAGS(5); /* 5 == RX */ + segment_rw PT_LOAD FLAGS(6); /* 6 == RW */ +} + SECTIONS { - /* Set current address to the value from which the RPi starts execution */ - . = 0x80000; + . = __rpi_load_addr; - __ro_start = .; + /*********************************************************************************************** + * Code + RO Data + Global Offset Table + ***********************************************************************************************/ + __rx_start = .; .text : { - *(.text._start) *(.text*) - } + KEEP(*(.text._start)) + *(.text*) + } :segment_rx - .rodata : - { - *(.rodata*) - } - . = ALIGN(65536); /* Fill up to 64 KiB */ - __ro_end = .; + .rodata : ALIGN(8) { *(.rodata*) } :segment_rx + .got : ALIGN(8) { *(.got) } :segment_rx - .data : - { - *(.data*) - } + . = ALIGN(64K); /* Align to page boundary */ + __rx_end_exclusive = .; + + /*********************************************************************************************** + * Data + BSS + ***********************************************************************************************/ + .data : { *(.data*) } :segment_rw /* Section is zeroed in u64 chunks, align start and end to 8 bytes */ - .bss ALIGN(8): + .bss : ALIGN(8) { __bss_start = .; *(.bss*); . = ALIGN(8); - /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ - . += 8; + . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ __bss_end_inclusive = . - 8; - } - - /DISCARD/ : { *(.comment*) } + } :NONE } diff --git a/11_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/memory.rs b/11_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/memory.rs index d4bcf0a3..bb18dd20 100644 --- a/11_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/memory.rs +++ b/11_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/memory.rs @@ -14,17 +14,18 @@ use core::{cell::UnsafeCell, ops::RangeInclusive}; // Symbols from the linker script. extern "Rust" { + static __rx_start: UnsafeCell<()>; + static __rx_end_exclusive: UnsafeCell<()>; + static __bss_start: UnsafeCell; static __bss_end_inclusive: UnsafeCell; - static __ro_start: UnsafeCell<()>; - static __ro_end: UnsafeCell<()>; } //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- -/// The board's memory map. +/// The board's physical memory map. #[rustfmt::skip] pub(super) mod map { /// The inclusive end address of the memory map. @@ -42,8 +43,6 @@ pub(super) mod map { /// an RPi3 that comes with 1 GiB of RAM). This would result in a crash or other kind of error. pub const END_INCLUSIVE: usize = 0xFFFF_FFFF; - pub const BOOT_CORE_STACK_END: usize = 0x8_0000; - pub const GPIO_OFFSET: usize = 0x0020_0000; pub const UART_OFFSET: usize = 0x0020_1000; @@ -74,24 +73,24 @@ pub(super) mod map { // Private Code //-------------------------------------------------------------------------------------------------- -/// Start address of the Read-Only (RO) range. +/// Start address of the Read+Execute (RX) range. /// /// # Safety /// /// - Value is provided by the linker script and must be trusted as-is. #[inline(always)] -fn ro_start() -> usize { - unsafe { __ro_start.get() as usize } +fn rx_start() -> usize { + unsafe { __rx_start.get() as usize } } -/// Size of the Read-Only (RO) range of the kernel binary. +/// Exclusive end address of the Read+Execute (RX) range. /// /// # Safety /// /// - Value is provided by the linker script and must be trusted as-is. #[inline(always)] -fn ro_end() -> usize { - unsafe { __ro_end.get() as usize } +fn rx_end_exclusive() -> usize { + unsafe { __rx_end_exclusive.get() as usize } } //-------------------------------------------------------------------------------------------------- @@ -101,7 +100,7 @@ fn ro_end() -> usize { /// Exclusive end address of the boot core's stack. #[inline(always)] pub fn boot_core_stack_end() -> usize { - map::BOOT_CORE_STACK_END + rx_start() } /// Return the inclusive range spanning the .bss section. diff --git a/11_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/memory/mmu.rs b/11_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/memory/mmu.rs index 703bb3ba..cf9cfcae 100644 --- a/11_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/memory/mmu.rs +++ b/11_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/memory/mmu.rs @@ -26,7 +26,7 @@ pub static LAYOUT: KernelVirtualLayout = KernelVirtualLayout::ne [ TranslationDescriptor { name: "Kernel code and RO data", - virtual_range: ro_range_inclusive, + virtual_range: rx_range_inclusive, physical_range_translation: Translation::Identity, attribute_fields: AttributeFields { mem_attributes: MemAttributes::CacheableDRAM, @@ -61,10 +61,10 @@ pub static LAYOUT: KernelVirtualLayout = KernelVirtualLayout::ne // Private Code //-------------------------------------------------------------------------------------------------- -fn ro_range_inclusive() -> RangeInclusive { +fn rx_range_inclusive() -> RangeInclusive { // Notice the subtraction to turn the exclusive end into an inclusive end. #[allow(clippy::range_minus_one)] - RangeInclusive::new(super::ro_start(), super::ro_end() - 1) + RangeInclusive::new(super::rx_start(), super::rx_end_exclusive() - 1) } fn remapped_mmio_range_inclusive() -> RangeInclusive { diff --git a/12_exceptions_part1_groundwork/Makefile b/12_exceptions_part1_groundwork/Makefile index 038244e7..e3dcaae8 100644 --- a/12_exceptions_part1_groundwork/Makefile +++ b/12_exceptions_part1_groundwork/Makefile @@ -147,6 +147,7 @@ objdump: $(KERNEL_ELF) @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ --section .rodata \ + --section .got \ $(KERNEL_ELF) | rustfilt nm: $(KERNEL_ELF) diff --git a/12_exceptions_part1_groundwork/README.md b/12_exceptions_part1_groundwork/README.md index 0ce07116..b495742d 100644 --- a/12_exceptions_part1_groundwork/README.md +++ b/12_exceptions_part1_groundwork/README.md @@ -238,7 +238,7 @@ because `Rust` has no stable convention ([yet](https://github.com/rust-lang/rfcs Next, we craft the exception vector table: ```asm -.section .exception_vectors, "ax", @progbits +.section .text // Align by 2^11 bytes, as demanded by ARMv8-A. Same as ALIGN(2048) in an ld script. .align 11 @@ -324,7 +324,7 @@ The actual handlers referenced from the assembly can now branch to it for the ti ```rust #[no_mangle] -unsafe extern "C" fn current_el0_synchronous(e: &mut ExceptionContext) { +unsafe extern "C" fn current_elx_irq(e: &mut ExceptionContext) { default_exception_handler(e); } ``` @@ -480,7 +480,7 @@ General purpose register: diff -uNr 11_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs 12_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs --- 11_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs +++ 12_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs -@@ -11,7 +11,230 @@ +@@ -11,7 +11,224 @@ //! //! crate::exception::arch_exception @@ -541,18 +541,18 @@ diff -uNr 11_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs 1 +//------------------------------------------------------------------------------ + +#[no_mangle] -+unsafe extern "C" fn current_el0_synchronous(e: &mut ExceptionContext) { -+ default_exception_handler(e); ++unsafe extern "C" fn current_el0_synchronous(_e: &mut ExceptionContext) { ++ panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") +} + +#[no_mangle] -+unsafe extern "C" fn current_el0_irq(e: &mut ExceptionContext) { -+ default_exception_handler(e); ++unsafe extern "C" fn current_el0_irq(_e: &mut ExceptionContext) { ++ panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") +} + +#[no_mangle] -+unsafe extern "C" fn current_el0_serror(e: &mut ExceptionContext) { -+ default_exception_handler(e); ++unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { ++ panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") +} + +//------------------------------------------------------------------------------ @@ -646,9 +646,7 @@ diff -uNr 11_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs 1 + writeln!(f, " - {}", ec_translation)?; + + // Raw print of instruction specific syndrome. -+ write!(f, " Instr Specific Syndrome (ISS): {:#x}", esr_el1.read(ESR_EL1::ISS))?; -+ -+ Ok(()) ++ write!(f, " Instr Specific Syndrome (ISS): {:#x}", esr_el1.read(ESR_EL1::ISS)) + } +} + @@ -681,9 +679,7 @@ diff -uNr 11_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs 1 + + write!(f, " Illegal Execution State (IL): {}", + to_flag_str(self.0.is_set(SPSR_EL1::IL)) -+ )?; -+ -+ Ok(()) ++ ) + } +} + @@ -704,15 +700,13 @@ diff -uNr 11_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs 1 + for (i, reg) in self.gpr.iter().enumerate() { + write!(f, " x{: <2}: {: >#018x}{}", i, reg, alternating(i))?; + } -+ write!(f, " lr : {:#018x}", self.lr)?; -+ -+ Ok(()) ++ write!(f, " lr : {:#018x}", self.lr) + } +} //-------------------------------------------------------------------------------------------------- // Public Code -@@ -28,3 +251,23 @@ +@@ -28,3 +245,23 @@ _ => (PrivilegeLevel::Unknown, "Unknown"), } } @@ -793,7 +787,7 @@ diff -uNr 11_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.S 12 +//-------------------------------------------------------------------------------------------------- +// The exception vector table. +//-------------------------------------------------------------------------------------------------- -+.section .exception_vectors, "ax", @progbits ++.section .text + +// Align by 2^11 bytes, as demanded by ARMv8-A. Same as ALIGN(2048) in an ld script. +.align 11 @@ -880,22 +874,6 @@ diff -uNr 11_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.S 12 + + eret -diff -uNr 11_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/link.ld 12_exceptions_part1_groundwork/src/bsp/raspberrypi/link.ld ---- 11_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/link.ld -+++ 12_exceptions_part1_groundwork/src/bsp/raspberrypi/link.ld -@@ -14,6 +14,11 @@ - *(.text._start) *(.text*) - } - -+ .exception_vectors : -+ { -+ *(.exception_vectors*) -+ } -+ - .rodata : - { - *(.rodata*) - diff -uNr 11_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/memory/mmu.rs 12_exceptions_part1_groundwork/src/bsp/raspberrypi/memory/mmu.rs --- 11_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/memory/mmu.rs +++ 12_exceptions_part1_groundwork/src/bsp/raspberrypi/memory/mmu.rs @@ -926,7 +904,7 @@ diff -uNr 11_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/memory/mmu.r virtual_range: mmio_range_inclusive, physical_range_translation: Translation::Identity, @@ -67,11 +57,6 @@ - RangeInclusive::new(super::ro_start(), super::ro_end() - 1) + RangeInclusive::new(super::rx_start(), super::rx_end_exclusive() - 1) } -fn remapped_mmio_range_inclusive() -> RangeInclusive { diff --git a/12_exceptions_part1_groundwork/src/_arch/aarch64/exception.S b/12_exceptions_part1_groundwork/src/_arch/aarch64/exception.S index 4d125334..fd7b1f93 100644 --- a/12_exceptions_part1_groundwork/src/_arch/aarch64/exception.S +++ b/12_exceptions_part1_groundwork/src/_arch/aarch64/exception.S @@ -50,7 +50,7 @@ //-------------------------------------------------------------------------------------------------- // The exception vector table. //-------------------------------------------------------------------------------------------------- -.section .exception_vectors, "ax", @progbits +.section .text // Align by 2^11 bytes, as demanded by ARMv8-A. Same as ALIGN(2048) in an ld script. .align 11 diff --git a/12_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs b/12_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs index 64f1fd23..f08d0ce4 100644 --- a/12_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs +++ b/12_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs @@ -67,18 +67,18 @@ fn default_exception_handler(e: &ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn current_el0_synchronous(e: &mut ExceptionContext) { - default_exception_handler(e); +unsafe extern "C" fn current_el0_synchronous(_e: &mut ExceptionContext) { + panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } #[no_mangle] -unsafe extern "C" fn current_el0_irq(e: &mut ExceptionContext) { - default_exception_handler(e); +unsafe extern "C" fn current_el0_irq(_e: &mut ExceptionContext) { + panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } #[no_mangle] -unsafe extern "C" fn current_el0_serror(e: &mut ExceptionContext) { - default_exception_handler(e); +unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { + panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } //------------------------------------------------------------------------------ @@ -172,9 +172,7 @@ impl fmt::Display for EsrEL1 { writeln!(f, " - {}", ec_translation)?; // Raw print of instruction specific syndrome. - write!(f, " Instr Specific Syndrome (ISS): {:#x}", esr_el1.read(ESR_EL1::ISS))?; - - Ok(()) + write!(f, " Instr Specific Syndrome (ISS): {:#x}", esr_el1.read(ESR_EL1::ISS)) } } @@ -207,9 +205,7 @@ impl fmt::Display for SpsrEL1 { write!(f, " Illegal Execution State (IL): {}", to_flag_str(self.0.is_set(SPSR_EL1::IL)) - )?; - - Ok(()) + ) } } @@ -230,9 +226,7 @@ impl fmt::Display for ExceptionContext { for (i, reg) in self.gpr.iter().enumerate() { write!(f, " x{: <2}: {: >#018x}{}", i, reg, alternating(i))?; } - write!(f, " lr : {:#018x}", self.lr)?; - - Ok(()) + write!(f, " lr : {:#018x}", self.lr) } } diff --git a/12_exceptions_part1_groundwork/src/bsp/raspberrypi/link.ld b/12_exceptions_part1_groundwork/src/bsp/raspberrypi/link.ld index 4dfe60c7..6c63ba10 100644 --- a/12_exceptions_part1_groundwork/src/bsp/raspberrypi/link.ld +++ b/12_exceptions_part1_groundwork/src/bsp/raspberrypi/link.ld @@ -3,45 +3,50 @@ * Copyright (c) 2018-2021 Andre Richter */ +/* The address at which the the kernel binary will be loaded by the Raspberry's firmware */ +__rpi_load_addr = 0x80000; + +ENTRY(__rpi_load_addr) + +PHDRS +{ + segment_rx PT_LOAD FLAGS(5); /* 5 == RX */ + segment_rw PT_LOAD FLAGS(6); /* 6 == RW */ +} + SECTIONS { - /* Set current address to the value from which the RPi starts execution */ - . = 0x80000; + . = __rpi_load_addr; - __ro_start = .; + /*********************************************************************************************** + * Code + RO Data + Global Offset Table + ***********************************************************************************************/ + __rx_start = .; .text : { - *(.text._start) *(.text*) - } + KEEP(*(.text._start)) + *(.text*) + } :segment_rx - .exception_vectors : - { - *(.exception_vectors*) - } + .rodata : ALIGN(8) { *(.rodata*) } :segment_rx + .got : ALIGN(8) { *(.got) } :segment_rx - .rodata : - { - *(.rodata*) - } - . = ALIGN(65536); /* Fill up to 64 KiB */ - __ro_end = .; + . = ALIGN(64K); /* Align to page boundary */ + __rx_end_exclusive = .; - .data : - { - *(.data*) - } + /*********************************************************************************************** + * Data + BSS + ***********************************************************************************************/ + .data : { *(.data*) } :segment_rw /* Section is zeroed in u64 chunks, align start and end to 8 bytes */ - .bss ALIGN(8): + .bss : ALIGN(8) { __bss_start = .; *(.bss*); . = ALIGN(8); - /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ - . += 8; + . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ __bss_end_inclusive = . - 8; - } - - /DISCARD/ : { *(.comment*) } + } :NONE } diff --git a/12_exceptions_part1_groundwork/src/bsp/raspberrypi/memory.rs b/12_exceptions_part1_groundwork/src/bsp/raspberrypi/memory.rs index d4bcf0a3..bb18dd20 100644 --- a/12_exceptions_part1_groundwork/src/bsp/raspberrypi/memory.rs +++ b/12_exceptions_part1_groundwork/src/bsp/raspberrypi/memory.rs @@ -14,17 +14,18 @@ use core::{cell::UnsafeCell, ops::RangeInclusive}; // Symbols from the linker script. extern "Rust" { + static __rx_start: UnsafeCell<()>; + static __rx_end_exclusive: UnsafeCell<()>; + static __bss_start: UnsafeCell; static __bss_end_inclusive: UnsafeCell; - static __ro_start: UnsafeCell<()>; - static __ro_end: UnsafeCell<()>; } //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- -/// The board's memory map. +/// The board's physical memory map. #[rustfmt::skip] pub(super) mod map { /// The inclusive end address of the memory map. @@ -42,8 +43,6 @@ pub(super) mod map { /// an RPi3 that comes with 1 GiB of RAM). This would result in a crash or other kind of error. pub const END_INCLUSIVE: usize = 0xFFFF_FFFF; - pub const BOOT_CORE_STACK_END: usize = 0x8_0000; - pub const GPIO_OFFSET: usize = 0x0020_0000; pub const UART_OFFSET: usize = 0x0020_1000; @@ -74,24 +73,24 @@ pub(super) mod map { // Private Code //-------------------------------------------------------------------------------------------------- -/// Start address of the Read-Only (RO) range. +/// Start address of the Read+Execute (RX) range. /// /// # Safety /// /// - Value is provided by the linker script and must be trusted as-is. #[inline(always)] -fn ro_start() -> usize { - unsafe { __ro_start.get() as usize } +fn rx_start() -> usize { + unsafe { __rx_start.get() as usize } } -/// Size of the Read-Only (RO) range of the kernel binary. +/// Exclusive end address of the Read+Execute (RX) range. /// /// # Safety /// /// - Value is provided by the linker script and must be trusted as-is. #[inline(always)] -fn ro_end() -> usize { - unsafe { __ro_end.get() as usize } +fn rx_end_exclusive() -> usize { + unsafe { __rx_end_exclusive.get() as usize } } //-------------------------------------------------------------------------------------------------- @@ -101,7 +100,7 @@ fn ro_end() -> usize { /// Exclusive end address of the boot core's stack. #[inline(always)] pub fn boot_core_stack_end() -> usize { - map::BOOT_CORE_STACK_END + rx_start() } /// Return the inclusive range spanning the .bss section. diff --git a/12_exceptions_part1_groundwork/src/bsp/raspberrypi/memory/mmu.rs b/12_exceptions_part1_groundwork/src/bsp/raspberrypi/memory/mmu.rs index 1775c07c..ef4bf32c 100644 --- a/12_exceptions_part1_groundwork/src/bsp/raspberrypi/memory/mmu.rs +++ b/12_exceptions_part1_groundwork/src/bsp/raspberrypi/memory/mmu.rs @@ -26,7 +26,7 @@ pub static LAYOUT: KernelVirtualLayout = KernelVirtualLayout::ne [ TranslationDescriptor { name: "Kernel code and RO data", - virtual_range: ro_range_inclusive, + virtual_range: rx_range_inclusive, physical_range_translation: Translation::Identity, attribute_fields: AttributeFields { mem_attributes: MemAttributes::CacheableDRAM, @@ -51,10 +51,10 @@ pub static LAYOUT: KernelVirtualLayout = KernelVirtualLayout::ne // Private Code //-------------------------------------------------------------------------------------------------- -fn ro_range_inclusive() -> RangeInclusive { +fn rx_range_inclusive() -> RangeInclusive { // Notice the subtraction to turn the exclusive end into an inclusive end. #[allow(clippy::range_minus_one)] - RangeInclusive::new(super::ro_start(), super::ro_end() - 1) + RangeInclusive::new(super::rx_start(), super::rx_end_exclusive() - 1) } fn mmio_range_inclusive() -> RangeInclusive { diff --git a/13_integrated_testing/Makefile b/13_integrated_testing/Makefile index 32d13924..4c2fb069 100644 --- a/13_integrated_testing/Makefile +++ b/13_integrated_testing/Makefile @@ -179,6 +179,7 @@ objdump: $(KERNEL_ELF) @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ --section .rodata \ + --section .got \ $(KERNEL_ELF) | rustfilt nm: $(KERNEL_ELF) diff --git a/13_integrated_testing/src/_arch/aarch64/exception.S b/13_integrated_testing/src/_arch/aarch64/exception.S index 4d125334..fd7b1f93 100644 --- a/13_integrated_testing/src/_arch/aarch64/exception.S +++ b/13_integrated_testing/src/_arch/aarch64/exception.S @@ -50,7 +50,7 @@ //-------------------------------------------------------------------------------------------------- // The exception vector table. //-------------------------------------------------------------------------------------------------- -.section .exception_vectors, "ax", @progbits +.section .text // Align by 2^11 bytes, as demanded by ARMv8-A. Same as ALIGN(2048) in an ld script. .align 11 diff --git a/13_integrated_testing/src/_arch/aarch64/exception.rs b/13_integrated_testing/src/_arch/aarch64/exception.rs index 0e640ec6..e67841f9 100644 --- a/13_integrated_testing/src/_arch/aarch64/exception.rs +++ b/13_integrated_testing/src/_arch/aarch64/exception.rs @@ -67,18 +67,18 @@ fn default_exception_handler(e: &ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn current_el0_synchronous(e: &mut ExceptionContext) { - default_exception_handler(e); +unsafe extern "C" fn current_el0_synchronous(_e: &mut ExceptionContext) { + panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } #[no_mangle] -unsafe extern "C" fn current_el0_irq(e: &mut ExceptionContext) { - default_exception_handler(e); +unsafe extern "C" fn current_el0_irq(_e: &mut ExceptionContext) { + panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } #[no_mangle] -unsafe extern "C" fn current_el0_serror(e: &mut ExceptionContext) { - default_exception_handler(e); +unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { + panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } //------------------------------------------------------------------------------ @@ -162,9 +162,7 @@ impl fmt::Display for EsrEL1 { writeln!(f, " - {}", ec_translation)?; // Raw print of instruction specific syndrome. - write!(f, " Instr Specific Syndrome (ISS): {:#x}", esr_el1.read(ESR_EL1::ISS))?; - - Ok(()) + write!(f, " Instr Specific Syndrome (ISS): {:#x}", esr_el1.read(ESR_EL1::ISS)) } } @@ -197,9 +195,7 @@ impl fmt::Display for SpsrEL1 { write!(f, " Illegal Execution State (IL): {}", to_flag_str(self.0.is_set(SPSR_EL1::IL)) - )?; - - Ok(()) + ) } } @@ -220,9 +216,7 @@ impl fmt::Display for ExceptionContext { for (i, reg) in self.gpr.iter().enumerate() { write!(f, " x{: <2}: {: >#018x}{}", i, reg, alternating(i))?; } - write!(f, " lr : {:#018x}", self.lr)?; - - Ok(()) + write!(f, " lr : {:#018x}", self.lr) } } diff --git a/13_integrated_testing/src/bsp/raspberrypi/link.ld b/13_integrated_testing/src/bsp/raspberrypi/link.ld index 4dfe60c7..6c63ba10 100644 --- a/13_integrated_testing/src/bsp/raspberrypi/link.ld +++ b/13_integrated_testing/src/bsp/raspberrypi/link.ld @@ -3,45 +3,50 @@ * Copyright (c) 2018-2021 Andre Richter */ +/* The address at which the the kernel binary will be loaded by the Raspberry's firmware */ +__rpi_load_addr = 0x80000; + +ENTRY(__rpi_load_addr) + +PHDRS +{ + segment_rx PT_LOAD FLAGS(5); /* 5 == RX */ + segment_rw PT_LOAD FLAGS(6); /* 6 == RW */ +} + SECTIONS { - /* Set current address to the value from which the RPi starts execution */ - . = 0x80000; + . = __rpi_load_addr; - __ro_start = .; + /*********************************************************************************************** + * Code + RO Data + Global Offset Table + ***********************************************************************************************/ + __rx_start = .; .text : { - *(.text._start) *(.text*) - } + KEEP(*(.text._start)) + *(.text*) + } :segment_rx - .exception_vectors : - { - *(.exception_vectors*) - } + .rodata : ALIGN(8) { *(.rodata*) } :segment_rx + .got : ALIGN(8) { *(.got) } :segment_rx - .rodata : - { - *(.rodata*) - } - . = ALIGN(65536); /* Fill up to 64 KiB */ - __ro_end = .; + . = ALIGN(64K); /* Align to page boundary */ + __rx_end_exclusive = .; - .data : - { - *(.data*) - } + /*********************************************************************************************** + * Data + BSS + ***********************************************************************************************/ + .data : { *(.data*) } :segment_rw /* Section is zeroed in u64 chunks, align start and end to 8 bytes */ - .bss ALIGN(8): + .bss : ALIGN(8) { __bss_start = .; *(.bss*); . = ALIGN(8); - /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ - . += 8; + . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ __bss_end_inclusive = . - 8; - } - - /DISCARD/ : { *(.comment*) } + } :NONE } diff --git a/13_integrated_testing/src/bsp/raspberrypi/memory.rs b/13_integrated_testing/src/bsp/raspberrypi/memory.rs index d4bcf0a3..bb18dd20 100644 --- a/13_integrated_testing/src/bsp/raspberrypi/memory.rs +++ b/13_integrated_testing/src/bsp/raspberrypi/memory.rs @@ -14,17 +14,18 @@ use core::{cell::UnsafeCell, ops::RangeInclusive}; // Symbols from the linker script. extern "Rust" { + static __rx_start: UnsafeCell<()>; + static __rx_end_exclusive: UnsafeCell<()>; + static __bss_start: UnsafeCell; static __bss_end_inclusive: UnsafeCell; - static __ro_start: UnsafeCell<()>; - static __ro_end: UnsafeCell<()>; } //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- -/// The board's memory map. +/// The board's physical memory map. #[rustfmt::skip] pub(super) mod map { /// The inclusive end address of the memory map. @@ -42,8 +43,6 @@ pub(super) mod map { /// an RPi3 that comes with 1 GiB of RAM). This would result in a crash or other kind of error. pub const END_INCLUSIVE: usize = 0xFFFF_FFFF; - pub const BOOT_CORE_STACK_END: usize = 0x8_0000; - pub const GPIO_OFFSET: usize = 0x0020_0000; pub const UART_OFFSET: usize = 0x0020_1000; @@ -74,24 +73,24 @@ pub(super) mod map { // Private Code //-------------------------------------------------------------------------------------------------- -/// Start address of the Read-Only (RO) range. +/// Start address of the Read+Execute (RX) range. /// /// # Safety /// /// - Value is provided by the linker script and must be trusted as-is. #[inline(always)] -fn ro_start() -> usize { - unsafe { __ro_start.get() as usize } +fn rx_start() -> usize { + unsafe { __rx_start.get() as usize } } -/// Size of the Read-Only (RO) range of the kernel binary. +/// Exclusive end address of the Read+Execute (RX) range. /// /// # Safety /// /// - Value is provided by the linker script and must be trusted as-is. #[inline(always)] -fn ro_end() -> usize { - unsafe { __ro_end.get() as usize } +fn rx_end_exclusive() -> usize { + unsafe { __rx_end_exclusive.get() as usize } } //-------------------------------------------------------------------------------------------------- @@ -101,7 +100,7 @@ fn ro_end() -> usize { /// Exclusive end address of the boot core's stack. #[inline(always)] pub fn boot_core_stack_end() -> usize { - map::BOOT_CORE_STACK_END + rx_start() } /// Return the inclusive range spanning the .bss section. diff --git a/13_integrated_testing/src/bsp/raspberrypi/memory/mmu.rs b/13_integrated_testing/src/bsp/raspberrypi/memory/mmu.rs index 0ccfae00..f4769ad3 100644 --- a/13_integrated_testing/src/bsp/raspberrypi/memory/mmu.rs +++ b/13_integrated_testing/src/bsp/raspberrypi/memory/mmu.rs @@ -26,7 +26,7 @@ pub static LAYOUT: KernelVirtualLayout = KernelVirtualLayout::ne [ TranslationDescriptor { name: "Kernel code and RO data", - virtual_range: ro_range_inclusive, + virtual_range: rx_range_inclusive, physical_range_translation: Translation::Identity, attribute_fields: AttributeFields { mem_attributes: MemAttributes::CacheableDRAM, @@ -51,10 +51,10 @@ pub static LAYOUT: KernelVirtualLayout = KernelVirtualLayout::ne // Private Code //-------------------------------------------------------------------------------------------------- -fn ro_range_inclusive() -> RangeInclusive { +fn rx_range_inclusive() -> RangeInclusive { // Notice the subtraction to turn the exclusive end into an inclusive end. #[allow(clippy::range_minus_one)] - RangeInclusive::new(super::ro_start(), super::ro_end() - 1) + RangeInclusive::new(super::rx_start(), super::rx_end_exclusive() - 1) } fn mmio_range_inclusive() -> RangeInclusive { diff --git a/14_exceptions_part2_peripheral_IRQs/Makefile b/14_exceptions_part2_peripheral_IRQs/Makefile index 32d13924..4c2fb069 100644 --- a/14_exceptions_part2_peripheral_IRQs/Makefile +++ b/14_exceptions_part2_peripheral_IRQs/Makefile @@ -179,6 +179,7 @@ objdump: $(KERNEL_ELF) @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ --section .rodata \ + --section .got \ $(KERNEL_ELF) | rustfilt nm: $(KERNEL_ELF) diff --git a/14_exceptions_part2_peripheral_IRQs/README.md b/14_exceptions_part2_peripheral_IRQs/README.md index 5e1f45e3..9ae718d7 100644 --- a/14_exceptions_part2_peripheral_IRQs/README.md +++ b/14_exceptions_part2_peripheral_IRQs/README.md @@ -2056,7 +2056,7 @@ diff -uNr 13_integrated_testing/src/bsp/raspberrypi/exception.rs 14_exceptions_p diff -uNr 13_integrated_testing/src/bsp/raspberrypi/memory.rs 14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory.rs --- 13_integrated_testing/src/bsp/raspberrypi/memory.rs +++ 14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory.rs -@@ -52,10 +52,12 @@ +@@ -51,10 +51,12 @@ pub mod mmio { use super::*; @@ -2073,7 +2073,7 @@ diff -uNr 13_integrated_testing/src/bsp/raspberrypi/memory.rs 14_exceptions_part } /// Physical devices. -@@ -66,6 +68,8 @@ +@@ -65,6 +67,8 @@ pub const START: usize = 0xFE00_0000; pub const GPIO_START: usize = START + GPIO_OFFSET; pub const PL011_UART_START: usize = START + UART_OFFSET; diff --git a/14_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/exception.S b/14_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/exception.S index 4d125334..fd7b1f93 100644 --- a/14_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/exception.S +++ b/14_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/exception.S @@ -50,7 +50,7 @@ //-------------------------------------------------------------------------------------------------- // The exception vector table. //-------------------------------------------------------------------------------------------------- -.section .exception_vectors, "ax", @progbits +.section .text // Align by 2^11 bytes, as demanded by ARMv8-A. Same as ALIGN(2048) in an ld script. .align 11 diff --git a/14_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/exception.rs b/14_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/exception.rs index 5cf9eb5c..de4f1f18 100644 --- a/14_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/exception.rs +++ b/14_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/exception.rs @@ -68,18 +68,18 @@ fn default_exception_handler(e: &ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn current_el0_synchronous(e: &mut ExceptionContext) { - default_exception_handler(e); +unsafe extern "C" fn current_el0_synchronous(_e: &mut ExceptionContext) { + panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } #[no_mangle] -unsafe extern "C" fn current_el0_irq(e: &mut ExceptionContext) { - default_exception_handler(e); +unsafe extern "C" fn current_el0_irq(_e: &mut ExceptionContext) { + panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } #[no_mangle] -unsafe extern "C" fn current_el0_serror(e: &mut ExceptionContext) { - default_exception_handler(e); +unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { + panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } //------------------------------------------------------------------------------ @@ -166,9 +166,7 @@ impl fmt::Display for EsrEL1 { writeln!(f, " - {}", ec_translation)?; // Raw print of instruction specific syndrome. - write!(f, " Instr Specific Syndrome (ISS): {:#x}", esr_el1.read(ESR_EL1::ISS))?; - - Ok(()) + write!(f, " Instr Specific Syndrome (ISS): {:#x}", esr_el1.read(ESR_EL1::ISS)) } } @@ -201,9 +199,7 @@ impl fmt::Display for SpsrEL1 { write!(f, " Illegal Execution State (IL): {}", to_flag_str(self.0.is_set(SPSR_EL1::IL)) - )?; - - Ok(()) + ) } } @@ -224,9 +220,7 @@ impl fmt::Display for ExceptionContext { for (i, reg) in self.gpr.iter().enumerate() { write!(f, " x{: <2}: {: >#018x}{}", i, reg, alternating(i))?; } - write!(f, " lr : {:#018x}", self.lr)?; - - Ok(()) + write!(f, " lr : {:#018x}", self.lr) } } diff --git a/14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/link.ld b/14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/link.ld index 4dfe60c7..6c63ba10 100644 --- a/14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/link.ld +++ b/14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/link.ld @@ -3,45 +3,50 @@ * Copyright (c) 2018-2021 Andre Richter */ +/* The address at which the the kernel binary will be loaded by the Raspberry's firmware */ +__rpi_load_addr = 0x80000; + +ENTRY(__rpi_load_addr) + +PHDRS +{ + segment_rx PT_LOAD FLAGS(5); /* 5 == RX */ + segment_rw PT_LOAD FLAGS(6); /* 6 == RW */ +} + SECTIONS { - /* Set current address to the value from which the RPi starts execution */ - . = 0x80000; + . = __rpi_load_addr; - __ro_start = .; + /*********************************************************************************************** + * Code + RO Data + Global Offset Table + ***********************************************************************************************/ + __rx_start = .; .text : { - *(.text._start) *(.text*) - } + KEEP(*(.text._start)) + *(.text*) + } :segment_rx - .exception_vectors : - { - *(.exception_vectors*) - } + .rodata : ALIGN(8) { *(.rodata*) } :segment_rx + .got : ALIGN(8) { *(.got) } :segment_rx - .rodata : - { - *(.rodata*) - } - . = ALIGN(65536); /* Fill up to 64 KiB */ - __ro_end = .; + . = ALIGN(64K); /* Align to page boundary */ + __rx_end_exclusive = .; - .data : - { - *(.data*) - } + /*********************************************************************************************** + * Data + BSS + ***********************************************************************************************/ + .data : { *(.data*) } :segment_rw /* Section is zeroed in u64 chunks, align start and end to 8 bytes */ - .bss ALIGN(8): + .bss : ALIGN(8) { __bss_start = .; *(.bss*); . = ALIGN(8); - /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ - . += 8; + . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ __bss_end_inclusive = . - 8; - } - - /DISCARD/ : { *(.comment*) } + } :NONE } diff --git a/14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory.rs b/14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory.rs index 4ac3b57b..d07f2dc3 100644 --- a/14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory.rs +++ b/14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory.rs @@ -14,17 +14,18 @@ use core::{cell::UnsafeCell, ops::RangeInclusive}; // Symbols from the linker script. extern "Rust" { + static __rx_start: UnsafeCell<()>; + static __rx_end_exclusive: UnsafeCell<()>; + static __bss_start: UnsafeCell; static __bss_end_inclusive: UnsafeCell; - static __ro_start: UnsafeCell<()>; - static __ro_end: UnsafeCell<()>; } //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- -/// The board's memory map. +/// The board's physical memory map. #[rustfmt::skip] pub(super) mod map { /// The inclusive end address of the memory map. @@ -42,8 +43,6 @@ pub(super) mod map { /// an RPi3 that comes with 1 GiB of RAM). This would result in a crash or other kind of error. pub const END_INCLUSIVE: usize = 0xFFFF_FFFF; - pub const BOOT_CORE_STACK_END: usize = 0x8_0000; - pub const GPIO_OFFSET: usize = 0x0020_0000; pub const UART_OFFSET: usize = 0x0020_1000; @@ -78,24 +77,24 @@ pub(super) mod map { // Private Code //-------------------------------------------------------------------------------------------------- -/// Start address of the Read-Only (RO) range. +/// Start address of the Read+Execute (RX) range. /// /// # Safety /// /// - Value is provided by the linker script and must be trusted as-is. #[inline(always)] -fn ro_start() -> usize { - unsafe { __ro_start.get() as usize } +fn rx_start() -> usize { + unsafe { __rx_start.get() as usize } } -/// Size of the Read-Only (RO) range of the kernel binary. +/// Exclusive end address of the Read+Execute (RX) range. /// /// # Safety /// /// - Value is provided by the linker script and must be trusted as-is. #[inline(always)] -fn ro_end() -> usize { - unsafe { __ro_end.get() as usize } +fn rx_end_exclusive() -> usize { + unsafe { __rx_end_exclusive.get() as usize } } //-------------------------------------------------------------------------------------------------- @@ -105,7 +104,7 @@ fn ro_end() -> usize { /// Exclusive end address of the boot core's stack. #[inline(always)] pub fn boot_core_stack_end() -> usize { - map::BOOT_CORE_STACK_END + rx_start() } /// Return the inclusive range spanning the .bss section. diff --git a/14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs b/14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs index 0ccfae00..f4769ad3 100644 --- a/14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs +++ b/14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs @@ -26,7 +26,7 @@ pub static LAYOUT: KernelVirtualLayout = KernelVirtualLayout::ne [ TranslationDescriptor { name: "Kernel code and RO data", - virtual_range: ro_range_inclusive, + virtual_range: rx_range_inclusive, physical_range_translation: Translation::Identity, attribute_fields: AttributeFields { mem_attributes: MemAttributes::CacheableDRAM, @@ -51,10 +51,10 @@ pub static LAYOUT: KernelVirtualLayout = KernelVirtualLayout::ne // Private Code //-------------------------------------------------------------------------------------------------- -fn ro_range_inclusive() -> RangeInclusive { +fn rx_range_inclusive() -> RangeInclusive { // Notice the subtraction to turn the exclusive end into an inclusive end. #[allow(clippy::range_minus_one)] - RangeInclusive::new(super::ro_start(), super::ro_end() - 1) + RangeInclusive::new(super::rx_start(), super::rx_end_exclusive() - 1) } fn mmio_range_inclusive() -> RangeInclusive { diff --git a/15_virtual_mem_part2_mmio_remap/Makefile b/15_virtual_mem_part2_mmio_remap/Makefile index 32d13924..4c2fb069 100644 --- a/15_virtual_mem_part2_mmio_remap/Makefile +++ b/15_virtual_mem_part2_mmio_remap/Makefile @@ -179,6 +179,7 @@ objdump: $(KERNEL_ELF) @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ --section .rodata \ + --section .got \ $(KERNEL_ELF) | rustfilt nm: $(KERNEL_ELF) diff --git a/15_virtual_mem_part2_mmio_remap/README.md b/15_virtual_mem_part2_mmio_remap/README.md index 9a6c6df6..18c72b74 100644 --- a/15_virtual_mem_part2_mmio_remap/README.md +++ b/15_virtual_mem_part2_mmio_remap/README.md @@ -276,6 +276,13 @@ unsafe fn init(&self) -> Result<(), &'static str> { There's a couple of changes not covered in this tutorial text, but the reader should ideally skim through them: +- [`src/bsp/raspberrypi/memory.rs`](src/bsp/raspberrypi/memory.rs) and + [`src/bsp/raspberrypi/link.ld`](src/bsp/raspberrypi/link.ld) changed the location of the boot + core's stack. It is now located after the data segment, and separated by an unmapped `guard page`. + There is also supporting code in + [`src/_arch/aarch64/exception.rs`](src/_arch/aarch64/exception.rs) that runs on data aborts and + checks if the fault address lies within the `stack guard page`. This can be an indication that a + kernel stack overflow happened. - [`src/memory/mmu/types.rs`](src/memory/mmu/types.rs) introduces a couple of supporting types, like `Page`. - [`src/memory/mmu/mapping_record.rs`](src/memory/mmu/mapping_record.rs) provides the generic kernel @@ -309,18 +316,18 @@ Minipush 1.0 [MP] ⏩ Pushing 67 KiB =========================================🦀 100% 0 KiB/s Time: 00:00:00 [ML] Loaded! Executing the payload now -[ 0.786819] Booting on: Raspberry Pi 3 -[ 0.787092] MMU online: -[ 0.787384] ------------------------------------------------------------------------------------------------------------------------------------------- -[ 0.789128] Virtual Physical Size Attr Entity -[ 0.790873] ------------------------------------------------------------------------------------------------------------------------------------------- -[ 0.792618] 0x0000_0000_0007_0000..0x0000_0000_0007_ffff --> 0x00_0007_0000..0x00_0007_ffff | 64 KiB | C RW XN | Kernel boot-core stack -[ 0.794221] 0x0000_0000_0008_0000..0x0000_0000_0008_ffff --> 0x00_0008_0000..0x00_0008_ffff | 64 KiB | C RO X | Kernel code and RO data -[ 0.795835] 0x0000_0000_0009_0000..0x0000_0000_001b_ffff --> 0x00_0009_0000..0x00_001b_ffff | 1 MiB | C RW XN | Kernel data and bss -[ 0.797406] 0x0000_0001_f000_0000..0x0000_0001_f000_ffff --> 0x00_3f20_0000..0x00_3f20_ffff | 64 KiB | Dev RW XN | BCM GPIO -[ 0.798857] | BCM PL011 UART -[ 0.800374] 0x0000_0001_f001_0000..0x0000_0001_f001_ffff --> 0x00_3f00_0000..0x00_3f00_ffff | 64 KiB | Dev RW XN | BCM Peripheral Interrupt Controller -[ 0.802117] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 0.789721] Booting on: Raspberry Pi 3 +[ 0.789994] MMU online: +[ 0.790286] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 0.792030] Virtual Physical Size Attr Entity +[ 0.793774] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 0.795520] 0x0000_0000_0008_0000..0x0000_0000_0008_ffff --> 0x00_0008_0000..0x00_0008_ffff | 64 KiB | C RO X | Kernel code and RO data +[ 0.797134] 0x0000_0000_0009_0000..0x0000_0000_001b_ffff --> 0x00_0009_0000..0x00_001b_ffff | 1 MiB | C RW XN | Kernel data and bss +[ 0.798704] 0x0000_0000_001d_0000..0x0000_0000_0024_ffff --> 0x00_001d_0000..0x00_0024_ffff | 512 KiB | C RW XN | Kernel boot-core stack +[ 0.800307] 0x0000_0001_f000_0000..0x0000_0001_f000_ffff --> 0x00_3f20_0000..0x00_3f20_ffff | 64 KiB | Dev RW XN | BCM GPIO +[ 0.801759] | BCM PL011 UART +[ 0.803276] 0x0000_0001_f001_0000..0x0000_0001_f001_ffff --> 0x00_3f00_0000..0x00_3f00_ffff | 64 KiB | Dev RW XN | BCM Peripheral Interrupt Controller +[ 0.805020] ------------------------------------------------------------------------------------------------------------------------------------------- ``` Raspberry Pi 4: @@ -344,19 +351,19 @@ Minipush 1.0 [MP] ⏩ Pushing 74 KiB =========================================🦀 100% 0 KiB/s Time: 00:00:00 [ML] Loaded! Executing the payload now -[ 0.853908] Booting on: Raspberry Pi 4 -[ 0.854007] MMU online: -[ 0.854299] ------------------------------------------------------------------------------------------------------------------------------------------- -[ 0.856043] Virtual Physical Size Attr Entity -[ 0.857788] ------------------------------------------------------------------------------------------------------------------------------------------- -[ 0.859533] 0x0000_0000_0007_0000..0x0000_0000_0007_ffff --> 0x00_0007_0000..0x00_0007_ffff | 64 KiB | C RW XN | Kernel boot-core stack -[ 0.861137] 0x0000_0000_0008_0000..0x0000_0000_0008_ffff --> 0x00_0008_0000..0x00_0008_ffff | 64 KiB | C RO X | Kernel code and RO data -[ 0.862750] 0x0000_0000_0009_0000..0x0000_0000_001b_ffff --> 0x00_0009_0000..0x00_001b_ffff | 1 MiB | C RW XN | Kernel data and bss -[ 0.864321] 0x0000_0001_f000_0000..0x0000_0001_f000_ffff --> 0x00_fe20_0000..0x00_fe20_ffff | 64 KiB | Dev RW XN | BCM GPIO -[ 0.865772] | BCM PL011 UART -[ 0.867289] 0x0000_0001_f001_0000..0x0000_0001_f001_ffff --> 0x00_ff84_0000..0x00_ff84_ffff | 64 KiB | Dev RW XN | GICD -[ 0.868697] | GICC -[ 0.870105] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 0.870371] Booting on: Raspberry Pi 4 +[ 0.870470] MMU online: +[ 0.870763] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 0.872507] Virtual Physical Size Attr Entity +[ 0.874251] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 0.875996] 0x0000_0000_0008_0000..0x0000_0000_0008_ffff --> 0x00_0008_0000..0x00_0008_ffff | 64 KiB | C RO X | Kernel code and RO data +[ 0.877611] 0x0000_0000_0009_0000..0x0000_0000_001b_ffff --> 0x00_0009_0000..0x00_001b_ffff | 1 MiB | C RW XN | Kernel data and bss +[ 0.879181] 0x0000_0000_001d_0000..0x0000_0000_0024_ffff --> 0x00_001d_0000..0x00_0024_ffff | 512 KiB | C RW XN | Kernel boot-core stack +[ 0.880784] 0x0000_0001_f000_0000..0x0000_0001_f000_ffff --> 0x00_fe20_0000..0x00_fe20_ffff | 64 KiB | Dev RW XN | BCM GPIO +[ 0.882235] | BCM PL011 UART +[ 0.883752] 0x0000_0001_f001_0000..0x0000_0001_f001_ffff --> 0x00_ff84_0000..0x00_ff84_ffff | 64 KiB | Dev RW XN | GICD +[ 0.885160] | GICC +[ 0.886569] ------------------------------------------------------------------------------------------------------------------------------------------- ``` ## Diff to previous @@ -375,6 +382,55 @@ diff -uNr 14_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/cpu/boot.rs 15_v // Use `eret` to "return" to EL1. This results in execution of runtime_init() in EL1. asm::eret() +diff -uNr 14_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/exception.rs 15_virtual_mem_part2_mmio_remap/src/_arch/aarch64/exception.rs +--- 14_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/exception.rs ++++ 15_virtual_mem_part2_mmio_remap/src/_arch/aarch64/exception.rs +@@ -11,7 +11,11 @@ + //! + //! crate::exception::arch_exception + +-use crate::{bsp, exception}; ++use crate::{ ++ bsp::{self}, ++ exception, ++ memory::Address, ++}; + use core::{cell::UnsafeCell, fmt}; + use cortex_a::{barrier, regs::*}; + use register::InMemoryRegister; +@@ -50,6 +54,20 @@ + // Private Code + //-------------------------------------------------------------------------------------------------- + ++/// Check if additional context can be derived from a data abort. ++fn inspect_data_abort(f: &mut fmt::Formatter) -> fmt::Result { ++ let fault_addr = Address::new(FAR_EL1.get() as usize); ++ ++ if bsp::memory::mmu::virt_boot_core_stack_guard_page_desc().contains(fault_addr) { ++ writeln!( ++ f, ++ "\n\n >> Attempted to access the guard page of the kernel's boot core stack <<" ++ )?; ++ } ++ ++ Ok(()) ++} ++ + /// Prints verbose information about the exception and then panics. + fn default_exception_handler(e: &ExceptionContext) { + panic!( +@@ -166,7 +184,9 @@ + writeln!(f, " - {}", ec_translation)?; + + // Raw print of instruction specific syndrome. +- write!(f, " Instr Specific Syndrome (ISS): {:#x}", esr_el1.read(ESR_EL1::ISS)) ++ write!(f, " Instr Specific Syndrome (ISS): {:#x}", esr_el1.read(ESR_EL1::ISS))?; ++ ++ inspect_data_abort(f) + } + } + + diff -uNr 14_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/memory/mmu/translation_table.rs 15_virtual_mem_part2_mmio_remap/src/_arch/aarch64/memory/mmu/translation_table.rs --- 14_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/memory/mmu/translation_table.rs +++ 15_virtual_mem_part2_mmio_remap/src/_arch/aarch64/memory/mmu/translation_table.rs @@ -1413,23 +1469,41 @@ diff -uNr 14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/driver.rs 15_v diff -uNr 14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/link.ld 15_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/link.ld --- 14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/link.ld +++ 15_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/link.ld -@@ -42,6 +42,11 @@ - . += 8; +@@ -37,6 +37,7 @@ + /*********************************************************************************************** + * Data + BSS + ***********************************************************************************************/ ++ __rw_start = .; + .data : { *(.data*) } :segment_rw + + /* Section is zeroed in u64 chunks, align start and end to 8 bytes */ +@@ -49,4 +50,21 @@ + . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ __bss_end_inclusive = . - 8; - } -+ . = ALIGN(65536); -+ __data_end = .; -+ -+ __ro_size = __ro_end - __ro_start; -+ __data_size = __data_end - __ro_end; - - /DISCARD/ : { *(.comment*) } + } :NONE ++ ++ . = ALIGN(64K); /* Align to page boundary */ ++ __rw_end_exclusive = .; ++ ++ /*********************************************************************************************** ++ * Guard Page between boot core stack and data ++ ***********************************************************************************************/ ++ __boot_core_stack_guard_page_start = .; ++ . += 64K; ++ __boot_core_stack_guard_page_end_exclusive = .; ++ ++ /*********************************************************************************************** ++ * Boot Core Stack ++ ***********************************************************************************************/ ++ __boot_core_stack_start = .; ++ . += 512K; ++ __boot_core_stack_end_exclusive = .; } diff -uNr 14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs 15_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory/mmu.rs --- 14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs +++ 15_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory/mmu.rs -@@ -4,70 +4,157 @@ +@@ -4,70 +4,164 @@ //! BSP Memory Management Unit. @@ -1465,16 +1539,16 @@ diff -uNr 14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs +/// The translation granule chosen by this BSP. This will be used everywhere else in the kernel to +/// derive respective data structures and their sizes. For example, the `crate::memory::mmu::Page`. +pub type KernelGranule = TranslationGranule<{ 64 * 1024 }>; - --const NUM_MEM_RANGES: usize = 2; ++ +/// The kernel's virtual address space defined by this BSP. +pub type KernelVirtAddrSpace = AddressSpace<{ 8 * 1024 * 1024 * 1024 }>; --/// The virtual memory layout. +-const NUM_MEM_RANGES: usize = 2; +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- -+ + +-/// The virtual memory layout. +/// The kernel translation tables. /// -/// The layout must contain only special ranges, aka anything that is _not_ normal cacheable DRAM. @@ -1484,7 +1558,7 @@ diff -uNr 14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs - [ - TranslationDescriptor { - name: "Kernel code and RO data", -- virtual_range: ro_range_inclusive, +- virtual_range: rx_range_inclusive, - physical_range_translation: Translation::Identity, - attribute_fields: AttributeFields { - mem_attributes: MemAttributes::CacheableDRAM, @@ -1515,10 +1589,10 @@ diff -uNr 14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs // Private Code //-------------------------------------------------------------------------------------------------- --fn ro_range_inclusive() -> RangeInclusive { +-fn rx_range_inclusive() -> RangeInclusive { - // Notice the subtraction to turn the exclusive end into an inclusive end. - #[allow(clippy::range_minus_one)] -- RangeInclusive::new(super::ro_start(), super::ro_end() - 1) +- RangeInclusive::new(super::rx_start(), super::rx_end_exclusive() - 1) +/// Helper function for calculating the number of pages the given parameter spans. +const fn size_to_num_pages(size: usize) -> usize { + assert!(size > 0); @@ -1527,44 +1601,44 @@ diff -uNr 14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs + size >> KernelGranule::SHIFT +} + -+/// The boot core's stack. -+fn virt_stack_page_desc() -> PageSliceDescriptor { -+ let num_pages = size_to_num_pages(super::boot_core_stack_size()); ++/// The Read+Execute (RX) pages of the kernel binary. ++fn virt_rx_page_desc() -> PageSliceDescriptor { ++ let num_pages = size_to_num_pages(super::rx_size()); + -+ PageSliceDescriptor::from_addr(super::virt_boot_core_stack_start(), num_pages) ++ PageSliceDescriptor::from_addr(super::virt_rx_start(), num_pages) +} + -+/// The Read-Only (RO) pages of the kernel binary. -+fn virt_ro_page_desc() -> PageSliceDescriptor { -+ let num_pages = size_to_num_pages(super::ro_size()); ++/// The Read+Write (RW) pages of the kernel binary. ++fn virt_rw_page_desc() -> PageSliceDescriptor { ++ let num_pages = size_to_num_pages(super::rw_size()); + -+ PageSliceDescriptor::from_addr(super::virt_ro_start(), num_pages) ++ PageSliceDescriptor::from_addr(super::virt_rw_start(), num_pages) +} + -+/// The data pages of the kernel binary. -+fn virt_data_page_desc() -> PageSliceDescriptor { -+ let num_pages = size_to_num_pages(super::data_size()); ++/// The boot core's stack. ++fn virt_boot_core_stack_page_desc() -> PageSliceDescriptor { ++ let num_pages = size_to_num_pages(super::boot_core_stack_size()); + -+ PageSliceDescriptor::from_addr(super::virt_data_start(), num_pages) ++ PageSliceDescriptor::from_addr(super::virt_boot_core_stack_start(), num_pages) +} + +// The binary is still identity mapped, so we don't need to convert in the following. + -+/// The boot core's stack. -+fn phys_stack_page_desc() -> PageSliceDescriptor { -+ virt_stack_page_desc().into() -+} -+ -+/// The Read-Only (RO) pages of the kernel binary. -+fn phys_ro_page_desc() -> PageSliceDescriptor { -+ virt_ro_page_desc().into() ++/// The Read+Execute (RX) pages of the kernel binary. ++fn phys_rx_page_desc() -> PageSliceDescriptor { ++ virt_rx_page_desc().into() } -fn mmio_range_inclusive() -> RangeInclusive { - RangeInclusive::new(memory_map::mmio::START, memory_map::mmio::END_INCLUSIVE) -+/// The data pages of the kernel binary. -+fn phys_data_page_desc() -> PageSliceDescriptor { -+ virt_data_page_desc().into() ++/// The Read+Write (RW) pages of the kernel binary. ++fn phys_rw_page_desc() -> PageSliceDescriptor { ++ virt_rw_page_desc().into() ++} ++ ++/// The boot core's stack. ++fn phys_boot_core_stack_page_desc() -> PageSliceDescriptor { ++ virt_boot_core_stack_page_desc().into() } //-------------------------------------------------------------------------------------------------- @@ -1579,6 +1653,13 @@ diff -uNr 14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs + &KERNEL_TABLES +} + ++/// The boot core's stack guard page. ++pub fn virt_boot_core_stack_guard_page_desc() -> PageSliceDescriptor { ++ let num_pages = size_to_num_pages(super::boot_core_stack_guard_page_size()); ++ ++ PageSliceDescriptor::from_addr(super::virt_boot_core_stack_guard_page_start(), num_pages) ++} ++ +/// Pointer to the last page of the physical address space. +pub fn phys_addr_space_end_page() -> *const Page { + common::align_down( @@ -1594,31 +1675,31 @@ diff -uNr 14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs +/// - Any miscalculation or attribute error will likely be fatal. Needs careful manual checking. +pub unsafe fn kernel_map_binary() -> Result<(), &'static str> { + generic_mmu::kernel_map_pages_at( -+ "Kernel boot-core stack", -+ &virt_stack_page_desc(), -+ &phys_stack_page_desc(), ++ "Kernel code and RO data", ++ &virt_rx_page_desc(), ++ &phys_rx_page_desc(), + &AttributeFields { + mem_attributes: MemAttributes::CacheableDRAM, -+ acc_perms: AccessPermissions::ReadWrite, -+ execute_never: true, ++ acc_perms: AccessPermissions::ReadOnly, ++ execute_never: false, + }, + )?; + + generic_mmu::kernel_map_pages_at( -+ "Kernel code and RO data", -+ &virt_ro_page_desc(), -+ &phys_ro_page_desc(), ++ "Kernel data and bss", ++ &virt_rw_page_desc(), ++ &phys_rw_page_desc(), + &AttributeFields { + mem_attributes: MemAttributes::CacheableDRAM, -+ acc_perms: AccessPermissions::ReadOnly, -+ execute_never: false, ++ acc_perms: AccessPermissions::ReadWrite, ++ execute_never: true, + }, + )?; + + generic_mmu::kernel_map_pages_at( -+ "Kernel data and bss", -+ &virt_data_page_desc(), -+ &phys_data_page_desc(), ++ "Kernel boot-core stack", ++ &virt_boot_core_stack_page_desc(), ++ &phys_boot_core_stack_page_desc(), + &AttributeFields { + mem_attributes: MemAttributes::CacheableDRAM, + acc_perms: AccessPermissions::ReadWrite, @@ -1630,7 +1711,7 @@ diff -uNr 14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs } //-------------------------------------------------------------------------------------------------- -@@ -82,14 +169,12 @@ +@@ -82,14 +176,18 @@ /// Check alignment of the kernel's virtual memory layout sections. #[kernel_test] fn virt_mem_layout_sections_are_64KiB_aligned() { @@ -1639,7 +1720,13 @@ diff -uNr 14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs - for i in LAYOUT.inner().iter() { - let start: usize = *(i.virtual_range)().start(); - let end: usize = *(i.virtual_range)().end() + 1; -+ for i in [virt_stack_page_desc, virt_ro_page_desc, virt_data_page_desc].iter() { ++ for i in [ ++ virt_rx_page_desc, ++ virt_rw_page_desc, ++ virt_boot_core_stack_page_desc, ++ ] ++ .iter() ++ { + let start: usize = i().start_addr().into_usize(); + let end: usize = i().end_addr().into_usize(); @@ -1650,7 +1737,7 @@ diff -uNr 14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs assert!(end >= start); } } -@@ -97,18 +182,28 @@ +@@ -97,18 +195,28 @@ /// Ensure the kernel's virtual memory layout is free of overlaps. #[kernel_test] fn virt_mem_layout_has_no_overlaps() { @@ -1666,9 +1753,9 @@ diff -uNr 14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs - assert!(!second_range().contains(first_range().start())); - assert!(!second_range().contains(first_range().end())); + let layout = [ -+ virt_stack_page_desc(), -+ virt_ro_page_desc(), -+ virt_data_page_desc(), ++ virt_rx_page_desc(), ++ virt_rw_page_desc(), ++ virt_boot_core_stack_page_desc(), + ]; + + for (i, first_range) in layout.iter().enumerate() { @@ -1694,7 +1781,7 @@ diff -uNr 14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs diff -uNr 14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory.rs 15_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory.rs --- 14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory.rs +++ 15_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory.rs -@@ -3,9 +3,41 @@ +@@ -3,9 +3,40 @@ // Copyright (c) 2018-2021 Andre Richter //! BSP Memory Management. @@ -1703,31 +1790,30 @@ diff -uNr 14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory.rs 15_v +//! copies the binary to 0x8_0000: +//! +//! +---------------------------------------------+ -+//! | | 0x0 -+//! | Unmapped | -+//! | | 0x6_FFFF -+//! +---------------------------------------------+ -+//! | BOOT_CORE_STACK_START | 0x7_0000 -+//! | | ^ -+//! | ... | | Stack growth direction -+//! | | | -+//! | BOOT_CORE_STACK_END_INCLUSIVE | 0x7_FFFF -+//! +---------------------------------------------+ -+//! | RO_START == BOOT_CORE_STACK_END | 0x8_0000 +//! | | ++//! | Unmapped | +//! | | ++//! +---------------------------------------------+ ++//! | | rx_start @ 0x8_0000 +//! | .text | -+//! | .exception_vectors | +//! | .rodata | -+//! | | -+//! | RO_END_INCLUSIVE | 0x8_0000 + __ro_size - 1 ++//! | .got | ++//! | | rx_end_inclusive +//! +---------------------------------------------+ -+//! | RO_END == DATA_START | 0x8_0000 + __ro_size -+//! | | ++//! | | rw_start == ro_end +//! | .data | +//! | .bss | ++//! | | rw_end_inclusive ++//! +---------------------------------------------+ ++//! | | rw_end ++//! | Unmapped Boot-core Stack Guard Page | +//! | | -+//! | DATA_END_INCLUSIVE | 0x8_0000 + __ro_size + __data_size - 1 ++//! +---------------------------------------------+ ++//! | | boot_core_stack_start ^ ++//! | | | stack ++//! | Boot-core Stack | | growth ++//! | | | direction ++//! | | boot_core_stack_end_inclusive | +//! +---------------------------------------------+ pub mod mmu; @@ -1736,21 +1822,25 @@ diff -uNr 14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory.rs 15_v use core::{cell::UnsafeCell, ops::RangeInclusive}; //-------------------------------------------------------------------------------------------------- -@@ -17,47 +49,39 @@ +@@ -17,8 +48,16 @@ + static __rx_start: UnsafeCell<()>; + static __rx_end_exclusive: UnsafeCell<()>; + ++ static __rw_start: UnsafeCell<()>; static __bss_start: UnsafeCell; static __bss_end_inclusive: UnsafeCell; - static __ro_start: UnsafeCell<()>; -- static __ro_end: UnsafeCell<()>; -+ static __ro_size: UnsafeCell<()>; -+ static __data_size: UnsafeCell<()>; ++ static __rw_end_exclusive: UnsafeCell<()>; ++ ++ static __boot_core_stack_start: UnsafeCell<()>; ++ static __boot_core_stack_end_exclusive: UnsafeCell<()>; ++ ++ static __boot_core_stack_guard_page_start: UnsafeCell<()>; ++ static __boot_core_stack_guard_page_end_exclusive: UnsafeCell<()>; } //-------------------------------------------------------------------------------------------------- - // Public Definitions - //-------------------------------------------------------------------------------------------------- - --/// The board's memory map. -+/// The board's physical memory map. +@@ -28,35 +67,26 @@ + /// The board's physical memory map. #[rustfmt::skip] pub(super) mod map { - /// The inclusive end address of the memory map. @@ -1767,13 +1857,10 @@ diff -uNr 14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory.rs 15_v - /// physical address that is not backed by any DRAM (e.g. accessing an address close to 4 GiB on - /// an RPi3 that comes with 1 GiB of RAM). This would result in a crash or other kind of error. - pub const END_INCLUSIVE: usize = 0xFFFF_FFFF; -+ use super::*; - -- pub const BOOT_CORE_STACK_END: usize = 0x8_0000; - - pub const GPIO_OFFSET: usize = 0x0020_0000; - pub const UART_OFFSET: usize = 0x0020_1000; -+ pub const BOOT_CORE_STACK_SIZE: usize = 0x1_0000; ++ use super::*; /// Physical devices. #[cfg(feature = "bsp_rpi3")] @@ -1802,7 +1889,7 @@ diff -uNr 14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory.rs 15_v } /// Physical devices. -@@ -65,13 +89,22 @@ +@@ -64,13 +94,22 @@ pub mod mmio { use super::*; @@ -1831,53 +1918,72 @@ diff -uNr 14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory.rs 15_v } //-------------------------------------------------------------------------------------------------- -@@ -84,8 +117,8 @@ +@@ -83,18 +122,69 @@ /// /// - Value is provided by the linker script and must be trusted as-is. #[inline(always)] --fn ro_start() -> usize { -- unsafe { __ro_start.get() as usize } -+fn virt_ro_start() -> Address { -+ Address::new(unsafe { __ro_start.get() as usize }) +-fn rx_start() -> usize { +- unsafe { __rx_start.get() as usize } ++fn virt_rx_start() -> Address { ++ Address::new(unsafe { __rx_start.get() as usize }) } - /// Size of the Read-Only (RO) range of the kernel binary. -@@ -94,8 +127,42 @@ +-/// Exclusive end address of the Read+Execute (RX) range. ++/// Size of the Read+Execute (RX) range. + /// + /// # Safety /// /// - Value is provided by the linker script and must be trusted as-is. #[inline(always)] --fn ro_end() -> usize { -- unsafe { __ro_end.get() as usize } -+fn ro_size() -> usize { -+ unsafe { __ro_size.get() as usize } +-fn rx_end_exclusive() -> usize { +- unsafe { __rx_end_exclusive.get() as usize } ++fn rx_size() -> usize { ++ unsafe { (__rx_end_exclusive.get() as usize) - (__rx_start.get() as usize) } +} + -+/// Start address of the data range. ++/// Start address of the Read+Write (RW) range. +#[inline(always)] -+fn virt_data_start() -> Address { -+ virt_ro_start() + ro_size() ++fn virt_rw_start() -> Address { ++ Address::new(unsafe { __rw_start.get() as usize }) +} + -+/// Size of the data range. ++/// Size of the Read+Write (RW) range. +/// +/// # Safety +/// +/// - Value is provided by the linker script and must be trusted as-is. +#[inline(always)] -+fn data_size() -> usize { -+ unsafe { __data_size.get() as usize } ++fn rw_size() -> usize { ++ unsafe { (__rw_end_exclusive.get() as usize) - (__rw_start.get() as usize) } +} + +/// Start address of the boot core's stack. +#[inline(always)] +fn virt_boot_core_stack_start() -> Address { -+ virt_ro_start() - map::BOOT_CORE_STACK_SIZE ++ Address::new(unsafe { __boot_core_stack_start.get() as usize }) +} + +/// Size of the boot core's stack. +#[inline(always)] +fn boot_core_stack_size() -> usize { -+ map::BOOT_CORE_STACK_SIZE ++ unsafe { ++ (__boot_core_stack_end_exclusive.get() as usize) - (__boot_core_stack_start.get() as usize) ++ } ++} ++ ++/// Start address of the boot core's stack guard page. ++#[inline(always)] ++fn virt_boot_core_stack_guard_page_start() -> Address { ++ Address::new(unsafe { __boot_core_stack_guard_page_start.get() as usize }) ++} ++ ++/// Size of the boot core's stack guard page. ++#[inline(always)] ++fn boot_core_stack_guard_page_size() -> usize { ++ unsafe { ++ (__boot_core_stack_guard_page_end_exclusive.get() as usize) ++ - (__boot_core_stack_guard_page_start.get() as usize) ++ } +} + +/// Exclusive end address of the physical address space. @@ -1887,12 +1993,12 @@ diff -uNr 14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory.rs 15_v } //-------------------------------------------------------------------------------------------------- -@@ -104,8 +171,10 @@ +@@ -103,8 +193,10 @@ /// Exclusive end address of the boot core's stack. #[inline(always)] -pub fn boot_core_stack_end() -> usize { -- map::BOOT_CORE_STACK_END +- rx_start() +pub fn phys_boot_core_stack_end() -> Address { + // The binary is still identity mapped, so we don't need to convert here. + let end = virt_boot_core_stack_start().into_usize() + boot_core_stack_size(); diff --git a/15_virtual_mem_part2_mmio_remap/src/_arch/aarch64/exception.S b/15_virtual_mem_part2_mmio_remap/src/_arch/aarch64/exception.S index 4d125334..fd7b1f93 100644 --- a/15_virtual_mem_part2_mmio_remap/src/_arch/aarch64/exception.S +++ b/15_virtual_mem_part2_mmio_remap/src/_arch/aarch64/exception.S @@ -50,7 +50,7 @@ //-------------------------------------------------------------------------------------------------- // The exception vector table. //-------------------------------------------------------------------------------------------------- -.section .exception_vectors, "ax", @progbits +.section .text // Align by 2^11 bytes, as demanded by ARMv8-A. Same as ALIGN(2048) in an ld script. .align 11 diff --git a/15_virtual_mem_part2_mmio_remap/src/_arch/aarch64/exception.rs b/15_virtual_mem_part2_mmio_remap/src/_arch/aarch64/exception.rs index 5cf9eb5c..b9338734 100644 --- a/15_virtual_mem_part2_mmio_remap/src/_arch/aarch64/exception.rs +++ b/15_virtual_mem_part2_mmio_remap/src/_arch/aarch64/exception.rs @@ -11,7 +11,11 @@ //! //! crate::exception::arch_exception -use crate::{bsp, exception}; +use crate::{ + bsp::{self}, + exception, + memory::Address, +}; use core::{cell::UnsafeCell, fmt}; use cortex_a::{barrier, regs::*}; use register::InMemoryRegister; @@ -50,6 +54,20 @@ struct EsrEL1; // Private Code //-------------------------------------------------------------------------------------------------- +/// Check if additional context can be derived from a data abort. +fn inspect_data_abort(f: &mut fmt::Formatter) -> fmt::Result { + let fault_addr = Address::new(FAR_EL1.get() as usize); + + if bsp::memory::mmu::virt_boot_core_stack_guard_page_desc().contains(fault_addr) { + writeln!( + f, + "\n\n >> Attempted to access the guard page of the kernel's boot core stack <<" + )?; + } + + Ok(()) +} + /// Prints verbose information about the exception and then panics. fn default_exception_handler(e: &ExceptionContext) { panic!( @@ -68,18 +86,18 @@ fn default_exception_handler(e: &ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn current_el0_synchronous(e: &mut ExceptionContext) { - default_exception_handler(e); +unsafe extern "C" fn current_el0_synchronous(_e: &mut ExceptionContext) { + panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } #[no_mangle] -unsafe extern "C" fn current_el0_irq(e: &mut ExceptionContext) { - default_exception_handler(e); +unsafe extern "C" fn current_el0_irq(_e: &mut ExceptionContext) { + panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } #[no_mangle] -unsafe extern "C" fn current_el0_serror(e: &mut ExceptionContext) { - default_exception_handler(e); +unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { + panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } //------------------------------------------------------------------------------ @@ -168,7 +186,7 @@ impl fmt::Display for EsrEL1 { // Raw print of instruction specific syndrome. write!(f, " Instr Specific Syndrome (ISS): {:#x}", esr_el1.read(ESR_EL1::ISS))?; - Ok(()) + inspect_data_abort(f) } } @@ -201,9 +219,7 @@ impl fmt::Display for SpsrEL1 { write!(f, " Illegal Execution State (IL): {}", to_flag_str(self.0.is_set(SPSR_EL1::IL)) - )?; - - Ok(()) + ) } } @@ -224,9 +240,7 @@ impl fmt::Display for ExceptionContext { for (i, reg) in self.gpr.iter().enumerate() { write!(f, " x{: <2}: {: >#018x}{}", i, reg, alternating(i))?; } - write!(f, " lr : {:#018x}", self.lr)?; - - Ok(()) + write!(f, " lr : {:#018x}", self.lr) } } diff --git a/15_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/link.ld b/15_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/link.ld index e5975256..f2b5d05d 100644 --- a/15_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/link.ld +++ b/15_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/link.ld @@ -3,50 +3,68 @@ * Copyright (c) 2018-2021 Andre Richter */ +/* The address at which the the kernel binary will be loaded by the Raspberry's firmware */ +__rpi_load_addr = 0x80000; + +ENTRY(__rpi_load_addr) + +PHDRS +{ + segment_rx PT_LOAD FLAGS(5); /* 5 == RX */ + segment_rw PT_LOAD FLAGS(6); /* 6 == RW */ +} + SECTIONS { - /* Set current address to the value from which the RPi starts execution */ - . = 0x80000; + . = __rpi_load_addr; - __ro_start = .; + /*********************************************************************************************** + * Code + RO Data + Global Offset Table + ***********************************************************************************************/ + __rx_start = .; .text : { - *(.text._start) *(.text*) - } + KEEP(*(.text._start)) + *(.text*) + } :segment_rx - .exception_vectors : - { - *(.exception_vectors*) - } + .rodata : ALIGN(8) { *(.rodata*) } :segment_rx + .got : ALIGN(8) { *(.got) } :segment_rx - .rodata : - { - *(.rodata*) - } - . = ALIGN(65536); /* Fill up to 64 KiB */ - __ro_end = .; + . = ALIGN(64K); /* Align to page boundary */ + __rx_end_exclusive = .; - .data : - { - *(.data*) - } + /*********************************************************************************************** + * Data + BSS + ***********************************************************************************************/ + __rw_start = .; + .data : { *(.data*) } :segment_rw /* Section is zeroed in u64 chunks, align start and end to 8 bytes */ - .bss ALIGN(8): + .bss : ALIGN(8) { __bss_start = .; *(.bss*); . = ALIGN(8); - /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ - . += 8; + . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ __bss_end_inclusive = . - 8; - } - . = ALIGN(65536); - __data_end = .; + } :NONE + + . = ALIGN(64K); /* Align to page boundary */ + __rw_end_exclusive = .; - __ro_size = __ro_end - __ro_start; - __data_size = __data_end - __ro_end; + /*********************************************************************************************** + * Guard Page between boot core stack and data + ***********************************************************************************************/ + __boot_core_stack_guard_page_start = .; + . += 64K; + __boot_core_stack_guard_page_end_exclusive = .; - /DISCARD/ : { *(.comment*) } + /*********************************************************************************************** + * Boot Core Stack + ***********************************************************************************************/ + __boot_core_stack_start = .; + . += 512K; + __boot_core_stack_end_exclusive = .; } diff --git a/15_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory.rs b/15_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory.rs index 7b48d7b5..19545c00 100644 --- a/15_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory.rs +++ b/15_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory.rs @@ -8,31 +8,30 @@ //! copies the binary to 0x8_0000: //! //! +---------------------------------------------+ -//! | | 0x0 -//! | Unmapped | -//! | | 0x6_FFFF -//! +---------------------------------------------+ -//! | BOOT_CORE_STACK_START | 0x7_0000 -//! | | ^ -//! | ... | | Stack growth direction -//! | | | -//! | BOOT_CORE_STACK_END_INCLUSIVE | 0x7_FFFF -//! +---------------------------------------------+ -//! | RO_START == BOOT_CORE_STACK_END | 0x8_0000 //! | | +//! | Unmapped | //! | | +//! +---------------------------------------------+ +//! | | rx_start @ 0x8_0000 //! | .text | -//! | .exception_vectors | //! | .rodata | -//! | | -//! | RO_END_INCLUSIVE | 0x8_0000 + __ro_size - 1 +//! | .got | +//! | | rx_end_inclusive //! +---------------------------------------------+ -//! | RO_END == DATA_START | 0x8_0000 + __ro_size -//! | | +//! | | rw_start == rx_end //! | .data | //! | .bss | +//! | | rw_end_inclusive +//! +---------------------------------------------+ +//! | | rw_end +//! | Unmapped Boot-core Stack Guard Page | //! | | -//! | DATA_END_INCLUSIVE | 0x8_0000 + __ro_size + __data_size - 1 +//! +---------------------------------------------+ +//! | | boot_core_stack_start ^ +//! | | | stack +//! | Boot-core Stack | | growth +//! | | | direction +//! | | boot_core_stack_end_inclusive | //! +---------------------------------------------+ pub mod mmu; @@ -46,11 +45,19 @@ use core::{cell::UnsafeCell, ops::RangeInclusive}; // Symbols from the linker script. extern "Rust" { + static __rx_start: UnsafeCell<()>; + static __rx_end_exclusive: UnsafeCell<()>; + + static __rw_start: UnsafeCell<()>; static __bss_start: UnsafeCell; static __bss_end_inclusive: UnsafeCell; - static __ro_start: UnsafeCell<()>; - static __ro_size: UnsafeCell<()>; - static __data_size: UnsafeCell<()>; + static __rw_end_exclusive: UnsafeCell<()>; + + static __boot_core_stack_start: UnsafeCell<()>; + static __boot_core_stack_end_exclusive: UnsafeCell<()>; + + static __boot_core_stack_guard_page_start: UnsafeCell<()>; + static __boot_core_stack_guard_page_end_exclusive: UnsafeCell<()>; } //-------------------------------------------------------------------------------------------------- @@ -62,8 +69,6 @@ extern "Rust" { pub(super) mod map { use super::*; - pub const BOOT_CORE_STACK_SIZE: usize = 0x1_0000; - /// Physical devices. #[cfg(feature = "bsp_rpi3")] pub mod mmio { @@ -111,52 +116,69 @@ pub(super) mod map { // Private Code //-------------------------------------------------------------------------------------------------- -/// Start address of the Read-Only (RO) range. +/// Start address of the Read+Execute (RX) range. /// /// # Safety /// /// - Value is provided by the linker script and must be trusted as-is. #[inline(always)] -fn virt_ro_start() -> Address { - Address::new(unsafe { __ro_start.get() as usize }) +fn virt_rx_start() -> Address { + Address::new(unsafe { __rx_start.get() as usize }) } -/// Size of the Read-Only (RO) range of the kernel binary. +/// Size of the Read+Execute (RX) range. /// /// # Safety /// /// - Value is provided by the linker script and must be trusted as-is. #[inline(always)] -fn ro_size() -> usize { - unsafe { __ro_size.get() as usize } +fn rx_size() -> usize { + unsafe { (__rx_end_exclusive.get() as usize) - (__rx_start.get() as usize) } } -/// Start address of the data range. +/// Start address of the Read+Write (RW) range. #[inline(always)] -fn virt_data_start() -> Address { - virt_ro_start() + ro_size() +fn virt_rw_start() -> Address { + Address::new(unsafe { __rw_start.get() as usize }) } -/// Size of the data range. +/// Size of the Read+Write (RW) range. /// /// # Safety /// /// - Value is provided by the linker script and must be trusted as-is. #[inline(always)] -fn data_size() -> usize { - unsafe { __data_size.get() as usize } +fn rw_size() -> usize { + unsafe { (__rw_end_exclusive.get() as usize) - (__rw_start.get() as usize) } } /// Start address of the boot core's stack. #[inline(always)] fn virt_boot_core_stack_start() -> Address { - virt_ro_start() - map::BOOT_CORE_STACK_SIZE + Address::new(unsafe { __boot_core_stack_start.get() as usize }) } /// Size of the boot core's stack. #[inline(always)] fn boot_core_stack_size() -> usize { - map::BOOT_CORE_STACK_SIZE + unsafe { + (__boot_core_stack_end_exclusive.get() as usize) - (__boot_core_stack_start.get() as usize) + } +} + +/// Start address of the boot core's stack guard page. +#[inline(always)] +fn virt_boot_core_stack_guard_page_start() -> Address { + Address::new(unsafe { __boot_core_stack_guard_page_start.get() as usize }) +} + +/// Size of the boot core's stack guard page. +#[inline(always)] +fn boot_core_stack_guard_page_size() -> usize { + unsafe { + (__boot_core_stack_guard_page_end_exclusive.get() as usize) + - (__boot_core_stack_guard_page_start.get() as usize) + } } /// Exclusive end address of the physical address space. diff --git a/15_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory/mmu.rs b/15_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory/mmu.rs index 842384de..88fc80bd 100644 --- a/15_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory/mmu.rs +++ b/15_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory/mmu.rs @@ -60,42 +60,42 @@ const fn size_to_num_pages(size: usize) -> usize { size >> KernelGranule::SHIFT } -/// The boot core's stack. -fn virt_stack_page_desc() -> PageSliceDescriptor { - let num_pages = size_to_num_pages(super::boot_core_stack_size()); +/// The Read+Execute (RX) pages of the kernel binary. +fn virt_rx_page_desc() -> PageSliceDescriptor { + let num_pages = size_to_num_pages(super::rx_size()); - PageSliceDescriptor::from_addr(super::virt_boot_core_stack_start(), num_pages) + PageSliceDescriptor::from_addr(super::virt_rx_start(), num_pages) } -/// The Read-Only (RO) pages of the kernel binary. -fn virt_ro_page_desc() -> PageSliceDescriptor { - let num_pages = size_to_num_pages(super::ro_size()); +/// The Read+Write (RW) pages of the kernel binary. +fn virt_rw_page_desc() -> PageSliceDescriptor { + let num_pages = size_to_num_pages(super::rw_size()); - PageSliceDescriptor::from_addr(super::virt_ro_start(), num_pages) + PageSliceDescriptor::from_addr(super::virt_rw_start(), num_pages) } -/// The data pages of the kernel binary. -fn virt_data_page_desc() -> PageSliceDescriptor { - let num_pages = size_to_num_pages(super::data_size()); +/// The boot core's stack. +fn virt_boot_core_stack_page_desc() -> PageSliceDescriptor { + let num_pages = size_to_num_pages(super::boot_core_stack_size()); - PageSliceDescriptor::from_addr(super::virt_data_start(), num_pages) + PageSliceDescriptor::from_addr(super::virt_boot_core_stack_start(), num_pages) } // The binary is still identity mapped, so we don't need to convert in the following. -/// The boot core's stack. -fn phys_stack_page_desc() -> PageSliceDescriptor { - virt_stack_page_desc().into() +/// The Read+Execute (RX) pages of the kernel binary. +fn phys_rx_page_desc() -> PageSliceDescriptor { + virt_rx_page_desc().into() } -/// The Read-Only (RO) pages of the kernel binary. -fn phys_ro_page_desc() -> PageSliceDescriptor { - virt_ro_page_desc().into() +/// The Read+Write (RW) pages of the kernel binary. +fn phys_rw_page_desc() -> PageSliceDescriptor { + virt_rw_page_desc().into() } -/// The data pages of the kernel binary. -fn phys_data_page_desc() -> PageSliceDescriptor { - virt_data_page_desc().into() +/// The boot core's stack. +fn phys_boot_core_stack_page_desc() -> PageSliceDescriptor { + virt_boot_core_stack_page_desc().into() } //-------------------------------------------------------------------------------------------------- @@ -107,6 +107,13 @@ pub fn kernel_translation_tables() -> &'static InitStateLock PageSliceDescriptor { + let num_pages = size_to_num_pages(super::boot_core_stack_guard_page_size()); + + PageSliceDescriptor::from_addr(super::virt_boot_core_stack_guard_page_start(), num_pages) +} + /// Pointer to the last page of the physical address space. pub fn phys_addr_space_end_page() -> *const Page { common::align_down( @@ -122,31 +129,31 @@ pub fn phys_addr_space_end_page() -> *const Page { /// - Any miscalculation or attribute error will likely be fatal. Needs careful manual checking. pub unsafe fn kernel_map_binary() -> Result<(), &'static str> { generic_mmu::kernel_map_pages_at( - "Kernel boot-core stack", - &virt_stack_page_desc(), - &phys_stack_page_desc(), + "Kernel code and RO data", + &virt_rx_page_desc(), + &phys_rx_page_desc(), &AttributeFields { mem_attributes: MemAttributes::CacheableDRAM, - acc_perms: AccessPermissions::ReadWrite, - execute_never: true, + acc_perms: AccessPermissions::ReadOnly, + execute_never: false, }, )?; generic_mmu::kernel_map_pages_at( - "Kernel code and RO data", - &virt_ro_page_desc(), - &phys_ro_page_desc(), + "Kernel data and bss", + &virt_rw_page_desc(), + &phys_rw_page_desc(), &AttributeFields { mem_attributes: MemAttributes::CacheableDRAM, - acc_perms: AccessPermissions::ReadOnly, - execute_never: false, + acc_perms: AccessPermissions::ReadWrite, + execute_never: true, }, )?; generic_mmu::kernel_map_pages_at( - "Kernel data and bss", - &virt_data_page_desc(), - &phys_data_page_desc(), + "Kernel boot-core stack", + &virt_boot_core_stack_page_desc(), + &phys_boot_core_stack_page_desc(), &AttributeFields { mem_attributes: MemAttributes::CacheableDRAM, acc_perms: AccessPermissions::ReadWrite, @@ -169,7 +176,13 @@ mod tests { /// Check alignment of the kernel's virtual memory layout sections. #[kernel_test] fn virt_mem_layout_sections_are_64KiB_aligned() { - for i in [virt_stack_page_desc, virt_ro_page_desc, virt_data_page_desc].iter() { + for i in [ + virt_rx_page_desc, + virt_rw_page_desc, + virt_boot_core_stack_page_desc, + ] + .iter() + { let start: usize = i().start_addr().into_usize(); let end: usize = i().end_addr().into_usize(); @@ -183,9 +196,9 @@ mod tests { #[kernel_test] fn virt_mem_layout_has_no_overlaps() { let layout = [ - virt_stack_page_desc(), - virt_ro_page_desc(), - virt_data_page_desc(), + virt_rx_page_desc(), + virt_rw_page_desc(), + virt_boot_core_stack_page_desc(), ]; for (i, first_range) in layout.iter().enumerate() { diff --git a/X1_JTAG_boot/Makefile b/X1_JTAG_boot/Makefile index 4206c528..b5a56d07 100644 --- a/X1_JTAG_boot/Makefile +++ b/X1_JTAG_boot/Makefile @@ -122,6 +122,7 @@ objdump: $(KERNEL_ELF) @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ --section .rodata \ + --section .got \ $(KERNEL_ELF) | rustfilt nm: $(KERNEL_ELF) diff --git a/X1_JTAG_boot/jtag_boot_rpi3.img b/X1_JTAG_boot/jtag_boot_rpi3.img index de6648804151541fd045c79f2f5dcf824f6094db..d45cc1ff0028c6d32ecd176a828fc440da668d97 100755 GIT binary patch delta 478 zcmca$f5U!)C_4kg29AsFKQ~G!@-jMaw&MNFDEQE5A~yrW1RkK&D`$p@*@>I&__dkD z3;2pI@{0LpKG^1((6Hi$uF zCqQY9$&E7NnhDGh(E=!~0ks(H3LwDa Lj2n|z%BuqaNydb6 delta 496 zcmca%f5Co&C^O@Npp7z$yo|=1?RY;k3SKmt$j!hofro)%!z*WoiP?dho%pqx#1sW4 zdUBqe#RZh|dT2NC{r~?T-hZ^++$<=>2$EaVv!f`B^VF=@Ao0nJ6SF_sPF^jfC3aD9 z;=A?CD_`m}{Nw~`^{!nzTi}u1=GQ`8jDfe@e{!-q?DP~BG3I1t*qH(3%THz4>Gc2q zbP$`9VMY+=Oop9yP(Dab9?1Xae{jVC=J;zM%mFkLWG=@=_n(?qC%cJgGhUrsBvQ_J zaq=sXel@7WG&oPp0;$pjI{Y2bfp4`LR%Y$$4D#YxRCEsLiTR>RjEst#4~e~FWMu#X zmB||=#5Dt$fTjb11_OkafbyN3eH8+H3=9nwLLGxb7#OBZ{wN{NIAb%Xq&~Ca26>3$ z2pI^y1IllJ^1((6)`&r5d!V$+>yOnjx!urg~`XOI`qqN3N28798@|NleJN85?7jTu*R*RGoV_A|r8x5i8> zv;U@D1{yM*Ma4BOn1JelK!*WBGeG%H&b|r( zJ_d${3ZafcAq)&tCT|oKXPmM5q-Z&l;tVN>;sgl@y#UJZfbzjcTUv-hWIdp?2Gj}( zu!RgT3mIaVA?k9Vw8rF(65@#S delta 363 zcmdmCy1{gUC^O@Npp7!Jyo}15t$05(3LZ3?$j!hofro)%!z*WoiP?^u?fA8s7z-z7 z2`*+7oXjUAF8k1S;%j5ZmE5(fX21Q+F!8N1)5`3>X_tXoCiEmub`sie>goDZi`8Lg zH%miMmZ*ra7AwO}4xkt(!>S<8rwls}Fvnj5VGf`U4o8qU!vsy&$!5aZjINWDgpCBc;?iH$W}hFnOYsIsk1kQ^^1T diff --git a/X1_JTAG_boot/src/bsp/raspberrypi/link.ld b/X1_JTAG_boot/src/bsp/raspberrypi/link.ld index 573abc5f..87e6a976 100644 --- a/X1_JTAG_boot/src/bsp/raspberrypi/link.ld +++ b/X1_JTAG_boot/src/bsp/raspberrypi/link.ld @@ -3,37 +3,47 @@ * Copyright (c) 2018-2021 Andre Richter */ +/* The address at which the the kernel binary will be loaded by the Raspberry's firmware */ +__rpi_load_addr = 0x80000; + +ENTRY(__rpi_load_addr) + +PHDRS +{ + segment_rx PT_LOAD FLAGS(5); /* 5 == RX */ + segment_rw PT_LOAD FLAGS(6); /* 6 == RW */ +} + SECTIONS { - /* Set current address to the value from which the RPi starts execution */ - . = 0x80000; + . = __rpi_load_addr; + /*********************************************************************************************** + * Code + RO Data + Global Offset Table + ***********************************************************************************************/ + __rx_start = .; .text : { - *(.text._start) *(.text*) - } + KEEP(*(.text._start)) + *(.text*) + } :segment_rx - .rodata : - { - *(.rodata*) - } + .rodata : ALIGN(8) { *(.rodata*) } :segment_rx + .got : ALIGN(8) { *(.got) } :segment_rx - .data : - { - *(.data*) - } + /*********************************************************************************************** + * Data + BSS + ***********************************************************************************************/ + .data : { *(.data*) } :segment_rw /* Section is zeroed in u64 chunks, align start and end to 8 bytes */ - .bss ALIGN(8): + .bss : ALIGN(8) { __bss_start = .; *(.bss*); . = ALIGN(8); - /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ - . += 8; + . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ __bss_end_inclusive = . - 8; - } - - /DISCARD/ : { *(.comment*) } + } :NONE } diff --git a/X1_JTAG_boot/src/bsp/raspberrypi/memory.rs b/X1_JTAG_boot/src/bsp/raspberrypi/memory.rs index fb47b141..56a3306e 100644 --- a/X1_JTAG_boot/src/bsp/raspberrypi/memory.rs +++ b/X1_JTAG_boot/src/bsp/raspberrypi/memory.rs @@ -12,6 +12,8 @@ use core::{cell::UnsafeCell, ops::RangeInclusive}; // Symbols from the linker script. extern "Rust" { + static __rx_start: UnsafeCell<()>; + static __bss_start: UnsafeCell; static __bss_end_inclusive: UnsafeCell; } @@ -20,10 +22,9 @@ extern "Rust" { // Public Definitions //-------------------------------------------------------------------------------------------------- -/// The board's memory map. +/// The board's physical memory map. #[rustfmt::skip] pub(super) mod map { - pub const BOOT_CORE_STACK_END: usize = 0x8_0000; pub const GPIO_OFFSET: usize = 0x0020_0000; pub const UART_OFFSET: usize = 0x0020_1000; @@ -49,6 +50,20 @@ pub(super) mod map { } } +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +/// Start address of the Read+Execute (RX) range. +/// +/// # Safety +/// +/// - Value is provided by the linker script and must be trusted as-is. +#[inline(always)] +fn rx_start() -> usize { + unsafe { __rx_start.get() as usize } +} + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- @@ -56,7 +71,7 @@ pub(super) mod map { /// Exclusive end address of the boot core's stack. #[inline(always)] pub fn boot_core_stack_end() -> usize { - map::BOOT_CORE_STACK_END + rx_start() } /// Return the inclusive range spanning the .bss section.