Overhaul linker script

pull/110/head
Andre Richter 3 years ago
parent fa4a2de331
commit 223989adb9
No known key found for this signature in database
GPG Key ID: 2116C1AB102F615E

@ -102,7 +102,6 @@ objdump: $(KERNEL_ELF)
$(call colorecho, "\nLaunching objdump") $(call colorecho, "\nLaunching objdump")
@$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \
--section .text \ --section .text \
--section .rodata \
$(KERNEL_ELF) | rustfilt $(KERNEL_ELF) | rustfilt
nm: $(KERNEL_ELF) nm: $(KERNEL_ELF)

@ -3,15 +3,26 @@
* Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com> * Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
*/ */
/* 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 SECTIONS
{ {
/* Set current address to the value from which the RPi starts execution */ . = __rpi_load_addr;
. = 0x80000;
/***********************************************************************************************
* Code
***********************************************************************************************/
.text : .text :
{ {
*(.text._start) *(.text*) KEEP(*(.text._start))
} *(.text*)
} :segment_rx
/DISCARD/ : { *(.comment*) }
} }

@ -103,6 +103,7 @@ objdump: $(KERNEL_ELF)
@$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \
--section .text \ --section .text \
--section .rodata \ --section .rodata \
--section .got \
$(KERNEL_ELF) | rustfilt $(KERNEL_ELF) | rustfilt
nm: $(KERNEL_ELF) nm: $(KERNEL_ELF)

@ -9,8 +9,7 @@
## Notable additions ## Notable additions
- More sections in linker script: - More sections in linker script:
- `.rodata`, `.data` - `.rodata`, `.got`, `.data`, `.bss`
- `.bss`
- `_start()`: - `_start()`:
- Halt core if core != `core0`. - Halt core if core != `core0`.
- `core0` jumps to the `runtime_init()` Rust function. - `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 = [] default = []
bsp_rpi3 = [] 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 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 --- 01_wait_forever/src/_arch/aarch64/cpu/boot.S
+++ 02_runtime_init/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 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 --- 01_wait_forever/src/bsp/raspberrypi/link.ld
+++ 02_runtime_init/src/bsp/raspberrypi/link.ld +++ 02_runtime_init/src/bsp/raspberrypi/link.ld
@@ -13,5 +13,27 @@ @@ -11,6 +11,7 @@
*(.text._start) *(.text*) PHDRS
} {
segment_rx PT_LOAD FLAGS(5); /* 5 == RX */
+ segment_rw PT_LOAD FLAGS(6); /* 6 == RW */
}
+ .rodata : SECTIONS
+ { @@ -18,11 +19,30 @@
+ *(.rodata*) . = __rpi_load_addr;
+ }
/***********************************************************************************************
- * Code
+ * Code + RO Data + Global Offset Table
***********************************************************************************************/
.text :
{
KEEP(*(.text._start))
*(.text*)
} :segment_rx
+ +
+ .data : + .rodata : ALIGN(8) { *(.rodata*) } :segment_rx
+ { + .got : ALIGN(8) { *(.got) } :segment_rx
+ *(.data*) +
+ } + /***********************************************************************************************
+ * Data + BSS
+ ***********************************************************************************************/
+ .data : { *(.data*) } :segment_rw
+ +
+ /* Section is zeroed in u64 chunks, align start and end to 8 bytes */ + /* Section is zeroed in u64 chunks, align start and end to 8 bytes */
+ .bss ALIGN(8): + .bss : ALIGN(8)
+ { + {
+ __bss_start = .; + __bss_start = .;
+ *(.bss*); + *(.bss*);
+ . = ALIGN(8); + . = ALIGN(8);
+ +
+ /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ + . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */
+ . += 8;
+ __bss_end_inclusive = . - 8; + __bss_end_inclusive = . - 8;
+ } + } :NONE
+
/DISCARD/ : { *(.comment*) }
} }
diff -uNr 01_wait_forever/src/bsp/raspberrypi/memory.rs 02_runtime_init/src/bsp/raspberrypi/memory.rs diff -uNr 01_wait_forever/src/bsp/raspberrypi/memory.rs 02_runtime_init/src/bsp/raspberrypi/memory.rs

@ -3,37 +3,46 @@
* Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com> * Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
*/ */
/* 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 SECTIONS
{ {
/* Set current address to the value from which the RPi starts execution */ . = __rpi_load_addr;
. = 0x80000;
/***********************************************************************************************
* Code + RO Data + Global Offset Table
***********************************************************************************************/
.text : .text :
{ {
*(.text._start) *(.text*) KEEP(*(.text._start))
} *(.text*)
} :segment_rx
.rodata : .rodata : ALIGN(8) { *(.rodata*) } :segment_rx
{ .got : ALIGN(8) { *(.got) } :segment_rx
*(.rodata*)
}
.data : /***********************************************************************************************
{ * Data + BSS
*(.data*) ***********************************************************************************************/
} .data : { *(.data*) } :segment_rw
/* Section is zeroed in u64 chunks, align start and end to 8 bytes */ /* Section is zeroed in u64 chunks, align start and end to 8 bytes */
.bss ALIGN(8): .bss : ALIGN(8)
{ {
__bss_start = .; __bss_start = .;
*(.bss*); *(.bss*);
. = ALIGN(8); . = ALIGN(8);
/* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */
. += 8;
__bss_end_inclusive = . - 8; __bss_end_inclusive = . - 8;
} } :NONE
/DISCARD/ : { *(.comment*) }
} }

@ -103,6 +103,7 @@ objdump: $(KERNEL_ELF)
@$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \
--section .text \ --section .text \
--section .rodata \ --section .rodata \
--section .got \
$(KERNEL_ELF) | rustfilt $(KERNEL_ELF) | rustfilt
nm: $(KERNEL_ELF) nm: $(KERNEL_ELF)

@ -3,37 +3,46 @@
* Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com> * Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
*/ */
/* 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 SECTIONS
{ {
/* Set current address to the value from which the RPi starts execution */ . = __rpi_load_addr;
. = 0x80000;
/***********************************************************************************************
* Code + RO Data + Global Offset Table
***********************************************************************************************/
.text : .text :
{ {
*(.text._start) *(.text*) KEEP(*(.text._start))
} *(.text*)
} :segment_rx
.rodata : .rodata : ALIGN(8) { *(.rodata*) } :segment_rx
{ .got : ALIGN(8) { *(.got) } :segment_rx
*(.rodata*)
}
.data : /***********************************************************************************************
{ * Data + BSS
*(.data*) ***********************************************************************************************/
} .data : { *(.data*) } :segment_rw
/* Section is zeroed in u64 chunks, align start and end to 8 bytes */ /* Section is zeroed in u64 chunks, align start and end to 8 bytes */
.bss ALIGN(8): .bss : ALIGN(8)
{ {
__bss_start = .; __bss_start = .;
*(.bss*); *(.bss*);
. = ALIGN(8); . = ALIGN(8);
/* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */
. += 8;
__bss_end_inclusive = . - 8; __bss_end_inclusive = . - 8;
} } :NONE
/DISCARD/ : { *(.comment*) }
} }

@ -103,6 +103,7 @@ objdump: $(KERNEL_ELF)
@$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \
--section .text \ --section .text \
--section .rodata \ --section .rodata \
--section .got \
$(KERNEL_ELF) | rustfilt $(KERNEL_ELF) | rustfilt
nm: $(KERNEL_ELF) nm: $(KERNEL_ELF)

@ -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. +/// Used by `arch` code to find the early boot core.
+pub const BOOT_CORE_ID: usize = 0; +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 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 --- 03_hacky_hello_world/src/bsp/raspberrypi/memory.rs
+++ 04_zero_overhead_abstraction/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<u64>;
static __bss_end_inclusive: UnsafeCell<u64>;
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
+// Public Definitions +// Private Code
+//-------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------
+ +
+/// The board's memory map. +/// Start address of the Read+Execute (RX) range.
+#[rustfmt::skip] +///
+pub(super) mod map { +/// # Safety
+ pub const BOOT_CORE_STACK_END: usize = 0x8_0000; +///
+/// - 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. +/// Exclusive end address of the boot core's stack.
+#[inline(always)] +#[inline(always)]
+pub fn boot_core_stack_end() -> usize { +pub fn boot_core_stack_end() -> usize {
+ map::BOOT_CORE_STACK_END + rx_start()
+} +}
+ +
/// Return the inclusive range spanning the .bss section. /// Return the inclusive range spanning the .bss section.

@ -3,37 +3,47 @@
* Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com> * Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
*/ */
/* 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 SECTIONS
{ {
/* Set current address to the value from which the RPi starts execution */ . = __rpi_load_addr;
. = 0x80000;
/***********************************************************************************************
* Code + RO Data + Global Offset Table
***********************************************************************************************/
__rx_start = .;
.text : .text :
{ {
*(.text._start) *(.text*) KEEP(*(.text._start))
} *(.text*)
} :segment_rx
.rodata : .rodata : ALIGN(8) { *(.rodata*) } :segment_rx
{ .got : ALIGN(8) { *(.got) } :segment_rx
*(.rodata*)
}
.data : /***********************************************************************************************
{ * Data + BSS
*(.data*) ***********************************************************************************************/
} .data : { *(.data*) } :segment_rw
/* Section is zeroed in u64 chunks, align start and end to 8 bytes */ /* Section is zeroed in u64 chunks, align start and end to 8 bytes */
.bss ALIGN(8): .bss : ALIGN(8)
{ {
__bss_start = .; __bss_start = .;
*(.bss*); *(.bss*);
. = ALIGN(8); . = ALIGN(8);
/* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */
. += 8;
__bss_end_inclusive = . - 8; __bss_end_inclusive = . - 8;
} } :NONE
/DISCARD/ : { *(.comment*) }
} }

@ -12,18 +12,24 @@ use core::{cell::UnsafeCell, ops::RangeInclusive};
// Symbols from the linker script. // Symbols from the linker script.
extern "Rust" { extern "Rust" {
static __rx_start: UnsafeCell<()>;
static __bss_start: UnsafeCell<u64>; static __bss_start: UnsafeCell<u64>;
static __bss_end_inclusive: UnsafeCell<u64>; static __bss_end_inclusive: UnsafeCell<u64>;
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Public Definitions // Private Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// The board's memory map. /// Start address of the Read+Execute (RX) range.
#[rustfmt::skip] ///
pub(super) mod map { /// # Safety
pub const BOOT_CORE_STACK_END: usize = 0x8_0000; ///
/// - 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. /// Exclusive end address of the boot core's stack.
#[inline(always)] #[inline(always)]
pub fn boot_core_stack_end() -> usize { pub fn boot_core_stack_end() -> usize {
map::BOOT_CORE_STACK_END rx_start()
} }
/// Return the inclusive range spanning the .bss section. /// Return the inclusive range spanning the .bss section.

@ -103,6 +103,7 @@ objdump: $(KERNEL_ELF)
@$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \
--section .text \ --section .text \
--section .rodata \ --section .rodata \
--section .got \
$(KERNEL_ELF) | rustfilt $(KERNEL_ELF) | rustfilt
nm: $(KERNEL_ELF) nm: $(KERNEL_ELF)

@ -3,37 +3,47 @@
* Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com> * Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
*/ */
/* 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 SECTIONS
{ {
/* Set current address to the value from which the RPi starts execution */ . = __rpi_load_addr;
. = 0x80000;
/***********************************************************************************************
* Code + RO Data + Global Offset Table
***********************************************************************************************/
__rx_start = .;
.text : .text :
{ {
*(.text._start) *(.text*) KEEP(*(.text._start))
} *(.text*)
} :segment_rx
.rodata : .rodata : ALIGN(8) { *(.rodata*) } :segment_rx
{ .got : ALIGN(8) { *(.got) } :segment_rx
*(.rodata*)
}
.data : /***********************************************************************************************
{ * Data + BSS
*(.data*) ***********************************************************************************************/
} .data : { *(.data*) } :segment_rw
/* Section is zeroed in u64 chunks, align start and end to 8 bytes */ /* Section is zeroed in u64 chunks, align start and end to 8 bytes */
.bss ALIGN(8): .bss : ALIGN(8)
{ {
__bss_start = .; __bss_start = .;
*(.bss*); *(.bss*);
. = ALIGN(8); . = ALIGN(8);
/* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */
. += 8;
__bss_end_inclusive = . - 8; __bss_end_inclusive = . - 8;
} } :NONE
/DISCARD/ : { *(.comment*) }
} }

@ -12,18 +12,24 @@ use core::{cell::UnsafeCell, ops::RangeInclusive};
// Symbols from the linker script. // Symbols from the linker script.
extern "Rust" { extern "Rust" {
static __rx_start: UnsafeCell<()>;
static __bss_start: UnsafeCell<u64>; static __bss_start: UnsafeCell<u64>;
static __bss_end_inclusive: UnsafeCell<u64>; static __bss_end_inclusive: UnsafeCell<u64>;
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Public Definitions // Private Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// The board's memory map. /// Start address of the Read+Execute (RX) range.
#[rustfmt::skip] ///
pub(super) mod map { /// # Safety
pub const BOOT_CORE_STACK_END: usize = 0x8_0000; ///
/// - 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. /// Exclusive end address of the boot core's stack.
#[inline(always)] #[inline(always)]
pub fn boot_core_stack_end() -> usize { pub fn boot_core_stack_end() -> usize {
map::BOOT_CORE_STACK_END rx_start()
} }
/// Return the inclusive range spanning the .bss section. /// Return the inclusive range spanning the .bss section.

@ -122,6 +122,7 @@ objdump: $(KERNEL_ELF)
@$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \
--section .text \ --section .text \
--section .rodata \ --section .rodata \
--section .got \
$(KERNEL_ELF) | rustfilt $(KERNEL_ELF) | rustfilt
nm: $(KERNEL_ELF) nm: $(KERNEL_ELF)

@ -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 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 --- 05_safe_globals/src/bsp/raspberrypi/memory.rs
+++ 06_drivers_gpio_uart/src/bsp/raspberrypi/memory.rs +++ 06_drivers_gpio_uart/src/bsp/raspberrypi/memory.rs
@@ -24,6 +24,29 @@ @@ -19,6 +19,38 @@
#[rustfmt::skip] }
pub(super) mod map {
pub const BOOT_CORE_STACK_END: usize = 0x8_0000; //--------------------------------------------------------------------------------------------------
+// Public Definitions
+//--------------------------------------------------------------------------------------------------
+
+/// The board's physical memory map.
+#[rustfmt::skip]
+pub(super) mod map {
+ +
+ pub const GPIO_OFFSET: usize = 0x0020_0000; + pub const GPIO_OFFSET: usize = 0x0020_0000;
+ pub const UART_OFFSET: usize = 0x0020_1000; + 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 GPIO_START: usize = START + GPIO_OFFSET;
+ pub const PL011_UART_START: usize = START + UART_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 diff -uNr 05_safe_globals/src/bsp/raspberrypi.rs 06_drivers_gpio_uart/src/bsp/raspberrypi.rs
--- 05_safe_globals/src/bsp/raspberrypi.rs --- 05_safe_globals/src/bsp/raspberrypi.rs
+++ 06_drivers_gpio_uart/src/bsp/raspberrypi.rs +++ 06_drivers_gpio_uart/src/bsp/raspberrypi.rs

@ -3,37 +3,47 @@
* Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com> * Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
*/ */
/* 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 SECTIONS
{ {
/* Set current address to the value from which the RPi starts execution */ . = __rpi_load_addr;
. = 0x80000;
/***********************************************************************************************
* Code + RO Data + Global Offset Table
***********************************************************************************************/
__rx_start = .;
.text : .text :
{ {
*(.text._start) *(.text*) KEEP(*(.text._start))
} *(.text*)
} :segment_rx
.rodata : .rodata : ALIGN(8) { *(.rodata*) } :segment_rx
{ .got : ALIGN(8) { *(.got) } :segment_rx
*(.rodata*)
}
.data : /***********************************************************************************************
{ * Data + BSS
*(.data*) ***********************************************************************************************/
} .data : { *(.data*) } :segment_rw
/* Section is zeroed in u64 chunks, align start and end to 8 bytes */ /* Section is zeroed in u64 chunks, align start and end to 8 bytes */
.bss ALIGN(8): .bss : ALIGN(8)
{ {
__bss_start = .; __bss_start = .;
*(.bss*); *(.bss*);
. = ALIGN(8); . = ALIGN(8);
/* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */
. += 8;
__bss_end_inclusive = . - 8; __bss_end_inclusive = . - 8;
} } :NONE
/DISCARD/ : { *(.comment*) }
} }

@ -12,6 +12,8 @@ use core::{cell::UnsafeCell, ops::RangeInclusive};
// Symbols from the linker script. // Symbols from the linker script.
extern "Rust" { extern "Rust" {
static __rx_start: UnsafeCell<()>;
static __bss_start: UnsafeCell<u64>; static __bss_start: UnsafeCell<u64>;
static __bss_end_inclusive: UnsafeCell<u64>; static __bss_end_inclusive: UnsafeCell<u64>;
} }
@ -20,10 +22,9 @@ extern "Rust" {
// Public Definitions // Public Definitions
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// The board's memory map. /// The board's physical memory map.
#[rustfmt::skip] #[rustfmt::skip]
pub(super) mod map { pub(super) mod map {
pub const BOOT_CORE_STACK_END: usize = 0x8_0000;
pub const GPIO_OFFSET: usize = 0x0020_0000; pub const GPIO_OFFSET: usize = 0x0020_0000;
pub const UART_OFFSET: usize = 0x0020_1000; 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 // Public Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -56,7 +71,7 @@ pub(super) mod map {
/// Exclusive end address of the boot core's stack. /// Exclusive end address of the boot core's stack.
#[inline(always)] #[inline(always)]
pub fn boot_core_stack_end() -> usize { pub fn boot_core_stack_end() -> usize {
map::BOOT_CORE_STACK_END rx_start()
} }
/// Return the inclusive range spanning the .bss section. /// Return the inclusive range spanning the .bss section.

@ -165,14 +165,6 @@ diff -uNr 06_drivers_gpio_uart/Makefile 07_uart_chainloader/Makefile
clippy: clippy:
@RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(CLIPPY_CMD) @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 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 --- 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 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 --- 06_drivers_gpio_uart/src/bsp/raspberrypi/link.ld
+++ 07_uart_chainloader/src/bsp/raspberrypi/link.ld +++ 07_uart_chainloader/src/bsp/raspberrypi/link.ld
@@ -5,12 +5,15 @@ @@ -16,12 +16,13 @@
SECTIONS SECTIONS
{ {
- /* Set current address to the value from which the RPi starts execution */ - . = __rpi_load_addr;
- . = 0x80000;
+ /* Set the link address to 32 MiB */ + /* Set the link address to 32 MiB */
+ . = 0x2000000; + . = 0x2000000;
/***********************************************************************************************
* Code + RO Data + Global Offset Table
***********************************************************************************************/
- __rx_start = .;
+ __binary_start = .; + __binary_start = .;
.text : .text :
{ {
- *(.text._start) *(.text*) KEEP(*(.text._start))
+ *(.text._start) @@ -46,4 +47,10 @@
+ KEEP(*(.text.runtime_init)) . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */
+ *(.text*);
}
.rodata :
@@ -35,5 +38,16 @@
__bss_end_inclusive = . - 8; __bss_end_inclusive = . - 8;
} } :NONE
+ .got :
+ {
+ *(.got*)
+ }
+ +
+ /* Fill up to 8 byte, b/c relocating the binary is done in u64 chunks */ + /* Fill up to 8 byte, b/c relocating the binary is done in u64 chunks */
+ . = ALIGN(8); + . = ALIGN(8);
+ __binary_end_inclusive = . - 8; + __binary_end_inclusive = . - 8;
+ +
+ __runtime_init_reloc = runtime_init; + __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 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 --- 06_drivers_gpio_uart/src/bsp/raspberrypi/memory.rs
+++ 07_uart_chainloader/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. // Symbols from the linker script.
extern "Rust" { extern "Rust" {
- static __rx_start: UnsafeCell<()>;
-
+ static __binary_start: UnsafeCell<u64>; + static __binary_start: UnsafeCell<u64>;
+ static __binary_end_inclusive: UnsafeCell<u64>;
+ static __runtime_init_reloc: UnsafeCell<u64>;
static __bss_start: UnsafeCell<u64>; static __bss_start: UnsafeCell<u64>;
static __bss_end_inclusive: UnsafeCell<u64>; static __bss_end_inclusive: UnsafeCell<u64>;
+ static __binary_end_inclusive: UnsafeCell<u64>;
+
+ static __runtime_init_reloc: UnsafeCell<u64>;
} }
@@ -23,10 +26,12 @@
/// The board's memory map. //--------------------------------------------------------------------------------------------------
@@ -25,9 +27,12 @@
/// The board's physical memory map.
#[rustfmt::skip] #[rustfmt::skip]
pub(super) mod map { pub(super) mod map {
- pub const BOOT_CORE_STACK_END: usize = 0x8_0000;
+ 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 GPIO_OFFSET: usize = 0x0020_0000;
- pub const UART_OFFSET: usize = 0x0020_1000; - 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 GPIO_OFFSET: usize = 0x0020_0000;
+ pub const UART_OFFSET: usize = 0x0020_1000; + pub const UART_OFFSET: usize = 0x0020_1000;
/// Physical devices. /// Physical devices.
#[cfg(feature = "bsp_rpi3")] #[cfg(feature = "bsp_rpi3")]
@@ -59,13 +64,35 @@ @@ -51,36 +56,44 @@
map::BOOT_CORE_STACK_END
} }
-/// 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. +/// The address on which the Raspberry firmware loads every binary by default.
+#[inline(always)] +#[inline(always)]
+pub fn board_default_load_addr() -> *const u64 { +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. +/// 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. +/// - Values are provided by the linker script and must be trusted as-is.
+/// - The linker-provided addresses must be u64 aligned. +/// - The linker-provided addresses must be u64 aligned.
+pub fn relocated_binary_range_inclusive() -> RangeInclusive<*mut u64> { +pub fn relocated_binary_range_inclusive() -> RangeInclusive<*mut u64> {
+ unsafe { RangeInclusive::new(__binary_start.get(), __binary_end_inclusive.get()) } + 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()`. +/// 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 { +pub fn relocated_runtime_init_addr() -> *const u64 {
+ unsafe { __runtime_init_reloc.get() as _ } + unsafe { __runtime_init_reloc.get() as _ }
+} }
+
-/// Return the inclusive range spanning the .bss section.
+/// Return the inclusive range spanning the relocated .bss section. +/// Return the inclusive range spanning the relocated .bss section.
/// ///
/// # Safety /// # 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 diff -uNr 06_drivers_gpio_uart/src/relocate.rs 07_uart_chainloader/src/relocate.rs
--- 06_drivers_gpio_uart/src/relocate.rs --- 06_drivers_gpio_uart/src/relocate.rs
+++ 07_uart_chainloader/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 +// SPDX-License-Identifier: MIT OR Apache-2.0
+// +//
+// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com> +// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
@ -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); + current_binary_start_addr = current_binary_start_addr.offset(1);
+ } + }
+ +
+ // The following function calls form a hack to achieve an "absolute jump" to + // The following function calls realize an "absolute jump" to `runtime_init::runtime_init()` by
+ // `runtime_init::runtime_init()` by forcing an indirection through the global offset table + // forcing an indirection through the global offset table (GOT), so that execution continues
+ // (GOT), so that execution continues from the relocated binary. + // 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; + let relocated_runtime_init_addr = bsp::memory::relocated_runtime_init_addr() as usize;
+ cpu::branch_to_raw_addr(relocated_runtime_init_addr) + cpu::branch_to_raw_addr(relocated_runtime_init_addr)
+} +}

@ -3,51 +3,54 @@
* Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com> * Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
*/ */
/* 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 SECTIONS
{ {
/* Set the link address to 32 MiB */ /* Set the link address to 32 MiB */
. = 0x2000000; . = 0x2000000;
/***********************************************************************************************
* Code + RO Data + Global Offset Table
***********************************************************************************************/
__binary_start = .; __binary_start = .;
.text : .text :
{ {
*(.text._start) KEEP(*(.text._start))
KEEP(*(.text.runtime_init)) *(.text*)
*(.text*); } :segment_rx
}
.rodata : .rodata : ALIGN(8) { *(.rodata*) } :segment_rx
{ .got : ALIGN(8) { *(.got) } :segment_rx
*(.rodata*)
}
.data : /***********************************************************************************************
{ * Data + BSS
*(.data*) ***********************************************************************************************/
} .data : { *(.data*) } :segment_rw
/* Section is zeroed in u64 chunks, align start and end to 8 bytes */ /* Section is zeroed in u64 chunks, align start and end to 8 bytes */
.bss ALIGN(8): .bss : ALIGN(8)
{ {
__bss_start = .; __bss_start = .;
*(.bss*); *(.bss*);
. = ALIGN(8); . = ALIGN(8);
/* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */
. += 8;
__bss_end_inclusive = . - 8; __bss_end_inclusive = . - 8;
} } :NONE
.got :
{
*(.got*)
}
/* Fill up to 8 byte, b/c relocating the binary is done in u64 chunks */ /* Fill up to 8 byte, b/c relocating the binary is done in u64 chunks */
. = ALIGN(8); . = ALIGN(8);
__binary_end_inclusive = . - 8; __binary_end_inclusive = . - 8;
__runtime_init_reloc = runtime_init; __runtime_init_reloc = runtime_init;
/DISCARD/ : { *(.comment*) }
} }

@ -13,17 +13,18 @@ use core::{cell::UnsafeCell, ops::RangeInclusive};
// Symbols from the linker script. // Symbols from the linker script.
extern "Rust" { extern "Rust" {
static __binary_start: UnsafeCell<u64>; static __binary_start: UnsafeCell<u64>;
static __binary_end_inclusive: UnsafeCell<u64>;
static __runtime_init_reloc: UnsafeCell<u64>;
static __bss_start: UnsafeCell<u64>; static __bss_start: UnsafeCell<u64>;
static __bss_end_inclusive: UnsafeCell<u64>; static __bss_end_inclusive: UnsafeCell<u64>;
static __binary_end_inclusive: UnsafeCell<u64>;
static __runtime_init_reloc: UnsafeCell<u64>;
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Public Definitions // Public Definitions
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// The board's memory map. /// The board's physical memory map.
#[rustfmt::skip] #[rustfmt::skip]
pub(super) mod map { pub(super) mod map {
pub const BOOT_CORE_STACK_END: usize = 0x8_0000; pub const BOOT_CORE_STACK_END: usize = 0x8_0000;

@ -36,16 +36,14 @@ pub unsafe fn relocate_self() -> ! {
current_binary_start_addr = current_binary_start_addr.offset(1); current_binary_start_addr = current_binary_start_addr.offset(1);
} }
// The following function calls form a hack to achieve an "absolute jump" to // The following function calls realize an "absolute jump" to `runtime_init::runtime_init()` by
// `runtime_init::runtime_init()` by forcing an indirection through the global offset table // forcing an indirection through the global offset table (GOT), so that execution continues
// (GOT), so that execution continues from the relocated binary. // from the relocated binary.
// //
// Without this, the address of `runtime_init()` would be calculated as a relative offset from // Without the indirection through the assembly, the address of `runtime_init()` would be
// the current program counter, since we are compiling as `position independent code`. This // calculated as a relative offset from the current program counter, since we are compiling as
// would cause us to keep executing from the address to which the firmware loaded us, instead of // `position independent code`. This would cause us to keep executing from the address to which
// the relocated position. // the firmware loaded us, instead of the relocated position.
//
// There likely is a more elegant way to do this.
let relocated_runtime_init_addr = bsp::memory::relocated_runtime_init_addr() as usize; let relocated_runtime_init_addr = bsp::memory::relocated_runtime_init_addr() as usize;
cpu::branch_to_raw_addr(relocated_runtime_init_addr) cpu::branch_to_raw_addr(relocated_runtime_init_addr)
} }

@ -122,6 +122,7 @@ objdump: $(KERNEL_ELF)
@$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \
--section .text \ --section .text \
--section .rodata \ --section .rodata \
--section .got \
$(KERNEL_ELF) | rustfilt $(KERNEL_ELF) | rustfilt
nm: $(KERNEL_ELF) nm: $(KERNEL_ELF)

@ -96,14 +96,6 @@ diff -uNr 07_uart_chainloader/Makefile 08_timestamps/Makefile
clippy: clippy:
@RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(CLIPPY_CMD) @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 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 --- 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 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 --- 07_uart_chainloader/src/bsp/raspberrypi/link.ld
+++ 08_timestamps/src/bsp/raspberrypi/link.ld +++ 08_timestamps/src/bsp/raspberrypi/link.ld
@@ -5,15 +5,12 @@ @@ -16,13 +16,12 @@
SECTIONS SECTIONS
{ {
- /* Set the link address to 32 MiB */ - /* Set the link address to 32 MiB */
- . = 0x2000000; - . = 0x2000000;
+ /* Set current address to the value from which the RPi starts execution */ + . = __rpi_load_addr;
+ . = 0x80000;
/***********************************************************************************************
* Code + RO Data + Global Offset Table
***********************************************************************************************/
- __binary_start = .; - __binary_start = .;
+ __rx_start = .;
.text : .text :
{ {
- *(.text._start) KEEP(*(.text._start))
- KEEP(*(.text.runtime_init)) @@ -47,10 +46,4 @@
- *(.text*); . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */
+ *(.text._start) *(.text*)
}
.rodata :
@@ -38,16 +35,5 @@
__bss_end_inclusive = . - 8; __bss_end_inclusive = . - 8;
} } :NONE
- .got :
- {
- *(.got*)
- }
- -
- /* Fill up to 8 byte, b/c relocating the binary is done in u64 chunks */ - /* Fill up to 8 byte, b/c relocating the binary is done in u64 chunks */
- . = ALIGN(8); - . = ALIGN(8);
- __binary_end_inclusive = . - 8; - __binary_end_inclusive = . - 8;
- -
- __runtime_init_reloc = runtime_init; - __runtime_init_reloc = runtime_init;
-
/DISCARD/ : { *(.comment*) }
} }
diff -uNr 07_uart_chainloader/src/bsp/raspberrypi/memory.rs 08_timestamps/src/bsp/raspberrypi/memory.rs 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 --- 07_uart_chainloader/src/bsp/raspberrypi/memory.rs
+++ 08_timestamps/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. // Symbols from the linker script.
extern "Rust" { extern "Rust" {
- static __binary_start: UnsafeCell<u64>; - static __binary_start: UnsafeCell<u64>;
- static __binary_end_inclusive: UnsafeCell<u64>; + static __rx_start: UnsafeCell<()>;
- static __runtime_init_reloc: UnsafeCell<u64>; +
static __bss_start: UnsafeCell<u64>; static __bss_start: UnsafeCell<u64>;
static __bss_end_inclusive: UnsafeCell<u64>; static __bss_end_inclusive: UnsafeCell<u64>;
- static __binary_end_inclusive: UnsafeCell<u64>;
-
- static __runtime_init_reloc: UnsafeCell<u64>;
} }
@@ -26,12 +23,10 @@
/// The board's memory map. //--------------------------------------------------------------------------------------------------
@@ -27,12 +25,9 @@
/// The board's physical memory map.
#[rustfmt::skip] #[rustfmt::skip]
pub(super) mod map { pub(super) mod map {
- pub const BOOT_CORE_STACK_END: usize = 0x8_0000; - 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 GPIO_OFFSET: usize = 0x0020_0000;
- pub const UART_OFFSET: usize = 0x0020_1000; - pub const UART_OFFSET: usize = 0x0020_1000;
+ pub const GPIO_OFFSET: usize = 0x0020_0000; + 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. /// Physical devices.
#[cfg(feature = "bsp_rpi3")] #[cfg(feature = "bsp_rpi3")]
@@ -64,35 +59,13 @@ @@ -56,44 +51,36 @@
map::BOOT_CORE_STACK_END
} }
//--------------------------------------------------------------------------------------------------
-// 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. -/// The address on which the Raspberry firmware loads every binary by default.
-#[inline(always)] -#[inline(always)]
-pub fn board_default_load_addr() -> *const u64 { -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. -/// Return the inclusive range spanning the relocated kernel binary.
-/// +/// Start address of the Read+Execute (RX) range.
-/// # Safety ///
-/// /// # Safety
///
-/// - Values are provided by the linker script and must be trusted as-is. -/// - Values are provided by the linker script and must be trusted as-is.
-/// - The linker-provided addresses must be u64 aligned. -/// - The linker-provided addresses must be u64 aligned.
-pub fn relocated_binary_range_inclusive() -> RangeInclusive<*mut u64> { -pub fn relocated_binary_range_inclusive() -> RangeInclusive<*mut u64> {
- unsafe { RangeInclusive::new(__binary_start.get(), __binary_end_inclusive.get()) } - 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()`. -/// 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 { -pub fn relocated_runtime_init_addr() -> *const u64 {
- unsafe { __runtime_init_reloc.get() as _ } - 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 relocated .bss section.
+/// Return the inclusive range spanning the .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 diff -uNr 07_uart_chainloader/src/relocate.rs 08_timestamps/src/relocate.rs
--- 07_uart_chainloader/src/relocate.rs --- 07_uart_chainloader/src/relocate.rs
+++ 08_timestamps/src/relocate.rs +++ 08_timestamps/src/relocate.rs
@@ -1,51 +0,0 @@ @@ -1,49 +0,0 @@
-// SPDX-License-Identifier: MIT OR Apache-2.0 -// SPDX-License-Identifier: MIT OR Apache-2.0
-// -//
-// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com> -// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
@ -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); - current_binary_start_addr = current_binary_start_addr.offset(1);
- } - }
- -
- // The following function calls form a hack to achieve an "absolute jump" to - // The following function calls realize an "absolute jump" to `runtime_init::runtime_init()` by
- // `runtime_init::runtime_init()` by forcing an indirection through the global offset table - // forcing an indirection through the global offset table (GOT), so that execution continues
- // (GOT), so that execution continues from the relocated binary. - // 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; - let relocated_runtime_init_addr = bsp::memory::relocated_runtime_init_addr() as usize;
- cpu::branch_to_raw_addr(relocated_runtime_init_addr) - cpu::branch_to_raw_addr(relocated_runtime_init_addr)
-} -}

@ -3,37 +3,47 @@
* Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com> * Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
*/ */
/* 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 SECTIONS
{ {
/* Set current address to the value from which the RPi starts execution */ . = __rpi_load_addr;
. = 0x80000;
/***********************************************************************************************
* Code + RO Data + Global Offset Table
***********************************************************************************************/
__rx_start = .;
.text : .text :
{ {
*(.text._start) *(.text*) KEEP(*(.text._start))
} *(.text*)
} :segment_rx
.rodata : .rodata : ALIGN(8) { *(.rodata*) } :segment_rx
{ .got : ALIGN(8) { *(.got) } :segment_rx
*(.rodata*)
}
.data : /***********************************************************************************************
{ * Data + BSS
*(.data*) ***********************************************************************************************/
} .data : { *(.data*) } :segment_rw
/* Section is zeroed in u64 chunks, align start and end to 8 bytes */ /* Section is zeroed in u64 chunks, align start and end to 8 bytes */
.bss ALIGN(8): .bss : ALIGN(8)
{ {
__bss_start = .; __bss_start = .;
*(.bss*); *(.bss*);
. = ALIGN(8); . = ALIGN(8);
/* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */
. += 8;
__bss_end_inclusive = . - 8; __bss_end_inclusive = . - 8;
} } :NONE
/DISCARD/ : { *(.comment*) }
} }

@ -12,6 +12,8 @@ use core::{cell::UnsafeCell, ops::RangeInclusive};
// Symbols from the linker script. // Symbols from the linker script.
extern "Rust" { extern "Rust" {
static __rx_start: UnsafeCell<()>;
static __bss_start: UnsafeCell<u64>; static __bss_start: UnsafeCell<u64>;
static __bss_end_inclusive: UnsafeCell<u64>; static __bss_end_inclusive: UnsafeCell<u64>;
} }
@ -20,10 +22,9 @@ extern "Rust" {
// Public Definitions // Public Definitions
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// The board's memory map. /// The board's physical memory map.
#[rustfmt::skip] #[rustfmt::skip]
pub(super) mod map { pub(super) mod map {
pub const BOOT_CORE_STACK_END: usize = 0x8_0000;
pub const GPIO_OFFSET: usize = 0x0020_0000; pub const GPIO_OFFSET: usize = 0x0020_0000;
pub const UART_OFFSET: usize = 0x0020_1000; 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 // Public Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -56,7 +71,7 @@ pub(super) mod map {
/// Exclusive end address of the boot core's stack. /// Exclusive end address of the boot core's stack.
#[inline(always)] #[inline(always)]
pub fn boot_core_stack_end() -> usize { pub fn boot_core_stack_end() -> usize {
map::BOOT_CORE_STACK_END rx_start()
} }
/// Return the inclusive range spanning the .bss section. /// Return the inclusive range spanning the .bss section.

@ -147,6 +147,7 @@ objdump: $(KERNEL_ELF)
@$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \
--section .text \ --section .text \
--section .rodata \ --section .rodata \
--section .got \
$(KERNEL_ELF) | rustfilt $(KERNEL_ELF) | rustfilt
nm: $(KERNEL_ELF) nm: $(KERNEL_ELF)

@ -3,37 +3,47 @@
* Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com> * Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
*/ */
/* 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 SECTIONS
{ {
/* Set current address to the value from which the RPi starts execution */ . = __rpi_load_addr;
. = 0x80000;
/***********************************************************************************************
* Code + RO Data + Global Offset Table
***********************************************************************************************/
__rx_start = .;
.text : .text :
{ {
*(.text._start) *(.text*) KEEP(*(.text._start))
} *(.text*)
} :segment_rx
.rodata : .rodata : ALIGN(8) { *(.rodata*) } :segment_rx
{ .got : ALIGN(8) { *(.got) } :segment_rx
*(.rodata*)
}
.data : /***********************************************************************************************
{ * Data + BSS
*(.data*) ***********************************************************************************************/
} .data : { *(.data*) } :segment_rw
/* Section is zeroed in u64 chunks, align start and end to 8 bytes */ /* Section is zeroed in u64 chunks, align start and end to 8 bytes */
.bss ALIGN(8): .bss : ALIGN(8)
{ {
__bss_start = .; __bss_start = .;
*(.bss*); *(.bss*);
. = ALIGN(8); . = ALIGN(8);
/* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */
. += 8;
__bss_end_inclusive = . - 8; __bss_end_inclusive = . - 8;
} } :NONE
/DISCARD/ : { *(.comment*) }
} }

@ -12,6 +12,8 @@ use core::{cell::UnsafeCell, ops::RangeInclusive};
// Symbols from the linker script. // Symbols from the linker script.
extern "Rust" { extern "Rust" {
static __rx_start: UnsafeCell<()>;
static __bss_start: UnsafeCell<u64>; static __bss_start: UnsafeCell<u64>;
static __bss_end_inclusive: UnsafeCell<u64>; static __bss_end_inclusive: UnsafeCell<u64>;
} }
@ -20,10 +22,9 @@ extern "Rust" {
// Public Definitions // Public Definitions
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// The board's memory map. /// The board's physical memory map.
#[rustfmt::skip] #[rustfmt::skip]
pub(super) mod map { pub(super) mod map {
pub const BOOT_CORE_STACK_END: usize = 0x8_0000;
pub const GPIO_OFFSET: usize = 0x0020_0000; pub const GPIO_OFFSET: usize = 0x0020_0000;
pub const UART_OFFSET: usize = 0x0020_1000; 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 // Public Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -56,7 +71,7 @@ pub(super) mod map {
/// Exclusive end address of the boot core's stack. /// Exclusive end address of the boot core's stack.
#[inline(always)] #[inline(always)]
pub fn boot_core_stack_end() -> usize { pub fn boot_core_stack_end() -> usize {
map::BOOT_CORE_STACK_END rx_start()
} }
/// Return the inclusive range spanning the .bss section. /// Return the inclusive range spanning the .bss section.

@ -147,6 +147,7 @@ objdump: $(KERNEL_ELF)
@$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \
--section .text \ --section .text \
--section .rodata \ --section .rodata \
--section .got \
$(KERNEL_ELF) | rustfilt $(KERNEL_ELF) | rustfilt
nm: $(KERNEL_ELF) nm: $(KERNEL_ELF)

@ -136,7 +136,7 @@ Finally, we set the stack pointer for `SP_EL1` and call `ERET`:
```rust ```rust
// Set up SP_EL1 (stack pointer), which will be used by EL1 once we "return" to it. // 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. // Use `eret` to "return" to EL1. This results in execution of runtime_init() in EL1.
asm::eret() asm::eret()

@ -3,37 +3,47 @@
* Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com> * Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
*/ */
/* 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 SECTIONS
{ {
/* Set current address to the value from which the RPi starts execution */ . = __rpi_load_addr;
. = 0x80000;
/***********************************************************************************************
* Code + RO Data + Global Offset Table
***********************************************************************************************/
__rx_start = .;
.text : .text :
{ {
*(.text._start) *(.text*) KEEP(*(.text._start))
} *(.text*)
} :segment_rx
.rodata : .rodata : ALIGN(8) { *(.rodata*) } :segment_rx
{ .got : ALIGN(8) { *(.got) } :segment_rx
*(.rodata*)
}
.data : /***********************************************************************************************
{ * Data + BSS
*(.data*) ***********************************************************************************************/
} .data : { *(.data*) } :segment_rw
/* Section is zeroed in u64 chunks, align start and end to 8 bytes */ /* Section is zeroed in u64 chunks, align start and end to 8 bytes */
.bss ALIGN(8): .bss : ALIGN(8)
{ {
__bss_start = .; __bss_start = .;
*(.bss*); *(.bss*);
. = ALIGN(8); . = ALIGN(8);
/* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */
. += 8;
__bss_end_inclusive = . - 8; __bss_end_inclusive = . - 8;
} } :NONE
/DISCARD/ : { *(.comment*) }
} }

@ -12,6 +12,8 @@ use core::{cell::UnsafeCell, ops::RangeInclusive};
// Symbols from the linker script. // Symbols from the linker script.
extern "Rust" { extern "Rust" {
static __rx_start: UnsafeCell<()>;
static __bss_start: UnsafeCell<u64>; static __bss_start: UnsafeCell<u64>;
static __bss_end_inclusive: UnsafeCell<u64>; static __bss_end_inclusive: UnsafeCell<u64>;
} }
@ -20,10 +22,9 @@ extern "Rust" {
// Public Definitions // Public Definitions
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// The board's memory map. /// The board's physical memory map.
#[rustfmt::skip] #[rustfmt::skip]
pub(super) mod map { pub(super) mod map {
pub const BOOT_CORE_STACK_END: usize = 0x8_0000;
pub const GPIO_OFFSET: usize = 0x0020_0000; pub const GPIO_OFFSET: usize = 0x0020_0000;
pub const UART_OFFSET: usize = 0x0020_1000; 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 // Public Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -56,7 +71,7 @@ pub(super) mod map {
/// Exclusive end address of the boot core's stack. /// Exclusive end address of the boot core's stack.
#[inline(always)] #[inline(always)]
pub fn boot_core_stack_end() -> usize { pub fn boot_core_stack_end() -> usize {
map::BOOT_CORE_STACK_END rx_start()
} }
/// Return the inclusive range spanning the .bss section. /// Return the inclusive range spanning the .bss section.

@ -147,6 +147,7 @@ objdump: $(KERNEL_ELF)
@$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \
--section .text \ --section .text \
--section .rodata \ --section .rodata \
--section .got \
$(KERNEL_ELF) | rustfilt $(KERNEL_ELF) | rustfilt
nm: $(KERNEL_ELF) nm: $(KERNEL_ELF)

@ -224,10 +224,16 @@ enables caching for data and instructions.
### `link.ld` ### `link.ld`
We need to align the `ro` section to `64 KiB` so that it doesn't overlap with the next section that 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. This blows up the binary in size, but is a small price to pay needs read/write attributes instead of read/execute attributes:
considering that it reduces the amount of static paging entries significantly, when compared to the
classical `4 KiB` granule. ```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 ## 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 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 --- 10_privilege_level/src/bsp/raspberrypi/link.ld
+++ 11_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/link.ld +++ 11_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/link.ld
@@ -8,6 +8,7 @@ @@ -31,6 +31,9 @@
/* Set current address to the value from which the RPi starts execution */ .rodata : ALIGN(8) { *(.rodata*) } :segment_rx
. = 0x80000; .got : ALIGN(8) { *(.got) } :segment_rx
+ __ro_start = .;
.text :
{
*(.text._start) *(.text*)
@@ -17,6 +18,8 @@
{
*(.rodata*)
}
+ . = ALIGN(65536); /* Fill up to 64 KiB */
+ __ro_end = .;
.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 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 --- 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 { + TranslationDescriptor {
+ name: "Kernel code and RO data", + name: "Kernel code and RO data",
+ virtual_range: ro_range_inclusive, + virtual_range: rx_range_inclusive,
+ physical_range_translation: Translation::Identity, + physical_range_translation: Translation::Identity,
+ attribute_fields: AttributeFields { + attribute_fields: AttributeFields {
+ mem_attributes: MemAttributes::CacheableDRAM, + 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 +// Private Code
+//-------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------
+ +
+fn ro_range_inclusive() -> RangeInclusive<usize> { +fn rx_range_inclusive() -> RangeInclusive<usize> {
+ // Notice the subtraction to turn the exclusive end into an inclusive end. + // Notice the subtraction to turn the exclusive end into an inclusive end.
+ #[allow(clippy::range_minus_one)] + #[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<usize> { +fn remapped_mmio_range_inclusive() -> RangeInclusive<usize> {
@ -928,17 +927,16 @@ diff -uNr 10_privilege_level/src/bsp/raspberrypi/memory.rs 11_virtual_mem_part1_
use core::{cell::UnsafeCell, ops::RangeInclusive}; use core::{cell::UnsafeCell, ops::RangeInclusive};
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@@ -14,6 +16,8 @@ @@ -13,6 +15,7 @@
// Symbols from the linker script.
extern "Rust" { extern "Rust" {
static __rx_start: UnsafeCell<()>;
+ static __rx_end_exclusive: UnsafeCell<()>;
static __bss_start: UnsafeCell<u64>; static __bss_start: UnsafeCell<u64>;
static __bss_end_inclusive: UnsafeCell<u64>; static __bss_end_inclusive: UnsafeCell<u64>;
+ static __ro_start: UnsafeCell<()>; @@ -25,6 +28,20 @@
+ static __ro_end: UnsafeCell<()>; /// The board's physical memory map.
}
//--------------------------------------------------------------------------------------------------
@@ -23,6 +27,21 @@
/// The board's memory map.
#[rustfmt::skip] #[rustfmt::skip]
pub(super) mod map { pub(super) mod map {
+ /// The inclusive end address of the memory 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 + /// 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. + /// 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 END_INCLUSIVE: usize = 0xFFFF_FFFF;
+
pub const BOOT_CORE_STACK_END: usize = 0x8_0000;
pub const GPIO_OFFSET: usize = 0x0020_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 START: usize = 0x3F00_0000;
pub const GPIO_START: usize = START + GPIO_OFFSET; pub const GPIO_START: usize = START + GPIO_OFFSET;
pub const PL011_UART_START: usize = START + UART_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. /// Physical devices.
@@ -46,10 +66,35 @@ @@ -47,6 +65,7 @@
pub const START: usize = 0xFE00_0000; pub const START: usize = 0xFE00_0000;
pub const GPIO_START: usize = START + GPIO_OFFSET; pub const GPIO_START: usize = START + GPIO_OFFSET;
pub const PL011_UART_START: usize = START + UART_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_
} }
} }
//-------------------------------------------------------------------------------------------------- @@ -64,6 +83,16 @@
+// Private Code unsafe { __rx_start.get() as usize }
+//-------------------------------------------------------------------------------------------------- }
+
+/// Start address of the Read-Only (RO) range. +/// 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_start() -> usize {
+ unsafe { __ro_start.get() as usize }
+}
+
+/// Size of the Read-Only (RO) range of the kernel binary.
+/// +///
+/// # Safety +/// # Safety
+/// +///
+/// - Value is provided by the linker script and must be trusted as-is. +/// - Value is provided by the linker script and must be trusted as-is.
+#[inline(always)] +#[inline(always)]
+fn ro_end() -> usize { +fn rx_end_exclusive() -> usize {
+ unsafe { __ro_end.get() as usize } + unsafe { __rx_end_exclusive.get() as usize }
+} +}
+ +
+//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Public Code // Public Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
diff -uNr 10_privilege_level/src/bsp.rs 11_virtual_mem_part1_identity_mapping/src/bsp.rs diff -uNr 10_privilege_level/src/bsp.rs 11_virtual_mem_part1_identity_mapping/src/bsp.rs
--- 10_privilege_level/src/bsp.rs --- 10_privilege_level/src/bsp.rs
+++ 11_virtual_mem_part1_identity_mapping/src/bsp.rs +++ 11_virtual_mem_part1_identity_mapping/src/bsp.rs

@ -3,40 +3,50 @@
* Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com> * Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
*/ */
/* 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 SECTIONS
{ {
/* Set current address to the value from which the RPi starts execution */ . = __rpi_load_addr;
. = 0x80000;
__ro_start = .; /***********************************************************************************************
* Code + RO Data + Global Offset Table
***********************************************************************************************/
__rx_start = .;
.text : .text :
{ {
*(.text._start) *(.text*) KEEP(*(.text._start))
} *(.text*)
} :segment_rx
.rodata : .rodata : ALIGN(8) { *(.rodata*) } :segment_rx
{ .got : ALIGN(8) { *(.got) } :segment_rx
*(.rodata*)
}
. = ALIGN(65536); /* Fill up to 64 KiB */
__ro_end = .;
.data : . = ALIGN(64K); /* Align to page boundary */
{ __rx_end_exclusive = .;
*(.data*)
} /***********************************************************************************************
* Data + BSS
***********************************************************************************************/
.data : { *(.data*) } :segment_rw
/* Section is zeroed in u64 chunks, align start and end to 8 bytes */ /* Section is zeroed in u64 chunks, align start and end to 8 bytes */
.bss ALIGN(8): .bss : ALIGN(8)
{ {
__bss_start = .; __bss_start = .;
*(.bss*); *(.bss*);
. = ALIGN(8); . = ALIGN(8);
/* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */
. += 8;
__bss_end_inclusive = . - 8; __bss_end_inclusive = . - 8;
} } :NONE
/DISCARD/ : { *(.comment*) }
} }

@ -14,17 +14,18 @@ use core::{cell::UnsafeCell, ops::RangeInclusive};
// Symbols from the linker script. // Symbols from the linker script.
extern "Rust" { extern "Rust" {
static __rx_start: UnsafeCell<()>;
static __rx_end_exclusive: UnsafeCell<()>;
static __bss_start: UnsafeCell<u64>; static __bss_start: UnsafeCell<u64>;
static __bss_end_inclusive: UnsafeCell<u64>; static __bss_end_inclusive: UnsafeCell<u64>;
static __ro_start: UnsafeCell<()>;
static __ro_end: UnsafeCell<()>;
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Public Definitions // Public Definitions
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// The board's memory map. /// The board's physical memory map.
#[rustfmt::skip] #[rustfmt::skip]
pub(super) mod map { pub(super) mod map {
/// The inclusive end address of the memory 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. /// 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 END_INCLUSIVE: usize = 0xFFFF_FFFF;
pub const BOOT_CORE_STACK_END: usize = 0x8_0000;
pub const GPIO_OFFSET: usize = 0x0020_0000; pub const GPIO_OFFSET: usize = 0x0020_0000;
pub const UART_OFFSET: usize = 0x0020_1000; pub const UART_OFFSET: usize = 0x0020_1000;
@ -74,24 +73,24 @@ pub(super) mod map {
// Private Code // Private Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// Start address of the Read-Only (RO) range. /// Start address of the Read+Execute (RX) range.
/// ///
/// # Safety /// # Safety
/// ///
/// - Value is provided by the linker script and must be trusted as-is. /// - Value is provided by the linker script and must be trusted as-is.
#[inline(always)] #[inline(always)]
fn ro_start() -> usize { fn rx_start() -> usize {
unsafe { __ro_start.get() as 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 /// # Safety
/// ///
/// - Value is provided by the linker script and must be trusted as-is. /// - Value is provided by the linker script and must be trusted as-is.
#[inline(always)] #[inline(always)]
fn ro_end() -> usize { fn rx_end_exclusive() -> usize {
unsafe { __ro_end.get() as 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. /// Exclusive end address of the boot core's stack.
#[inline(always)] #[inline(always)]
pub fn boot_core_stack_end() -> usize { pub fn boot_core_stack_end() -> usize {
map::BOOT_CORE_STACK_END rx_start()
} }
/// Return the inclusive range spanning the .bss section. /// Return the inclusive range spanning the .bss section.

@ -26,7 +26,7 @@ pub static LAYOUT: KernelVirtualLayout<NUM_MEM_RANGES> = KernelVirtualLayout::ne
[ [
TranslationDescriptor { TranslationDescriptor {
name: "Kernel code and RO data", name: "Kernel code and RO data",
virtual_range: ro_range_inclusive, virtual_range: rx_range_inclusive,
physical_range_translation: Translation::Identity, physical_range_translation: Translation::Identity,
attribute_fields: AttributeFields { attribute_fields: AttributeFields {
mem_attributes: MemAttributes::CacheableDRAM, mem_attributes: MemAttributes::CacheableDRAM,
@ -61,10 +61,10 @@ pub static LAYOUT: KernelVirtualLayout<NUM_MEM_RANGES> = KernelVirtualLayout::ne
// Private Code // Private Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
fn ro_range_inclusive() -> RangeInclusive<usize> { fn rx_range_inclusive() -> RangeInclusive<usize> {
// Notice the subtraction to turn the exclusive end into an inclusive end. // Notice the subtraction to turn the exclusive end into an inclusive end.
#[allow(clippy::range_minus_one)] #[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<usize> { fn remapped_mmio_range_inclusive() -> RangeInclusive<usize> {

@ -147,6 +147,7 @@ objdump: $(KERNEL_ELF)
@$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \
--section .text \ --section .text \
--section .rodata \ --section .rodata \
--section .got \
$(KERNEL_ELF) | rustfilt $(KERNEL_ELF) | rustfilt
nm: $(KERNEL_ELF) nm: $(KERNEL_ELF)

@ -238,7 +238,7 @@ because `Rust` has no stable convention ([yet](https://github.com/rust-lang/rfcs
Next, we craft the exception vector table: Next, we craft the exception vector table:
```asm ```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 by 2^11 bytes, as demanded by ARMv8-A. Same as ALIGN(2048) in an ld script.
.align 11 .align 11
@ -324,7 +324,7 @@ The actual handlers referenced from the assembly can now branch to it for the ti
```rust ```rust
#[no_mangle] #[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); 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 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 --- 11_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs
+++ 12_exceptions_part1_groundwork/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 //! crate::exception::arch_exception
@ -541,18 +541,18 @@ diff -uNr 11_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs 1
+//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------
+ +
+#[no_mangle] +#[no_mangle]
+unsafe extern "C" fn current_el0_synchronous(e: &mut ExceptionContext) { +unsafe extern "C" fn current_el0_synchronous(_e: &mut ExceptionContext) {
+ default_exception_handler(e); + panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.")
+} +}
+ +
+#[no_mangle] +#[no_mangle]
+unsafe extern "C" fn current_el0_irq(e: &mut ExceptionContext) { +unsafe extern "C" fn current_el0_irq(_e: &mut ExceptionContext) {
+ default_exception_handler(e); + panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.")
+} +}
+ +
+#[no_mangle] +#[no_mangle]
+unsafe extern "C" fn current_el0_serror(e: &mut ExceptionContext) { +unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) {
+ default_exception_handler(e); + 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)?; + writeln!(f, " - {}", ec_translation)?;
+ +
+ // Raw print of instruction specific syndrome. + // 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))
+
+ Ok(())
+ } + }
+} +}
+ +
@ -681,9 +679,7 @@ diff -uNr 11_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs 1
+ +
+ write!(f, " Illegal Execution State (IL): {}", + write!(f, " Illegal Execution State (IL): {}",
+ to_flag_str(self.0.is_set(SPSR_EL1::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() { + for (i, reg) in self.gpr.iter().enumerate() {
+ write!(f, " x{: <2}: {: >#018x}{}", i, reg, alternating(i))?; + write!(f, " x{: <2}: {: >#018x}{}", i, reg, alternating(i))?;
+ } + }
+ write!(f, " lr : {:#018x}", self.lr)?; + write!(f, " lr : {:#018x}", self.lr)
+
+ Ok(())
+ } + }
+} +}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Public Code // Public Code
@@ -28,3 +251,23 @@ @@ -28,3 +245,23 @@
_ => (PrivilegeLevel::Unknown, "Unknown"), _ => (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. +// 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 by 2^11 bytes, as demanded by ARMv8-A. Same as ALIGN(2048) in an ld script.
+.align 11 +.align 11
@ -880,22 +874,6 @@ diff -uNr 11_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.S 12
+ +
+ eret + 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 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 --- 11_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/memory/mmu.rs
+++ 12_exceptions_part1_groundwork/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, virtual_range: mmio_range_inclusive,
physical_range_translation: Translation::Identity, physical_range_translation: Translation::Identity,
@@ -67,11 +57,6 @@ @@ -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<usize> { -fn remapped_mmio_range_inclusive() -> RangeInclusive<usize> {

@ -50,7 +50,7 @@
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// The exception vector table. // 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 by 2^11 bytes, as demanded by ARMv8-A. Same as ALIGN(2048) in an ld script.
.align 11 .align 11

@ -67,18 +67,18 @@ fn default_exception_handler(e: &ExceptionContext) {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#[no_mangle] #[no_mangle]
unsafe extern "C" fn current_el0_synchronous(e: &mut ExceptionContext) { unsafe extern "C" fn current_el0_synchronous(_e: &mut ExceptionContext) {
default_exception_handler(e); panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.")
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn current_el0_irq(e: &mut ExceptionContext) { unsafe extern "C" fn current_el0_irq(_e: &mut ExceptionContext) {
default_exception_handler(e); panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.")
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn current_el0_serror(e: &mut ExceptionContext) { unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) {
default_exception_handler(e); 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)?; writeln!(f, " - {}", ec_translation)?;
// Raw print of instruction specific syndrome. // 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))
Ok(())
} }
} }
@ -207,9 +205,7 @@ impl fmt::Display for SpsrEL1 {
write!(f, " Illegal Execution State (IL): {}", write!(f, " Illegal Execution State (IL): {}",
to_flag_str(self.0.is_set(SPSR_EL1::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() { for (i, reg) in self.gpr.iter().enumerate() {
write!(f, " x{: <2}: {: >#018x}{}", i, reg, alternating(i))?; write!(f, " x{: <2}: {: >#018x}{}", i, reg, alternating(i))?;
} }
write!(f, " lr : {:#018x}", self.lr)?; write!(f, " lr : {:#018x}", self.lr)
Ok(())
} }
} }

@ -3,45 +3,50 @@
* Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com> * Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
*/ */
/* 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 SECTIONS
{ {
/* Set current address to the value from which the RPi starts execution */ . = __rpi_load_addr;
. = 0x80000;
__ro_start = .; /***********************************************************************************************
* Code + RO Data + Global Offset Table
***********************************************************************************************/
__rx_start = .;
.text : .text :
{ {
*(.text._start) *(.text*) KEEP(*(.text._start))
} *(.text*)
} :segment_rx
.exception_vectors : .rodata : ALIGN(8) { *(.rodata*) } :segment_rx
{ .got : ALIGN(8) { *(.got) } :segment_rx
*(.exception_vectors*)
}
.rodata : . = ALIGN(64K); /* Align to page boundary */
{ __rx_end_exclusive = .;
*(.rodata*)
}
. = ALIGN(65536); /* Fill up to 64 KiB */
__ro_end = .;
.data : /***********************************************************************************************
{ * Data + BSS
*(.data*) ***********************************************************************************************/
} .data : { *(.data*) } :segment_rw
/* Section is zeroed in u64 chunks, align start and end to 8 bytes */ /* Section is zeroed in u64 chunks, align start and end to 8 bytes */
.bss ALIGN(8): .bss : ALIGN(8)
{ {
__bss_start = .; __bss_start = .;
*(.bss*); *(.bss*);
. = ALIGN(8); . = ALIGN(8);
/* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */
. += 8;
__bss_end_inclusive = . - 8; __bss_end_inclusive = . - 8;
} } :NONE
/DISCARD/ : { *(.comment*) }
} }

@ -14,17 +14,18 @@ use core::{cell::UnsafeCell, ops::RangeInclusive};
// Symbols from the linker script. // Symbols from the linker script.
extern "Rust" { extern "Rust" {
static __rx_start: UnsafeCell<()>;
static __rx_end_exclusive: UnsafeCell<()>;
static __bss_start: UnsafeCell<u64>; static __bss_start: UnsafeCell<u64>;
static __bss_end_inclusive: UnsafeCell<u64>; static __bss_end_inclusive: UnsafeCell<u64>;
static __ro_start: UnsafeCell<()>;
static __ro_end: UnsafeCell<()>;
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Public Definitions // Public Definitions
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// The board's memory map. /// The board's physical memory map.
#[rustfmt::skip] #[rustfmt::skip]
pub(super) mod map { pub(super) mod map {
/// The inclusive end address of the memory 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. /// 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 END_INCLUSIVE: usize = 0xFFFF_FFFF;
pub const BOOT_CORE_STACK_END: usize = 0x8_0000;
pub const GPIO_OFFSET: usize = 0x0020_0000; pub const GPIO_OFFSET: usize = 0x0020_0000;
pub const UART_OFFSET: usize = 0x0020_1000; pub const UART_OFFSET: usize = 0x0020_1000;
@ -74,24 +73,24 @@ pub(super) mod map {
// Private Code // Private Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// Start address of the Read-Only (RO) range. /// Start address of the Read+Execute (RX) range.
/// ///
/// # Safety /// # Safety
/// ///
/// - Value is provided by the linker script and must be trusted as-is. /// - Value is provided by the linker script and must be trusted as-is.
#[inline(always)] #[inline(always)]
fn ro_start() -> usize { fn rx_start() -> usize {
unsafe { __ro_start.get() as 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 /// # Safety
/// ///
/// - Value is provided by the linker script and must be trusted as-is. /// - Value is provided by the linker script and must be trusted as-is.
#[inline(always)] #[inline(always)]
fn ro_end() -> usize { fn rx_end_exclusive() -> usize {
unsafe { __ro_end.get() as 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. /// Exclusive end address of the boot core's stack.
#[inline(always)] #[inline(always)]
pub fn boot_core_stack_end() -> usize { pub fn boot_core_stack_end() -> usize {
map::BOOT_CORE_STACK_END rx_start()
} }
/// Return the inclusive range spanning the .bss section. /// Return the inclusive range spanning the .bss section.

@ -26,7 +26,7 @@ pub static LAYOUT: KernelVirtualLayout<NUM_MEM_RANGES> = KernelVirtualLayout::ne
[ [
TranslationDescriptor { TranslationDescriptor {
name: "Kernel code and RO data", name: "Kernel code and RO data",
virtual_range: ro_range_inclusive, virtual_range: rx_range_inclusive,
physical_range_translation: Translation::Identity, physical_range_translation: Translation::Identity,
attribute_fields: AttributeFields { attribute_fields: AttributeFields {
mem_attributes: MemAttributes::CacheableDRAM, mem_attributes: MemAttributes::CacheableDRAM,
@ -51,10 +51,10 @@ pub static LAYOUT: KernelVirtualLayout<NUM_MEM_RANGES> = KernelVirtualLayout::ne
// Private Code // Private Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
fn ro_range_inclusive() -> RangeInclusive<usize> { fn rx_range_inclusive() -> RangeInclusive<usize> {
// Notice the subtraction to turn the exclusive end into an inclusive end. // Notice the subtraction to turn the exclusive end into an inclusive end.
#[allow(clippy::range_minus_one)] #[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<usize> { fn mmio_range_inclusive() -> RangeInclusive<usize> {

@ -179,6 +179,7 @@ objdump: $(KERNEL_ELF)
@$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \
--section .text \ --section .text \
--section .rodata \ --section .rodata \
--section .got \
$(KERNEL_ELF) | rustfilt $(KERNEL_ELF) | rustfilt
nm: $(KERNEL_ELF) nm: $(KERNEL_ELF)

@ -50,7 +50,7 @@
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// The exception vector table. // 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 by 2^11 bytes, as demanded by ARMv8-A. Same as ALIGN(2048) in an ld script.
.align 11 .align 11

@ -67,18 +67,18 @@ fn default_exception_handler(e: &ExceptionContext) {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#[no_mangle] #[no_mangle]
unsafe extern "C" fn current_el0_synchronous(e: &mut ExceptionContext) { unsafe extern "C" fn current_el0_synchronous(_e: &mut ExceptionContext) {
default_exception_handler(e); panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.")
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn current_el0_irq(e: &mut ExceptionContext) { unsafe extern "C" fn current_el0_irq(_e: &mut ExceptionContext) {
default_exception_handler(e); panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.")
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn current_el0_serror(e: &mut ExceptionContext) { unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) {
default_exception_handler(e); 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)?; writeln!(f, " - {}", ec_translation)?;
// Raw print of instruction specific syndrome. // 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))
Ok(())
} }
} }
@ -197,9 +195,7 @@ impl fmt::Display for SpsrEL1 {
write!(f, " Illegal Execution State (IL): {}", write!(f, " Illegal Execution State (IL): {}",
to_flag_str(self.0.is_set(SPSR_EL1::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() { for (i, reg) in self.gpr.iter().enumerate() {
write!(f, " x{: <2}: {: >#018x}{}", i, reg, alternating(i))?; write!(f, " x{: <2}: {: >#018x}{}", i, reg, alternating(i))?;
} }
write!(f, " lr : {:#018x}", self.lr)?; write!(f, " lr : {:#018x}", self.lr)
Ok(())
} }
} }

@ -3,45 +3,50 @@
* Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com> * Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
*/ */
/* 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 SECTIONS
{ {
/* Set current address to the value from which the RPi starts execution */ . = __rpi_load_addr;
. = 0x80000;
__ro_start = .; /***********************************************************************************************
* Code + RO Data + Global Offset Table
***********************************************************************************************/
__rx_start = .;
.text : .text :
{ {
*(.text._start) *(.text*) KEEP(*(.text._start))
} *(.text*)
} :segment_rx
.exception_vectors : .rodata : ALIGN(8) { *(.rodata*) } :segment_rx
{ .got : ALIGN(8) { *(.got) } :segment_rx
*(.exception_vectors*)
}
.rodata : . = ALIGN(64K); /* Align to page boundary */
{ __rx_end_exclusive = .;
*(.rodata*)
}
. = ALIGN(65536); /* Fill up to 64 KiB */
__ro_end = .;
.data : /***********************************************************************************************
{ * Data + BSS
*(.data*) ***********************************************************************************************/
} .data : { *(.data*) } :segment_rw
/* Section is zeroed in u64 chunks, align start and end to 8 bytes */ /* Section is zeroed in u64 chunks, align start and end to 8 bytes */
.bss ALIGN(8): .bss : ALIGN(8)
{ {
__bss_start = .; __bss_start = .;
*(.bss*); *(.bss*);
. = ALIGN(8); . = ALIGN(8);
/* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */
. += 8;
__bss_end_inclusive = . - 8; __bss_end_inclusive = . - 8;
} } :NONE
/DISCARD/ : { *(.comment*) }
} }

@ -14,17 +14,18 @@ use core::{cell::UnsafeCell, ops::RangeInclusive};
// Symbols from the linker script. // Symbols from the linker script.
extern "Rust" { extern "Rust" {
static __rx_start: UnsafeCell<()>;
static __rx_end_exclusive: UnsafeCell<()>;
static __bss_start: UnsafeCell<u64>; static __bss_start: UnsafeCell<u64>;
static __bss_end_inclusive: UnsafeCell<u64>; static __bss_end_inclusive: UnsafeCell<u64>;
static __ro_start: UnsafeCell<()>;
static __ro_end: UnsafeCell<()>;
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Public Definitions // Public Definitions
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// The board's memory map. /// The board's physical memory map.
#[rustfmt::skip] #[rustfmt::skip]
pub(super) mod map { pub(super) mod map {
/// The inclusive end address of the memory 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. /// 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 END_INCLUSIVE: usize = 0xFFFF_FFFF;
pub const BOOT_CORE_STACK_END: usize = 0x8_0000;
pub const GPIO_OFFSET: usize = 0x0020_0000; pub const GPIO_OFFSET: usize = 0x0020_0000;
pub const UART_OFFSET: usize = 0x0020_1000; pub const UART_OFFSET: usize = 0x0020_1000;
@ -74,24 +73,24 @@ pub(super) mod map {
// Private Code // Private Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// Start address of the Read-Only (RO) range. /// Start address of the Read+Execute (RX) range.
/// ///
/// # Safety /// # Safety
/// ///
/// - Value is provided by the linker script and must be trusted as-is. /// - Value is provided by the linker script and must be trusted as-is.
#[inline(always)] #[inline(always)]
fn ro_start() -> usize { fn rx_start() -> usize {
unsafe { __ro_start.get() as 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 /// # Safety
/// ///
/// - Value is provided by the linker script and must be trusted as-is. /// - Value is provided by the linker script and must be trusted as-is.
#[inline(always)] #[inline(always)]
fn ro_end() -> usize { fn rx_end_exclusive() -> usize {
unsafe { __ro_end.get() as 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. /// Exclusive end address of the boot core's stack.
#[inline(always)] #[inline(always)]
pub fn boot_core_stack_end() -> usize { pub fn boot_core_stack_end() -> usize {
map::BOOT_CORE_STACK_END rx_start()
} }
/// Return the inclusive range spanning the .bss section. /// Return the inclusive range spanning the .bss section.

@ -26,7 +26,7 @@ pub static LAYOUT: KernelVirtualLayout<NUM_MEM_RANGES> = KernelVirtualLayout::ne
[ [
TranslationDescriptor { TranslationDescriptor {
name: "Kernel code and RO data", name: "Kernel code and RO data",
virtual_range: ro_range_inclusive, virtual_range: rx_range_inclusive,
physical_range_translation: Translation::Identity, physical_range_translation: Translation::Identity,
attribute_fields: AttributeFields { attribute_fields: AttributeFields {
mem_attributes: MemAttributes::CacheableDRAM, mem_attributes: MemAttributes::CacheableDRAM,
@ -51,10 +51,10 @@ pub static LAYOUT: KernelVirtualLayout<NUM_MEM_RANGES> = KernelVirtualLayout::ne
// Private Code // Private Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
fn ro_range_inclusive() -> RangeInclusive<usize> { fn rx_range_inclusive() -> RangeInclusive<usize> {
// Notice the subtraction to turn the exclusive end into an inclusive end. // Notice the subtraction to turn the exclusive end into an inclusive end.
#[allow(clippy::range_minus_one)] #[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<usize> { fn mmio_range_inclusive() -> RangeInclusive<usize> {

@ -179,6 +179,7 @@ objdump: $(KERNEL_ELF)
@$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \
--section .text \ --section .text \
--section .rodata \ --section .rodata \
--section .got \
$(KERNEL_ELF) | rustfilt $(KERNEL_ELF) | rustfilt
nm: $(KERNEL_ELF) nm: $(KERNEL_ELF)

@ -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 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 --- 13_integrated_testing/src/bsp/raspberrypi/memory.rs
+++ 14_exceptions_part2_peripheral_IRQs/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 { pub mod mmio {
use super::*; use super::*;
@ -2073,7 +2073,7 @@ diff -uNr 13_integrated_testing/src/bsp/raspberrypi/memory.rs 14_exceptions_part
} }
/// Physical devices. /// Physical devices.
@@ -66,6 +68,8 @@ @@ -65,6 +67,8 @@
pub const START: usize = 0xFE00_0000; pub const START: usize = 0xFE00_0000;
pub const GPIO_START: usize = START + GPIO_OFFSET; pub const GPIO_START: usize = START + GPIO_OFFSET;
pub const PL011_UART_START: usize = START + UART_OFFSET; pub const PL011_UART_START: usize = START + UART_OFFSET;

@ -50,7 +50,7 @@
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// The exception vector table. // 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 by 2^11 bytes, as demanded by ARMv8-A. Same as ALIGN(2048) in an ld script.
.align 11 .align 11

@ -68,18 +68,18 @@ fn default_exception_handler(e: &ExceptionContext) {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#[no_mangle] #[no_mangle]
unsafe extern "C" fn current_el0_synchronous(e: &mut ExceptionContext) { unsafe extern "C" fn current_el0_synchronous(_e: &mut ExceptionContext) {
default_exception_handler(e); panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.")
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn current_el0_irq(e: &mut ExceptionContext) { unsafe extern "C" fn current_el0_irq(_e: &mut ExceptionContext) {
default_exception_handler(e); panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.")
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn current_el0_serror(e: &mut ExceptionContext) { unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) {
default_exception_handler(e); 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)?; writeln!(f, " - {}", ec_translation)?;
// Raw print of instruction specific syndrome. // 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))
Ok(())
} }
} }
@ -201,9 +199,7 @@ impl fmt::Display for SpsrEL1 {
write!(f, " Illegal Execution State (IL): {}", write!(f, " Illegal Execution State (IL): {}",
to_flag_str(self.0.is_set(SPSR_EL1::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() { for (i, reg) in self.gpr.iter().enumerate() {
write!(f, " x{: <2}: {: >#018x}{}", i, reg, alternating(i))?; write!(f, " x{: <2}: {: >#018x}{}", i, reg, alternating(i))?;
} }
write!(f, " lr : {:#018x}", self.lr)?; write!(f, " lr : {:#018x}", self.lr)
Ok(())
} }
} }

@ -3,45 +3,50 @@
* Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com> * Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
*/ */
/* 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 SECTIONS
{ {
/* Set current address to the value from which the RPi starts execution */ . = __rpi_load_addr;
. = 0x80000;
__ro_start = .; /***********************************************************************************************
* Code + RO Data + Global Offset Table
***********************************************************************************************/
__rx_start = .;
.text : .text :
{ {
*(.text._start) *(.text*) KEEP(*(.text._start))
} *(.text*)
} :segment_rx
.exception_vectors : .rodata : ALIGN(8) { *(.rodata*) } :segment_rx
{ .got : ALIGN(8) { *(.got) } :segment_rx
*(.exception_vectors*)
}
.rodata : . = ALIGN(64K); /* Align to page boundary */
{ __rx_end_exclusive = .;
*(.rodata*)
}
. = ALIGN(65536); /* Fill up to 64 KiB */
__ro_end = .;
.data : /***********************************************************************************************
{ * Data + BSS
*(.data*) ***********************************************************************************************/
} .data : { *(.data*) } :segment_rw
/* Section is zeroed in u64 chunks, align start and end to 8 bytes */ /* Section is zeroed in u64 chunks, align start and end to 8 bytes */
.bss ALIGN(8): .bss : ALIGN(8)
{ {
__bss_start = .; __bss_start = .;
*(.bss*); *(.bss*);
. = ALIGN(8); . = ALIGN(8);
/* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */
. += 8;
__bss_end_inclusive = . - 8; __bss_end_inclusive = . - 8;
} } :NONE
/DISCARD/ : { *(.comment*) }
} }

@ -14,17 +14,18 @@ use core::{cell::UnsafeCell, ops::RangeInclusive};
// Symbols from the linker script. // Symbols from the linker script.
extern "Rust" { extern "Rust" {
static __rx_start: UnsafeCell<()>;
static __rx_end_exclusive: UnsafeCell<()>;
static __bss_start: UnsafeCell<u64>; static __bss_start: UnsafeCell<u64>;
static __bss_end_inclusive: UnsafeCell<u64>; static __bss_end_inclusive: UnsafeCell<u64>;
static __ro_start: UnsafeCell<()>;
static __ro_end: UnsafeCell<()>;
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Public Definitions // Public Definitions
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// The board's memory map. /// The board's physical memory map.
#[rustfmt::skip] #[rustfmt::skip]
pub(super) mod map { pub(super) mod map {
/// The inclusive end address of the memory 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. /// 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 END_INCLUSIVE: usize = 0xFFFF_FFFF;
pub const BOOT_CORE_STACK_END: usize = 0x8_0000;
pub const GPIO_OFFSET: usize = 0x0020_0000; pub const GPIO_OFFSET: usize = 0x0020_0000;
pub const UART_OFFSET: usize = 0x0020_1000; pub const UART_OFFSET: usize = 0x0020_1000;
@ -78,24 +77,24 @@ pub(super) mod map {
// Private Code // Private Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// Start address of the Read-Only (RO) range. /// Start address of the Read+Execute (RX) range.
/// ///
/// # Safety /// # Safety
/// ///
/// - Value is provided by the linker script and must be trusted as-is. /// - Value is provided by the linker script and must be trusted as-is.
#[inline(always)] #[inline(always)]
fn ro_start() -> usize { fn rx_start() -> usize {
unsafe { __ro_start.get() as 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 /// # Safety
/// ///
/// - Value is provided by the linker script and must be trusted as-is. /// - Value is provided by the linker script and must be trusted as-is.
#[inline(always)] #[inline(always)]
fn ro_end() -> usize { fn rx_end_exclusive() -> usize {
unsafe { __ro_end.get() as 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. /// Exclusive end address of the boot core's stack.
#[inline(always)] #[inline(always)]
pub fn boot_core_stack_end() -> usize { pub fn boot_core_stack_end() -> usize {
map::BOOT_CORE_STACK_END rx_start()
} }
/// Return the inclusive range spanning the .bss section. /// Return the inclusive range spanning the .bss section.

@ -26,7 +26,7 @@ pub static LAYOUT: KernelVirtualLayout<NUM_MEM_RANGES> = KernelVirtualLayout::ne
[ [
TranslationDescriptor { TranslationDescriptor {
name: "Kernel code and RO data", name: "Kernel code and RO data",
virtual_range: ro_range_inclusive, virtual_range: rx_range_inclusive,
physical_range_translation: Translation::Identity, physical_range_translation: Translation::Identity,
attribute_fields: AttributeFields { attribute_fields: AttributeFields {
mem_attributes: MemAttributes::CacheableDRAM, mem_attributes: MemAttributes::CacheableDRAM,
@ -51,10 +51,10 @@ pub static LAYOUT: KernelVirtualLayout<NUM_MEM_RANGES> = KernelVirtualLayout::ne
// Private Code // Private Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
fn ro_range_inclusive() -> RangeInclusive<usize> { fn rx_range_inclusive() -> RangeInclusive<usize> {
// Notice the subtraction to turn the exclusive end into an inclusive end. // Notice the subtraction to turn the exclusive end into an inclusive end.
#[allow(clippy::range_minus_one)] #[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<usize> { fn mmio_range_inclusive() -> RangeInclusive<usize> {

@ -179,6 +179,7 @@ objdump: $(KERNEL_ELF)
@$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \
--section .text \ --section .text \
--section .rodata \ --section .rodata \
--section .got \
$(KERNEL_ELF) | rustfilt $(KERNEL_ELF) | rustfilt
nm: $(KERNEL_ELF) nm: $(KERNEL_ELF)

@ -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 There's a couple of changes not covered in this tutorial text, but the reader should ideally skim
through them: 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 - [`src/memory/mmu/types.rs`](src/memory/mmu/types.rs) introduces a couple of supporting types, like
`Page<ATYPE>`. `Page<ATYPE>`.
- [`src/memory/mmu/mapping_record.rs`](src/memory/mmu/mapping_record.rs) provides the generic kernel - [`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 [MP] ⏩ Pushing 67 KiB =========================================🦀 100% 0 KiB/s Time: 00:00:00
[ML] Loaded! Executing the payload now [ML] Loaded! Executing the payload now
[ 0.786819] Booting on: Raspberry Pi 3 [ 0.789721] Booting on: Raspberry Pi 3
[ 0.787092] MMU online: [ 0.789994] MMU online:
[ 0.787384] ------------------------------------------------------------------------------------------------------------------------------------------- [ 0.790286] -------------------------------------------------------------------------------------------------------------------------------------------
[ 0.789128] Virtual Physical Size Attr Entity [ 0.792030] Virtual Physical Size Attr Entity
[ 0.790873] ------------------------------------------------------------------------------------------------------------------------------------------- [ 0.793774] -------------------------------------------------------------------------------------------------------------------------------------------
[ 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.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.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.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.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.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.797406] 0x0000_0001_f000_0000..0x0000_0001_f000_ffff --> 0x00_3f20_0000..0x00_3f20_ffff | 64 KiB | Dev RW XN | BCM GPIO [ 0.800307] 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.801759] | 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.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.802117] ------------------------------------------------------------------------------------------------------------------------------------------- [ 0.805020] -------------------------------------------------------------------------------------------------------------------------------------------
``` ```
Raspberry Pi 4: Raspberry Pi 4:
@ -344,19 +351,19 @@ Minipush 1.0
[MP] ⏩ Pushing 74 KiB =========================================🦀 100% 0 KiB/s Time: 00:00:00 [MP] ⏩ Pushing 74 KiB =========================================🦀 100% 0 KiB/s Time: 00:00:00
[ML] Loaded! Executing the payload now [ML] Loaded! Executing the payload now
[ 0.853908] Booting on: Raspberry Pi 4 [ 0.870371] Booting on: Raspberry Pi 4
[ 0.854007] MMU online: [ 0.870470] MMU online:
[ 0.854299] ------------------------------------------------------------------------------------------------------------------------------------------- [ 0.870763] -------------------------------------------------------------------------------------------------------------------------------------------
[ 0.856043] Virtual Physical Size Attr Entity [ 0.872507] Virtual Physical Size Attr Entity
[ 0.857788] ------------------------------------------------------------------------------------------------------------------------------------------- [ 0.874251] -------------------------------------------------------------------------------------------------------------------------------------------
[ 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.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.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.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.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.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.864321] 0x0000_0001_f000_0000..0x0000_0001_f000_ffff --> 0x00_fe20_0000..0x00_fe20_ffff | 64 KiB | Dev RW XN | BCM GPIO [ 0.880784] 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.882235] | 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.883752] 0x0000_0001_f001_0000..0x0000_0001_f001_ffff --> 0x00_ff84_0000..0x00_ff84_ffff | 64 KiB | Dev RW XN | GICD
[ 0.868697] | GICC [ 0.885160] | GICC
[ 0.870105] ------------------------------------------------------------------------------------------------------------------------------------------- [ 0.886569] -------------------------------------------------------------------------------------------------------------------------------------------
``` ```
## Diff to previous ## 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. // Use `eret` to "return" to EL1. This results in execution of runtime_init() in EL1.
asm::eret() 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 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 --- 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 +++ 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 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 --- 14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/link.ld
+++ 15_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/link.ld +++ 15_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/link.ld
@@ -42,6 +42,11 @@ @@ -37,6 +37,7 @@
. += 8; /***********************************************************************************************
* 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; __bss_end_inclusive = . - 8;
} } :NONE
+ . = ALIGN(65536); +
+ __data_end = .; + . = 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
/DISCARD/ : { *(.comment*) } + ***********************************************************************************************/
+ __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 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 --- 14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs
+++ 15_virtual_mem_part2_mmio_remap/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. //! 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 +/// 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`. +/// derive respective data structures and their sizes. For example, the `crate::memory::mmu::Page`.
+pub type KernelGranule = TranslationGranule<{ 64 * 1024 }>; +pub type KernelGranule = TranslationGranule<{ 64 * 1024 }>;
+
-const NUM_MEM_RANGES: usize = 2;
+/// The kernel's virtual address space defined by this BSP. +/// The kernel's virtual address space defined by this BSP.
+pub type KernelVirtAddrSpace = AddressSpace<{ 8 * 1024 * 1024 * 1024 }>; +pub type KernelVirtAddrSpace = AddressSpace<{ 8 * 1024 * 1024 * 1024 }>;
-/// The virtual memory layout. -const NUM_MEM_RANGES: usize = 2;
+//-------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------
+// Global instances +// Global instances
+//-------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------
+
-/// The virtual memory layout.
+/// The kernel translation tables. +/// The kernel translation tables.
/// ///
-/// The layout must contain only special ranges, aka anything that is _not_ normal cacheable DRAM. -/// 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 { - TranslationDescriptor {
- name: "Kernel code and RO data", - name: "Kernel code and RO data",
- virtual_range: ro_range_inclusive, - virtual_range: rx_range_inclusive,
- physical_range_translation: Translation::Identity, - physical_range_translation: Translation::Identity,
- attribute_fields: AttributeFields { - attribute_fields: AttributeFields {
- mem_attributes: MemAttributes::CacheableDRAM, - mem_attributes: MemAttributes::CacheableDRAM,
@ -1515,10 +1589,10 @@ diff -uNr 14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs
// Private Code // Private Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
-fn ro_range_inclusive() -> RangeInclusive<usize> { -fn rx_range_inclusive() -> RangeInclusive<usize> {
- // Notice the subtraction to turn the exclusive end into an inclusive end. - // Notice the subtraction to turn the exclusive end into an inclusive end.
- #[allow(clippy::range_minus_one)] - #[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. +/// Helper function for calculating the number of pages the given parameter spans.
+const fn size_to_num_pages(size: usize) -> usize { +const fn size_to_num_pages(size: usize) -> usize {
+ assert!(size > 0); + assert!(size > 0);
@ -1527,44 +1601,44 @@ diff -uNr 14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs
+ size >> KernelGranule::SHIFT + size >> KernelGranule::SHIFT
+} +}
+ +
+/// The boot core's stack. +/// The Read+Execute (RX) pages of the kernel binary.
+fn virt_stack_page_desc() -> PageSliceDescriptor<Virtual> { +fn virt_rx_page_desc() -> PageSliceDescriptor<Virtual> {
+ let num_pages = size_to_num_pages(super::boot_core_stack_size()); + 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. +/// The Read+Write (RW) pages of the kernel binary.
+fn virt_ro_page_desc() -> PageSliceDescriptor<Virtual> { +fn virt_rw_page_desc() -> PageSliceDescriptor<Virtual> {
+ let num_pages = size_to_num_pages(super::ro_size()); + 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. +/// The boot core's stack.
+fn virt_data_page_desc() -> PageSliceDescriptor<Virtual> { +fn virt_boot_core_stack_page_desc() -> PageSliceDescriptor<Virtual> {
+ let num_pages = size_to_num_pages(super::data_size()); + 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 binary is still identity mapped, so we don't need to convert in the following.
+ +
+/// The boot core's stack. +/// The Read+Execute (RX) pages of the kernel binary.
+fn phys_stack_page_desc() -> PageSliceDescriptor<Physical> { +fn phys_rx_page_desc() -> PageSliceDescriptor<Physical> {
+ virt_stack_page_desc().into() + virt_rx_page_desc().into()
+}
+
+/// The Read-Only (RO) pages of the kernel binary.
+fn phys_ro_page_desc() -> PageSliceDescriptor<Physical> {
+ virt_ro_page_desc().into()
} }
-fn mmio_range_inclusive() -> RangeInclusive<usize> { -fn mmio_range_inclusive() -> RangeInclusive<usize> {
- RangeInclusive::new(memory_map::mmio::START, memory_map::mmio::END_INCLUSIVE) - RangeInclusive::new(memory_map::mmio::START, memory_map::mmio::END_INCLUSIVE)
+/// The data pages of the kernel binary. +/// The Read+Write (RW) pages of the kernel binary.
+fn phys_data_page_desc() -> PageSliceDescriptor<Physical> { +fn phys_rw_page_desc() -> PageSliceDescriptor<Physical> {
+ virt_data_page_desc().into() + virt_rw_page_desc().into()
+}
+
+/// The boot core's stack.
+fn phys_boot_core_stack_page_desc() -> PageSliceDescriptor<Physical> {
+ 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 + &KERNEL_TABLES
+} +}
+ +
+/// The boot core's stack guard page.
+pub fn virt_boot_core_stack_guard_page_desc() -> PageSliceDescriptor<Virtual> {
+ 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. +/// Pointer to the last page of the physical address space.
+pub fn phys_addr_space_end_page() -> *const Page<Physical> { +pub fn phys_addr_space_end_page() -> *const Page<Physical> {
+ common::align_down( + 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. +/// - Any miscalculation or attribute error will likely be fatal. Needs careful manual checking.
+pub unsafe fn kernel_map_binary() -> Result<(), &'static str> { +pub unsafe fn kernel_map_binary() -> Result<(), &'static str> {
+ generic_mmu::kernel_map_pages_at( + generic_mmu::kernel_map_pages_at(
+ "Kernel boot-core stack", + "Kernel code and RO data",
+ &virt_stack_page_desc(), + &virt_rx_page_desc(),
+ &phys_stack_page_desc(), + &phys_rx_page_desc(),
+ &AttributeFields { + &AttributeFields {
+ mem_attributes: MemAttributes::CacheableDRAM, + mem_attributes: MemAttributes::CacheableDRAM,
+ acc_perms: AccessPermissions::ReadWrite, + acc_perms: AccessPermissions::ReadOnly,
+ execute_never: true, + execute_never: false,
+ }, + },
+ )?; + )?;
+ +
+ generic_mmu::kernel_map_pages_at( + generic_mmu::kernel_map_pages_at(
+ "Kernel code and RO data", + "Kernel data and bss",
+ &virt_ro_page_desc(), + &virt_rw_page_desc(),
+ &phys_ro_page_desc(), + &phys_rw_page_desc(),
+ &AttributeFields { + &AttributeFields {
+ mem_attributes: MemAttributes::CacheableDRAM, + mem_attributes: MemAttributes::CacheableDRAM,
+ acc_perms: AccessPermissions::ReadOnly, + acc_perms: AccessPermissions::ReadWrite,
+ execute_never: false, + execute_never: true,
+ }, + },
+ )?; + )?;
+ +
+ generic_mmu::kernel_map_pages_at( + generic_mmu::kernel_map_pages_at(
+ "Kernel data and bss", + "Kernel boot-core stack",
+ &virt_data_page_desc(), + &virt_boot_core_stack_page_desc(),
+ &phys_data_page_desc(), + &phys_boot_core_stack_page_desc(),
+ &AttributeFields { + &AttributeFields {
+ mem_attributes: MemAttributes::CacheableDRAM, + mem_attributes: MemAttributes::CacheableDRAM,
+ acc_perms: AccessPermissions::ReadWrite, + 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. /// Check alignment of the kernel's virtual memory layout sections.
#[kernel_test] #[kernel_test]
fn virt_mem_layout_sections_are_64KiB_aligned() { 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() { - for i in LAYOUT.inner().iter() {
- let start: usize = *(i.virtual_range)().start(); - let start: usize = *(i.virtual_range)().start();
- let end: usize = *(i.virtual_range)().end() + 1; - 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 start: usize = i().start_addr().into_usize();
+ let end: usize = i().end_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); assert!(end >= start);
} }
} }
@@ -97,18 +182,28 @@ @@ -97,18 +195,28 @@
/// Ensure the kernel's virtual memory layout is free of overlaps. /// Ensure the kernel's virtual memory layout is free of overlaps.
#[kernel_test] #[kernel_test]
fn virt_mem_layout_has_no_overlaps() { 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().start()));
- assert!(!second_range().contains(first_range().end())); - assert!(!second_range().contains(first_range().end()));
+ let layout = [ + let layout = [
+ virt_stack_page_desc(), + virt_rx_page_desc(),
+ virt_ro_page_desc(), + virt_rw_page_desc(),
+ virt_data_page_desc(), + virt_boot_core_stack_page_desc(),
+ ]; + ];
+ +
+ for (i, first_range) in layout.iter().enumerate() { + 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 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 --- 14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory.rs
+++ 15_virtual_mem_part2_mmio_remap/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 <andre.o.richter@gmail.com> // Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
//! BSP Memory Management. //! 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: +//! 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 | +//! | .text |
+//! | .exception_vectors |
+//! | .rodata | +//! | .rodata |
+//! | | +//! | .got |
+//! | RO_END_INCLUSIVE | 0x8_0000 + __ro_size - 1 +//! | | rx_end_inclusive
+//! +---------------------------------------------+ +//! +---------------------------------------------+
+//! | RO_END == DATA_START | 0x8_0000 + __ro_size +//! | | rw_start == ro_end
+//! | |
+//! | .data | +//! | .data |
+//! | .bss | +//! | .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; 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}; 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<u64>; static __bss_start: UnsafeCell<u64>;
static __bss_end_inclusive: UnsafeCell<u64>; static __bss_end_inclusive: UnsafeCell<u64>;
static __ro_start: UnsafeCell<()>; + static __rw_end_exclusive: UnsafeCell<()>;
- static __ro_end: UnsafeCell<()>; +
+ static __ro_size: UnsafeCell<()>; + static __boot_core_stack_start: UnsafeCell<()>;
+ static __data_size: 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 @@ -28,35 +67,26 @@
//-------------------------------------------------------------------------------------------------- /// The board's physical memory map.
-/// The board's memory map.
+/// The board's physical memory map.
#[rustfmt::skip] #[rustfmt::skip]
pub(super) mod map { pub(super) mod map {
- /// The inclusive end address of the memory 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 - /// 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. - /// 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 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 GPIO_OFFSET: usize = 0x0020_0000;
- pub const UART_OFFSET: usize = 0x0020_1000; - pub const UART_OFFSET: usize = 0x0020_1000;
+ pub const BOOT_CORE_STACK_SIZE: usize = 0x1_0000; + use super::*;
/// Physical devices. /// Physical devices.
#[cfg(feature = "bsp_rpi3")] #[cfg(feature = "bsp_rpi3")]
@ -1802,7 +1889,7 @@ diff -uNr 14_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory.rs 15_v
} }
/// Physical devices. /// Physical devices.
@@ -65,13 +89,22 @@ @@ -64,13 +94,22 @@
pub mod mmio { pub mod mmio {
use super::*; 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. /// - Value is provided by the linker script and must be trusted as-is.
#[inline(always)] #[inline(always)]
-fn ro_start() -> usize { -fn rx_start() -> usize {
- unsafe { __ro_start.get() as usize } - unsafe { __rx_start.get() as usize }
+fn virt_ro_start() -> Address<Virtual> { +fn virt_rx_start() -> Address<Virtual> {
+ Address::new(unsafe { __ro_start.get() as usize }) + Address::new(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.
@@ -94,8 +127,42 @@ +/// Size of the Read+Execute (RX) range.
///
/// # Safety
/// ///
/// - Value is provided by the linker script and must be trusted as-is. /// - Value is provided by the linker script and must be trusted as-is.
#[inline(always)] #[inline(always)]
-fn ro_end() -> usize { -fn rx_end_exclusive() -> usize {
- unsafe { __ro_end.get() as usize } - unsafe { __rx_end_exclusive.get() as usize }
+fn ro_size() -> usize { +fn rx_size() -> usize {
+ unsafe { __ro_size.get() as 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)] +#[inline(always)]
+fn virt_data_start() -> Address<Virtual> { +fn virt_rw_start() -> Address<Virtual> {
+ virt_ro_start() + ro_size() + Address::new(unsafe { __rw_start.get() as usize })
+} +}
+ +
+/// Size of the data range. +/// Size of the Read+Write (RW) range.
+/// +///
+/// # Safety +/// # Safety
+/// +///
+/// - Value is provided by the linker script and must be trusted as-is. +/// - Value is provided by the linker script and must be trusted as-is.
+#[inline(always)] +#[inline(always)]
+fn data_size() -> usize { +fn rw_size() -> usize {
+ unsafe { __data_size.get() as usize } + unsafe { (__rw_end_exclusive.get() as usize) - (__rw_start.get() as usize) }
+} +}
+ +
+/// Start address of the boot core's stack. +/// Start address of the boot core's stack.
+#[inline(always)] +#[inline(always)]
+fn virt_boot_core_stack_start() -> Address<Virtual> { +fn virt_boot_core_stack_start() -> Address<Virtual> {
+ 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. +/// Size of the boot core's stack.
+#[inline(always)] +#[inline(always)]
+fn boot_core_stack_size() -> usize { +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<Virtual> {
+ 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. +/// 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. /// Exclusive end address of the boot core's stack.
#[inline(always)] #[inline(always)]
-pub fn boot_core_stack_end() -> usize { -pub fn boot_core_stack_end() -> usize {
- map::BOOT_CORE_STACK_END - rx_start()
+pub fn phys_boot_core_stack_end() -> Address<Physical> { +pub fn phys_boot_core_stack_end() -> Address<Physical> {
+ // The binary is still identity mapped, so we don't need to convert here. + // 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(); + let end = virt_boot_core_stack_start().into_usize() + boot_core_stack_size();

@ -50,7 +50,7 @@
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// The exception vector table. // 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 by 2^11 bytes, as demanded by ARMv8-A. Same as ALIGN(2048) in an ld script.
.align 11 .align 11

@ -11,7 +11,11 @@
//! //!
//! crate::exception::arch_exception //! crate::exception::arch_exception
use crate::{bsp, exception}; use crate::{
bsp::{self},
exception,
memory::Address,
};
use core::{cell::UnsafeCell, fmt}; use core::{cell::UnsafeCell, fmt};
use cortex_a::{barrier, regs::*}; use cortex_a::{barrier, regs::*};
use register::InMemoryRegister; use register::InMemoryRegister;
@ -50,6 +54,20 @@ struct EsrEL1;
// Private Code // 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. /// Prints verbose information about the exception and then panics.
fn default_exception_handler(e: &ExceptionContext) { fn default_exception_handler(e: &ExceptionContext) {
panic!( panic!(
@ -68,18 +86,18 @@ fn default_exception_handler(e: &ExceptionContext) {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#[no_mangle] #[no_mangle]
unsafe extern "C" fn current_el0_synchronous(e: &mut ExceptionContext) { unsafe extern "C" fn current_el0_synchronous(_e: &mut ExceptionContext) {
default_exception_handler(e); panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.")
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn current_el0_irq(e: &mut ExceptionContext) { unsafe extern "C" fn current_el0_irq(_e: &mut ExceptionContext) {
default_exception_handler(e); panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.")
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn current_el0_serror(e: &mut ExceptionContext) { unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) {
default_exception_handler(e); 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. // 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))?;
Ok(()) inspect_data_abort(f)
} }
} }
@ -201,9 +219,7 @@ impl fmt::Display for SpsrEL1 {
write!(f, " Illegal Execution State (IL): {}", write!(f, " Illegal Execution State (IL): {}",
to_flag_str(self.0.is_set(SPSR_EL1::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() { for (i, reg) in self.gpr.iter().enumerate() {
write!(f, " x{: <2}: {: >#018x}{}", i, reg, alternating(i))?; write!(f, " x{: <2}: {: >#018x}{}", i, reg, alternating(i))?;
} }
write!(f, " lr : {:#018x}", self.lr)?; write!(f, " lr : {:#018x}", self.lr)
Ok(())
} }
} }

@ -3,50 +3,68 @@
* Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com> * Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
*/ */
/* 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 SECTIONS
{ {
/* Set current address to the value from which the RPi starts execution */ . = __rpi_load_addr;
. = 0x80000;
__ro_start = .; /***********************************************************************************************
* Code + RO Data + Global Offset Table
***********************************************************************************************/
__rx_start = .;
.text : .text :
{ {
*(.text._start) *(.text*) KEEP(*(.text._start))
} *(.text*)
} :segment_rx
.exception_vectors : .rodata : ALIGN(8) { *(.rodata*) } :segment_rx
{ .got : ALIGN(8) { *(.got) } :segment_rx
*(.exception_vectors*)
}
.rodata : . = ALIGN(64K); /* Align to page boundary */
{ __rx_end_exclusive = .;
*(.rodata*)
}
. = ALIGN(65536); /* Fill up to 64 KiB */
__ro_end = .;
.data : /***********************************************************************************************
{ * Data + BSS
*(.data*) ***********************************************************************************************/
} __rw_start = .;
.data : { *(.data*) } :segment_rw
/* Section is zeroed in u64 chunks, align start and end to 8 bytes */ /* Section is zeroed in u64 chunks, align start and end to 8 bytes */
.bss ALIGN(8): .bss : ALIGN(8)
{ {
__bss_start = .; __bss_start = .;
*(.bss*); *(.bss*);
. = ALIGN(8); . = ALIGN(8);
/* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */
. += 8;
__bss_end_inclusive = . - 8; __bss_end_inclusive = . - 8;
} } :NONE
. = ALIGN(65536);
__data_end = .; . = 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 = .;
} }

@ -8,31 +8,30 @@
//! copies the binary to 0x8_0000: //! 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 | //! | .text |
//! | .exception_vectors |
//! | .rodata | //! | .rodata |
//! | | //! | .got |
//! | RO_END_INCLUSIVE | 0x8_0000 + __ro_size - 1 //! | | rx_end_inclusive
//! +---------------------------------------------+ //! +---------------------------------------------+
//! | RO_END == DATA_START | 0x8_0000 + __ro_size //! | | rw_start == rx_end
//! | |
//! | .data | //! | .data |
//! | .bss | //! | .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; pub mod mmu;
@ -46,11 +45,19 @@ use core::{cell::UnsafeCell, ops::RangeInclusive};
// Symbols from the linker script. // Symbols from the linker script.
extern "Rust" { extern "Rust" {
static __rx_start: UnsafeCell<()>;
static __rx_end_exclusive: UnsafeCell<()>;
static __rw_start: UnsafeCell<()>;
static __bss_start: UnsafeCell<u64>; static __bss_start: UnsafeCell<u64>;
static __bss_end_inclusive: UnsafeCell<u64>; static __bss_end_inclusive: UnsafeCell<u64>;
static __ro_start: UnsafeCell<()>; static __rw_end_exclusive: UnsafeCell<()>;
static __ro_size: UnsafeCell<()>;
static __data_size: 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 { pub(super) mod map {
use super::*; use super::*;
pub const BOOT_CORE_STACK_SIZE: usize = 0x1_0000;
/// Physical devices. /// Physical devices.
#[cfg(feature = "bsp_rpi3")] #[cfg(feature = "bsp_rpi3")]
pub mod mmio { pub mod mmio {
@ -111,52 +116,69 @@ pub(super) mod map {
// Private Code // Private Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// Start address of the Read-Only (RO) range. /// Start address of the Read+Execute (RX) range.
/// ///
/// # Safety /// # Safety
/// ///
/// - Value is provided by the linker script and must be trusted as-is. /// - Value is provided by the linker script and must be trusted as-is.
#[inline(always)] #[inline(always)]
fn virt_ro_start() -> Address<Virtual> { fn virt_rx_start() -> Address<Virtual> {
Address::new(unsafe { __ro_start.get() as usize }) 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 /// # Safety
/// ///
/// - Value is provided by the linker script and must be trusted as-is. /// - Value is provided by the linker script and must be trusted as-is.
#[inline(always)] #[inline(always)]
fn ro_size() -> usize { fn rx_size() -> usize {
unsafe { __ro_size.get() as 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)] #[inline(always)]
fn virt_data_start() -> Address<Virtual> { fn virt_rw_start() -> Address<Virtual> {
virt_ro_start() + ro_size() Address::new(unsafe { __rw_start.get() as usize })
} }
/// Size of the data range. /// Size of the Read+Write (RW) range.
/// ///
/// # Safety /// # Safety
/// ///
/// - Value is provided by the linker script and must be trusted as-is. /// - Value is provided by the linker script and must be trusted as-is.
#[inline(always)] #[inline(always)]
fn data_size() -> usize { fn rw_size() -> usize {
unsafe { __data_size.get() as usize } unsafe { (__rw_end_exclusive.get() as usize) - (__rw_start.get() as usize) }
} }
/// Start address of the boot core's stack. /// Start address of the boot core's stack.
#[inline(always)] #[inline(always)]
fn virt_boot_core_stack_start() -> Address<Virtual> { fn virt_boot_core_stack_start() -> Address<Virtual> {
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. /// Size of the boot core's stack.
#[inline(always)] #[inline(always)]
fn boot_core_stack_size() -> usize { 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<Virtual> {
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. /// Exclusive end address of the physical address space.

@ -60,42 +60,42 @@ const fn size_to_num_pages(size: usize) -> usize {
size >> KernelGranule::SHIFT size >> KernelGranule::SHIFT
} }
/// The boot core's stack. /// The Read+Execute (RX) pages of the kernel binary.
fn virt_stack_page_desc() -> PageSliceDescriptor<Virtual> { fn virt_rx_page_desc() -> PageSliceDescriptor<Virtual> {
let num_pages = size_to_num_pages(super::boot_core_stack_size()); 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. /// The Read+Write (RW) pages of the kernel binary.
fn virt_ro_page_desc() -> PageSliceDescriptor<Virtual> { fn virt_rw_page_desc() -> PageSliceDescriptor<Virtual> {
let num_pages = size_to_num_pages(super::ro_size()); 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. /// The boot core's stack.
fn virt_data_page_desc() -> PageSliceDescriptor<Virtual> { fn virt_boot_core_stack_page_desc() -> PageSliceDescriptor<Virtual> {
let num_pages = size_to_num_pages(super::data_size()); 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 binary is still identity mapped, so we don't need to convert in the following.
/// The boot core's stack. /// The Read+Execute (RX) pages of the kernel binary.
fn phys_stack_page_desc() -> PageSliceDescriptor<Physical> { fn phys_rx_page_desc() -> PageSliceDescriptor<Physical> {
virt_stack_page_desc().into() virt_rx_page_desc().into()
} }
/// The Read-Only (RO) pages of the kernel binary. /// The Read+Write (RW) pages of the kernel binary.
fn phys_ro_page_desc() -> PageSliceDescriptor<Physical> { fn phys_rw_page_desc() -> PageSliceDescriptor<Physical> {
virt_ro_page_desc().into() virt_rw_page_desc().into()
} }
/// The data pages of the kernel binary. /// The boot core's stack.
fn phys_data_page_desc() -> PageSliceDescriptor<Physical> { fn phys_boot_core_stack_page_desc() -> PageSliceDescriptor<Physical> {
virt_data_page_desc().into() virt_boot_core_stack_page_desc().into()
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -107,6 +107,13 @@ pub fn kernel_translation_tables() -> &'static InitStateLock<KernelTranslationTa
&KERNEL_TABLES &KERNEL_TABLES
} }
/// The boot core's stack guard page.
pub fn virt_boot_core_stack_guard_page_desc() -> PageSliceDescriptor<Virtual> {
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. /// Pointer to the last page of the physical address space.
pub fn phys_addr_space_end_page() -> *const Page<Physical> { pub fn phys_addr_space_end_page() -> *const Page<Physical> {
common::align_down( common::align_down(
@ -122,31 +129,31 @@ pub fn phys_addr_space_end_page() -> *const Page<Physical> {
/// - Any miscalculation or attribute error will likely be fatal. Needs careful manual checking. /// - Any miscalculation or attribute error will likely be fatal. Needs careful manual checking.
pub unsafe fn kernel_map_binary() -> Result<(), &'static str> { pub unsafe fn kernel_map_binary() -> Result<(), &'static str> {
generic_mmu::kernel_map_pages_at( generic_mmu::kernel_map_pages_at(
"Kernel boot-core stack", "Kernel code and RO data",
&virt_stack_page_desc(), &virt_rx_page_desc(),
&phys_stack_page_desc(), &phys_rx_page_desc(),
&AttributeFields { &AttributeFields {
mem_attributes: MemAttributes::CacheableDRAM, mem_attributes: MemAttributes::CacheableDRAM,
acc_perms: AccessPermissions::ReadWrite, acc_perms: AccessPermissions::ReadOnly,
execute_never: true, execute_never: false,
}, },
)?; )?;
generic_mmu::kernel_map_pages_at( generic_mmu::kernel_map_pages_at(
"Kernel code and RO data", "Kernel data and bss",
&virt_ro_page_desc(), &virt_rw_page_desc(),
&phys_ro_page_desc(), &phys_rw_page_desc(),
&AttributeFields { &AttributeFields {
mem_attributes: MemAttributes::CacheableDRAM, mem_attributes: MemAttributes::CacheableDRAM,
acc_perms: AccessPermissions::ReadOnly, acc_perms: AccessPermissions::ReadWrite,
execute_never: false, execute_never: true,
}, },
)?; )?;
generic_mmu::kernel_map_pages_at( generic_mmu::kernel_map_pages_at(
"Kernel data and bss", "Kernel boot-core stack",
&virt_data_page_desc(), &virt_boot_core_stack_page_desc(),
&phys_data_page_desc(), &phys_boot_core_stack_page_desc(),
&AttributeFields { &AttributeFields {
mem_attributes: MemAttributes::CacheableDRAM, mem_attributes: MemAttributes::CacheableDRAM,
acc_perms: AccessPermissions::ReadWrite, acc_perms: AccessPermissions::ReadWrite,
@ -169,7 +176,13 @@ mod tests {
/// Check alignment of the kernel's virtual memory layout sections. /// Check alignment of the kernel's virtual memory layout sections.
#[kernel_test] #[kernel_test]
fn virt_mem_layout_sections_are_64KiB_aligned() { 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 start: usize = i().start_addr().into_usize();
let end: usize = i().end_addr().into_usize(); let end: usize = i().end_addr().into_usize();
@ -183,9 +196,9 @@ mod tests {
#[kernel_test] #[kernel_test]
fn virt_mem_layout_has_no_overlaps() { fn virt_mem_layout_has_no_overlaps() {
let layout = [ let layout = [
virt_stack_page_desc(), virt_rx_page_desc(),
virt_ro_page_desc(), virt_rw_page_desc(),
virt_data_page_desc(), virt_boot_core_stack_page_desc(),
]; ];
for (i, first_range) in layout.iter().enumerate() { for (i, first_range) in layout.iter().enumerate() {

@ -122,6 +122,7 @@ objdump: $(KERNEL_ELF)
@$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \
--section .text \ --section .text \
--section .rodata \ --section .rodata \
--section .got \
$(KERNEL_ELF) | rustfilt $(KERNEL_ELF) | rustfilt
nm: $(KERNEL_ELF) nm: $(KERNEL_ELF)

Binary file not shown.

Binary file not shown.

@ -3,37 +3,47 @@
* Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com> * Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
*/ */
/* 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 SECTIONS
{ {
/* Set current address to the value from which the RPi starts execution */ . = __rpi_load_addr;
. = 0x80000;
/***********************************************************************************************
* Code + RO Data + Global Offset Table
***********************************************************************************************/
__rx_start = .;
.text : .text :
{ {
*(.text._start) *(.text*) KEEP(*(.text._start))
} *(.text*)
} :segment_rx
.rodata : .rodata : ALIGN(8) { *(.rodata*) } :segment_rx
{ .got : ALIGN(8) { *(.got) } :segment_rx
*(.rodata*)
}
.data : /***********************************************************************************************
{ * Data + BSS
*(.data*) ***********************************************************************************************/
} .data : { *(.data*) } :segment_rw
/* Section is zeroed in u64 chunks, align start and end to 8 bytes */ /* Section is zeroed in u64 chunks, align start and end to 8 bytes */
.bss ALIGN(8): .bss : ALIGN(8)
{ {
__bss_start = .; __bss_start = .;
*(.bss*); *(.bss*);
. = ALIGN(8); . = ALIGN(8);
/* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */
. += 8;
__bss_end_inclusive = . - 8; __bss_end_inclusive = . - 8;
} } :NONE
/DISCARD/ : { *(.comment*) }
} }

@ -12,6 +12,8 @@ use core::{cell::UnsafeCell, ops::RangeInclusive};
// Symbols from the linker script. // Symbols from the linker script.
extern "Rust" { extern "Rust" {
static __rx_start: UnsafeCell<()>;
static __bss_start: UnsafeCell<u64>; static __bss_start: UnsafeCell<u64>;
static __bss_end_inclusive: UnsafeCell<u64>; static __bss_end_inclusive: UnsafeCell<u64>;
} }
@ -20,10 +22,9 @@ extern "Rust" {
// Public Definitions // Public Definitions
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// The board's memory map. /// The board's physical memory map.
#[rustfmt::skip] #[rustfmt::skip]
pub(super) mod map { pub(super) mod map {
pub const BOOT_CORE_STACK_END: usize = 0x8_0000;
pub const GPIO_OFFSET: usize = 0x0020_0000; pub const GPIO_OFFSET: usize = 0x0020_0000;
pub const UART_OFFSET: usize = 0x0020_1000; 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 // Public Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -56,7 +71,7 @@ pub(super) mod map {
/// Exclusive end address of the boot core's stack. /// Exclusive end address of the boot core's stack.
#[inline(always)] #[inline(always)]
pub fn boot_core_stack_end() -> usize { pub fn boot_core_stack_end() -> usize {
map::BOOT_CORE_STACK_END rx_start()
} }
/// Return the inclusive range spanning the .bss section. /// Return the inclusive range spanning the .bss section.

Loading…
Cancel
Save